diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f67eba45..dcd0f1163 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -969,6 +969,7 @@ Theme UI is now written in TypeScript, and the emitted types differ from ### `@theme-ui/core` +- Add ability to use arrays to merge variants. Issues #1209 #1208, PR #1226 - Make ThemeProvider `theme` prop required ### `@theme-ui/editor` diff --git a/packages/components/index.d.ts b/packages/components/index.d.ts index 88ec80c4c..bd18c7036 100644 --- a/packages/components/index.d.ts +++ b/packages/components/index.d.ts @@ -2,7 +2,7 @@ import * as React from 'react' import { StyledComponent } from '@emotion/styled' import { Interpolation } from '@emotion/react' import { SpaceProps, ColorProps, MarginProps } from 'styled-system' -import { ResponsiveStyleValue, ThemeUIStyleObject } from '@theme-ui/css' +import { ResponsiveStyleValue, ThemeUIStyleObject, VariantProperty } from '@theme-ui/css' type Omit = Pick> @@ -20,7 +20,7 @@ type ForwardRef = React.ForwardRefExoticComponent< export interface BoxOwnProps extends SpaceProps, ColorProps { as?: React.ElementType - variant?: string + variant?: VariantProperty.Variant css?: Interpolation sx?: ThemeUIStyleObject } diff --git a/packages/components/src/Box.js b/packages/components/src/Box.js index 650c45e2e..60c755a84 100644 --- a/packages/components/src/Box.js +++ b/packages/components/src/Box.js @@ -1,5 +1,6 @@ import styled from '@emotion/styled' -import { css, get } from '@theme-ui/css' +import { css, getVariantValue } from '@theme-ui/css' +import deepmerge from 'deepmerge' import { createShouldForwardProp } from '@styled-system/should-forward-prop' import space from '@styled-system/space' import color from '@styled-system/color' @@ -17,7 +18,7 @@ const shouldForwardProp = createShouldForwardProp(boxSystemProps) const sx = (props) => css(props.sx)(props.theme) const base = (props) => css(props.__css)(props.theme) const variant = ({ theme, variant, __themeKey = 'variants' }) => - css(get(theme, __themeKey + '.' + variant, get(theme, variant))) + css(getVariantValue(theme, variant, __themeKey)) export const Box = styled('div', { shouldForwardProp, diff --git a/packages/components/test/__snapshots__/index.js.snap b/packages/components/test/__snapshots__/index.js.snap index 5dc4c641e..e85957ba9 100644 --- a/packages/components/test/__snapshots__/index.js.snap +++ b/packages/components/test/__snapshots__/index.js.snap @@ -180,6 +180,43 @@ exports[`Box renders 1`] = ` `; +exports[`Box renders with variant array derived variant from theme merge 1`] = ` +.emotion-0 { + box-sizing: border-box; + margin: 0; + min-width: 0; + -webkit-appearance: none; + -moz-appearance: none; + -ms-appearance: none; + appearance: none; + display: inline-block; + text-align: center; + line-height: inherit; + -webkit-text-decoration: none; + text-decoration: none; + font-size: inherit; + padding-left: 16px; + padding-right: 16px; + padding-top: 8px; + padding-bottom: 8px; + color: white; + background-color: var(--theme-ui-colors-primary, #0cf); + border: 0; + border-radius: 4px; + color: var(--theme-ui-colors-background, #fefefe); + border: 2px solid undefined; + background-color: transparent; + border-bottom-left-radius: 5px 85px; + border-bottom-right-radius: 75px 5px; + border-top-left-radius: 85px 5px; + border-top-right-radius: 5px 75px; +} + + ``` -## Example Theme +## Combining multiple variants + +If you want to combine multiple variants on the same element, pass an array of variants with the `variant` prop. +Variant styles are merged from left to right, so if some of the styles conflict, those of the variant passed later will render. + +```jsx live=true +Title text +``` + +## Variant as a function + +If you need to determine variants at run-time, pass a function to the `variant` prop. + +```jsx live=true + { + const buttonVariant = Object.keys(theme.buttons)[0] + return `buttons.${buttonVariant}` + }}> + some text + +``` + +## Example theme ```js // example theme diff --git a/packages/docs/src/pages/guides/variants.mdx b/packages/docs/src/pages/guides/variants.mdx index 5b05ea0ca..27a43e278 100644 --- a/packages/docs/src/pages/guides/variants.mdx +++ b/packages/docs/src/pages/guides/variants.mdx @@ -99,6 +99,30 @@ With the example below, the primary button will adapt its colors based on the cu } ``` +## Combining Multiple Variants + +If you want to combine multiple variants on the same element, pass an array to `variant` in the `sx` prop. +If styles conflict, those of the variant passed later will render. + +```jsx +