Skip to content

Commit 6a9e2d1

Browse files
committed
feat: more usable Typo
1 parent 00d7368 commit 6a9e2d1

File tree

2 files changed

+34
-15
lines changed

2 files changed

+34
-15
lines changed

example/src/stories/Typo.stories.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ export default {
1313
variant: {
1414
control: {
1515
type: 'select',
16-
optopns: [
16+
options: [
1717
'default',
1818
'description',
1919
'error',

src/components/Typo.tsx

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { css } from '@emotion/react'
22
import styled from '@emotion/styled'
33
import React, { ElementType } from 'react'
4-
import { SolvedTheme } from '../styles'
4+
import { SolvedTheme, solvedThemes } from '../styles'
55
import { PC, PP, PR } from '../types/PolymorphicElementProps'
66

77
const variants = (theme: SolvedTheme) =>
@@ -104,7 +104,13 @@ const variants = (theme: SolvedTheme) =>
104104
`,
105105
} as const)
106106

107-
export type TypoVariant = keyof ReturnType<typeof variants>
107+
const variantKeys = Object.keys(variants(solvedThemes.light))
108+
109+
type VariantsObject = ReturnType<typeof variants>
110+
type OptionalVariables = {
111+
[key in keyof VariantsObject]: boolean
112+
}
113+
export type TypoVariant = keyof VariantsObject
108114

109115
const asMap = {
110116
h1: 'h1',
@@ -118,23 +124,18 @@ const asMap = {
118124
} as const
119125

120126
interface TypoContainerProps {
121-
variant: TypoVariant | TypoVariant[]
127+
variant: TypoVariant[]
122128
}
123129

124130
const TypoContainer = styled.span<TypoContainerProps>`
125-
${({ theme, variant }) =>
126-
typeof variant === 'string'
127-
? variants(theme)[variant]
128-
: variant.map((v) => variants(theme)[v])}
131+
${({ theme, variant }) => variant.map((v) => variants(theme)[v])}
129132
`
130133

131-
export interface TypoProps {
134+
export type TypoProps = {
132135
variant?: TypoVariant | TypoVariant[]
133-
}
136+
} & OptionalVariables
134137

135-
const firstVariant = (
136-
variant?: TypoVariant | TypoVariant[]
137-
): TypoVariant | undefined => {
138+
const firstVariant = (variant?: TypoVariant[]): TypoVariant | undefined => {
138139
if (typeof variant === 'string') return variant
139140
if (Array.isArray(variant) && variant.length > 0) return variant[0]
140141
return undefined
@@ -144,12 +145,30 @@ export const Typo: PC<'span', TypoProps> = React.forwardRef(
144145
<T extends ElementType>(props: PP<T, TypoProps>, ref?: PR<T>) => {
145146
const { variant = [], as, ...rest } = props
146147

148+
const calculatedVariants = [
149+
...(typeof variant === 'string' ? [variant] : variant),
150+
...Object.entries(rest)
151+
.filter(
152+
([k, v]) => variantKeys.includes(k) && typeof v === 'boolean' && v
153+
)
154+
.map(([k]) => k),
155+
] as TypoVariant[]
156+
147157
// TODO types are wrong when `as` is inferred by variant
148158
const calculatedAs =
149-
as || asMap[firstVariant(variant) ?? 'default'] || 'span'
159+
as || asMap[firstVariant(calculatedVariants) ?? 'default'] || 'span'
160+
161+
const filteredRest = Object.fromEntries(
162+
Object.entries(rest).filter(([k]) => !variantKeys.includes(k))
163+
)
150164

151165
return (
152-
<TypoContainer ref={ref} as={calculatedAs} variant={variant} {...rest} />
166+
<TypoContainer
167+
ref={ref}
168+
as={calculatedAs}
169+
variant={calculatedVariants}
170+
{...filteredRest}
171+
/>
153172
)
154173
}
155174
)

0 commit comments

Comments
 (0)