Skip to content

Commit

Permalink
chore(components): fix themed()
Browse files Browse the repository at this point in the history
  • Loading branch information
hasparus committed Mar 18, 2022
1 parent b994c5e commit 9775deb
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 34 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"typecheck:tests": "tsc --noEmit -P ./tsconfig.test.json",
"logo": "yarn workspace docs logo",
"postinstall": "preconstruct dev",
"dev": "preconstruct dev",
"version:bump": "lerna version",
"version:bump-next": "lerna version prerelease --preid alpha --exact",
"release": "yarn clean && yarn build && yarn shipit",
Expand Down
53 changes: 33 additions & 20 deletions packages/mdx/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import {
ReactNode,
DetailedHTMLProps,
HTMLAttributes,
ElementType,
ComponentProps,
useMemo,
} from 'react'
Expand Down Expand Up @@ -86,21 +85,8 @@ const alias = (n: ThemedComponentName): keyof JSX.IntrinsicElements =>
isAlias(n) ? aliases[n] : n

export const themed =
(key: ThemedComponentName | (string & {})) =>
({ theme, ...rest }: ThemedProps) => {
const extraStyles: CSSObject = {}

if (key === 'th' || key === 'td') {
const { align } = rest as DetailedHTMLProps<
React.ThHTMLAttributes<HTMLTableHeaderCellElement>,
HTMLTableHeaderCellElement
>

if (align !== 'char') extraStyles.textAlign = align
}

return css({ ...get(theme, `styles.${key}`), ...extraStyles })(theme)
}
(key: ThemedComponentName | (string & {})) => (theme: Theme) =>
css(get(theme, `styles.${key}`))(theme)

// opt out of typechecking whenever `as` prop is used
interface AnyComponentProps extends JSX.IntrinsicAttributes {
Expand All @@ -109,8 +95,11 @@ interface AnyComponentProps extends JSX.IntrinsicAttributes {

export interface ThemedComponent<Name extends string> {
(
props: Name extends keyof JSX.IntrinsicElements ? ComponentProps<Name> : {}
props: (Name extends keyof JSX.IntrinsicElements
? ComponentProps<Name>
: {}) & { css?: CSSObject }
): JSX.Element
displayName: string
}

export type ThemedComponentsDict = {
Expand All @@ -127,14 +116,30 @@ const createThemedComponent = <Name extends string>(
): ThemedComponent<Name> => {
const variantStyles = themed(variant)

return (props) => {
const component: ThemedComponent<Name> = (props) => {
const extraStyles: { textAlign?: 'left' | 'right' | 'center' | 'justify' } =
{}

if (name === 'th' || name === 'td') {
const { align } = props as DetailedHTMLProps<
React.ThHTMLAttributes<HTMLTableHeaderCellElement>,
HTMLTableHeaderCellElement
>

if (align !== 'char') extraStyles.textAlign = align
}

const css = (props as any)['css']

return jsx(name, {
...props,
css: css ? [css, variantStyles] : variantStyles,
css: [props.css, variantStyles, extraStyles].filter(Boolean),
})
}

component.displayName = `Themed(${name})`

return component
}

interface ThemedDivProps
Expand Down Expand Up @@ -167,10 +172,18 @@ const createComponents = (comps: MDXProviderComponents) => {
// todo: test this behaviour
componentKeys.forEach((key) => {
const componentAtKey = comps[key]

if (componentAtKey) {
next[key] = (props) => jsx(componentAtKey, { ...props, css: themed(key) })
const component: ThemedComponent<string> = (props) => {
return jsx(componentAtKey, { ...props, css: themed(key) })
}

component.displayName = "MdxComponents('" + key + "')"

next[key] = component
}
})

return next
}

Expand Down
17 changes: 3 additions & 14 deletions packages/mdx/test/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@ expect.extend(matchers)

test('styles React components', () => {
const Beep = (props: React.ComponentPropsWithoutRef<'h2'>) => (
// eslint-disable-next-line jsx-a11y/heading-has-content
<h2 {...props} />
)

const Inner = (props: React.ComponentPropsWithoutRef<typeof Beep>) =>
mdx('Beep', props)

Expand All @@ -45,22 +47,9 @@ test('styles React components', () => {
expect(json).toHaveStyleRule('color', 'tomato')
})

test('cleans up style props', () => {
const json = renderJSON(
// @ts-expect-error
<Themed.h1 mx={2} id="test">
Hello
</Themed.h1>
)!
expect(json.props.id).toBe('test')
expect(json.props.mx).not.toBeDefined()
})

test('themed extracts styles from the theme', () => {
expect(
themed('footer')({
theme: { styles: { footer: { background: 'skyblue' } } },
})
themed('footer')({ styles: { footer: { background: 'skyblue' } } })
).toStrictEqual({ background: 'skyblue' })
})

Expand Down

0 comments on commit 9775deb

Please sign in to comment.