-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #570 from LifeSG/typography-component
Set up V3 Typography component
- Loading branch information
Showing
12 changed files
with
518 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import { css } from "styled-components"; | ||
import { Colour, Typography } from "../theme"; | ||
import { TypographySizeType } from "../theme/typography/types"; | ||
import { TypographyProps, TypographyWeight } from "./types"; | ||
|
||
export const getTextStyle = ( | ||
type: TypographySizeType, | ||
weight: TypographyWeight, | ||
paragraph = false | ||
) => { | ||
const token = `${type}-${weight.toLowerCase()}`; | ||
|
||
return css` | ||
${Typography[token]} | ||
${paragraph ? "margin-bottom: 1.05em;" : "margin-bottom: 0;"} | ||
`; | ||
}; | ||
|
||
export const getDisplayStyle = (inline = false, paragraph = false) => { | ||
if (paragraph) { | ||
return css` | ||
display: block; | ||
`; | ||
} else if (inline) { | ||
return css` | ||
display: inline; | ||
`; | ||
} else { | ||
return css` | ||
display: block; | ||
`; | ||
} | ||
}; | ||
|
||
export const createTypographyStyles = ( | ||
textStyle: TypographySizeType, | ||
props: TypographyProps | ||
) => css` | ||
${getTextStyle(textStyle, props.weight || "regular", props.paragraph)} | ||
${getDisplayStyle(props.inline, props.paragraph)} | ||
color: ${Colour.text}; | ||
`; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export * from "./typography"; | ||
export * from "./types"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
export type TypographyWeight = "regular" | "semibold" | "bold" | "light"; | ||
|
||
export interface TypographyProps extends React.HTMLAttributes<HTMLElement> { | ||
/** The font weight */ | ||
weight?: TypographyWeight | undefined; | ||
/** Specifies if text is displayed inline */ | ||
inline?: boolean | undefined; | ||
/** Specifies if text has a bottom margin */ | ||
paragraph?: boolean | undefined; | ||
} | ||
|
||
export interface TypographyLinkProps | ||
extends React.AnchorHTMLAttributes<HTMLAnchorElement> { | ||
/** The font weight */ | ||
weight?: TypographyWeight | undefined; | ||
/** Displays indicator to signal that link leads to an external site */ | ||
external?: boolean | undefined; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
import { ExternalIcon } from "@lifesg/react-icons/external"; | ||
import styled, { css } from "styled-components"; | ||
import { Colour } from "../theme"; | ||
import { TypographySizeType } from "../theme/typography/types"; | ||
import { createTypographyStyles, getTextStyle } from "./helper"; | ||
import { TypographyLinkProps, TypographyProps } from "./types"; | ||
|
||
export namespace Typography { | ||
const createHeader = ( | ||
tag: keyof JSX.IntrinsicElements, | ||
textStyle: TypographySizeType, | ||
displayName: string | ||
) => { | ||
const Header = styled(tag).attrs<TypographyProps>(({ inline }) => ({ | ||
as: inline ? "span" : undefined, | ||
}))<TypographyProps>` | ||
${(props) => createTypographyStyles(textStyle, props)} | ||
`; | ||
Header.displayName = `Typography.${displayName}`; | ||
return Header; | ||
}; | ||
|
||
export const HeaderXXL = createHeader("h1", "header-xxl", "HeaderXXL"); | ||
export const HeaderXL = createHeader("h2", "header-xl", "HeaderXL"); | ||
export const HeaderLG = createHeader("h3", "header-lg", "HeaderLG"); | ||
export const HeaderMD = createHeader("h4", "header-md", "HeaderMD"); | ||
export const HeaderSM = createHeader("h5", "header-sm", "HeaderSM"); | ||
export const HeaderXS = createHeader("h6", "header-xs", "HeaderXS"); | ||
|
||
const createBody = (textStyle: TypographySizeType, displayName: string) => { | ||
const Body = styled.p.attrs<TypographyProps>(({ inline }) => ({ | ||
as: inline ? "span" : undefined, | ||
}))<TypographyProps>` | ||
${(props) => createTypographyStyles(textStyle, props)} | ||
`; | ||
Body.displayName = `Typography.${displayName}`; | ||
return Body; | ||
}; | ||
|
||
export const BodyBL = createBody("body-baseline", "BodyBL"); | ||
export const BodyLG = createBody("body-lg", "BodyLG"); | ||
export const BodyMD = createBody("body-md", "BodyMD"); | ||
export const BodySM = createBody("body-sm", "BodySM"); | ||
|
||
const createLinkComponent = ( | ||
textStyle: TypographySizeType, | ||
displayName: string | ||
) => { | ||
const HyperlinkBase = styled.a<TypographyLinkProps>` | ||
${(props) => css` | ||
${getTextStyle(textStyle, props.weight || "regular")} | ||
color: ${Colour.hyperlink}; | ||
text-decoration: none; | ||
:hover, | ||
:active, | ||
:focus { | ||
color: ${Colour["text-hover"]}; | ||
} | ||
`} | ||
`; | ||
|
||
const Component = ({ | ||
external = false, | ||
children, | ||
...rest | ||
}: TypographyLinkProps) => ( | ||
<HyperlinkBase {...rest}> | ||
{children} | ||
{external && <StyledExternalIcon />} | ||
</HyperlinkBase> | ||
); | ||
Component.displayName = `Typography.${displayName}`; | ||
return Component; | ||
}; | ||
|
||
export const LinkBL = createLinkComponent("body-baseline", "LinkBL"); | ||
export const LinkMD = createLinkComponent("body-md", "LinkMD"); | ||
export const LinkLG = createLinkComponent("body-lg", "LinkLG"); | ||
export const LinkSM = createLinkComponent("body-sm", "LinkSM"); | ||
} | ||
|
||
const StyledExternalIcon = styled(ExternalIcon)` | ||
height: 1lh; | ||
width: 1em; | ||
margin-left: 0.4em; | ||
vertical-align: middle; | ||
`; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
export * from "./api-table-components"; | ||
export * from "./api-table"; | ||
export * from "./api-table-components"; | ||
export * from "./markup-helpers"; | ||
export * from "./types"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
import { | ||
ApiTable, | ||
ApiTableSectionProps, | ||
TabAttribute, | ||
Tabs, | ||
} from "../storybook-common"; | ||
|
||
const TEXT_DATA: ApiTableSectionProps[] = [ | ||
{ | ||
attributes: [ | ||
{ | ||
name: "", | ||
description: ( | ||
<> | ||
This component also inherits props from{" "} | ||
<a | ||
href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement" | ||
target="_blank" | ||
rel="noreferrer" | ||
> | ||
HTMLElement | ||
</a> | ||
</> | ||
), | ||
}, | ||
{ | ||
name: "inline", | ||
description: | ||
"Sets the text to an inline display to allow a combination of text in a single line", | ||
propTypes: ["boolean"], | ||
}, | ||
{ | ||
name: "maxLines", | ||
description: | ||
"Specifies the number of lines visible. Additional lines will be truncated", | ||
propTypes: ["number"], | ||
}, | ||
{ | ||
name: "paragraph", | ||
description: | ||
"Adds an extra bottom margin to allow a better separation of text blocks", | ||
propTypes: ["boolean"], | ||
defaultValue: "false", | ||
}, | ||
{ | ||
name: "weight", | ||
description: "The weight of the text component", | ||
propTypes: [`"regular"`, `"semibold"`, `"bold"`, `"light"`], | ||
defaultValue: `"regular"`, | ||
}, | ||
], | ||
}, | ||
]; | ||
|
||
const LINK_DATA: ApiTableSectionProps[] = [ | ||
{ | ||
attributes: [ | ||
{ | ||
name: "", | ||
description: ( | ||
<> | ||
This component also inherits props from{" "} | ||
<a | ||
href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLAnchorElement" | ||
target="_blank" | ||
rel="noreferrer" | ||
> | ||
HTMLAnchorElement | ||
</a> | ||
</> | ||
), | ||
}, | ||
{ | ||
name: "weight", | ||
description: "The weight of the hyperlink component", | ||
propTypes: [`"regular"`, `"semibold"`, `"bold"`, `"light"`], | ||
defaultValue: `"regular"`, | ||
}, | ||
{ | ||
name: "external", | ||
description: | ||
"Indicates if the link is external to the domain. Adds an indicator at the end of the link", | ||
propTypes: ["boolean"], | ||
}, | ||
], | ||
}, | ||
]; | ||
|
||
const PROPS_TABLE_DATA: TabAttribute[] = [ | ||
{ | ||
title: "Header/Body", | ||
component: <ApiTable sections={TEXT_DATA} />, | ||
}, | ||
{ | ||
title: "Link", | ||
component: <ApiTable sections={LINK_DATA} />, | ||
}, | ||
]; | ||
|
||
export const PropsTable = () => <Tabs tabs={PROPS_TABLE_DATA} />; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
import { Canvas, Meta } from "@storybook/blocks"; | ||
import { DocInfo } from "stories/storybook-common"; | ||
import { PropsTable } from "./props-table"; | ||
import * as TypographyStories from "./typography.stories"; | ||
|
||
<Meta of={TypographyStories} /> | ||
|
||
# Typography | ||
|
||
## Overview | ||
|
||
The component that is used for headings, body text, links and more. | ||
|
||
```tsx | ||
import { Typography } from "@lifesg/react-design-system/typography"; | ||
``` | ||
|
||
<Canvas of={TypographyStories.TypographySet} /> | ||
|
||
<DocInfo> | ||
**Which module to use?**<br /><br /> | ||
|
||
**Scenario 1: Text content** | ||
|
||
If you are rendering text content, such as headings, paragraphs and links, use | ||
this Typography component as it comes with additional capabilities to help you | ||
lay out text.<br /><br /> | ||
|
||
**Scenario 2: Parent container** | ||
|
||
If you are rendering a container that contains text children but does not need | ||
to be a text element itself, apply the [typography design | ||
tokens](/docs/foundations-typography-introduction--docs) directly.<br /><br /> | ||
|
||
**Scenario 3: HTML children** | ||
|
||
If you are rendering a container that can contain arbitrary HTML markup, use the | ||
[Markup component](/docs/general-markup--docs). | ||
|
||
</DocInfo> | ||
|
||
## Combining styles | ||
|
||
### Inline text | ||
|
||
You can nest text within text using the `inline` prop. The nested text is | ||
rendered as a `span` element. | ||
|
||
<Canvas of={TypographyStories.InlineText} /> | ||
|
||
### Inline link | ||
|
||
You can include links within a set of text. Links are inline by default. | ||
|
||
<Canvas of={TypographyStories.InlineLink} /> | ||
|
||
### Font weight | ||
|
||
You can include different weights within a set of text using the `weight` and | ||
`inline` props. | ||
|
||
<Canvas of={TypographyStories.MixedFontWeights} /> | ||
|
||
## Paragraph specification | ||
|
||
You can include paragraph spacing between text blocks by specifying the | ||
`paragraph` prop. | ||
|
||
<Canvas of={TypographyStories.Paragraphs} /> | ||
|
||
## External links | ||
|
||
If a link leads to an external site, it is recommended to specify the `external` | ||
prop, which displays an indicator. | ||
|
||
<Canvas of={TypographyStories.ExternalLink} /> | ||
|
||
## Component API | ||
|
||
<PropsTable /> |
Oops, something went wrong.