Skip to content
Open
Show file tree
Hide file tree
Changes from 3 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
4 changes: 2 additions & 2 deletions examples/prism/src/layout.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/** @jsx jsx */
import { jsx, Layout, Header, Main, Container } from 'theme-ui'

const Layout = (props) => (
const PageLayout = (props) => (
<Layout>
<Header>
<h2>Theme UI Gatsby Example</h2>
Expand All @@ -12,4 +12,4 @@ const Layout = (props) => (
</Layout>
)

export default Layout
export default PageLayout
72 changes: 2 additions & 70 deletions packages/components/src/Box.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,56 +7,11 @@ import {
useTheme,
} from '@emotion/react'
import React, { forwardRef } from 'react'
import {
css,
get,
ThemeUICSSProperties,
ThemeUIStyleObject,
} from '@theme-ui/css'
import { css, get, ThemeUIStyleObject } from '@theme-ui/css'
import type { Assign } from './types'
import type { __ThemeUIComponentsInternalProps } from './util'

const boxSystemProps = [
// space scale props (inherited from @styled-system/space)
'margin',
'marginTop',
'marginRight',
'marginBottom',
'marginLeft',
'marginX',
'marginY',
'm',
'mt',
'mr',
'mb',
'ml',
'mx',
'my',
'padding',
'paddingTop',
'paddingRight',
'paddingBottom',
'paddingLeft',
'paddingX',
'paddingY',
'p',
'pt',
'pr',
'pb',
'pl',
'px',
'py',
// color props (inherited from @styled-system/color)
'color',
'backgroundColor',
'bg',
'opacity',
] as const

type BoxSystemPropsKeys = typeof boxSystemProps[number]
type BoxSystemProps = Pick<ThemeUICSSProperties, BoxSystemPropsKeys>

export interface BoxOwnProps extends BoxSystemProps {
export interface BoxOwnProps {
as?: React.ElementType
variant?: string
css?: Interpolation<any>
Expand All @@ -69,22 +24,6 @@ export interface BoxProps
'ref'
> {}

/**
* @internal
*/
export const __isBoxStyledSystemProp = (prop: string) =>
(boxSystemProps as readonly string[]).includes(prop)

const pickSystemProps = (props: BoxOwnProps) => {
const res: Partial<Pick<BoxOwnProps, typeof boxSystemProps[number]>> = {}
for (const key of boxSystemProps) {
// ts2590: union is too large
;(res as any)[key] = props[key]
}

return res
}

/**
* Use the Box component as a layout primitive to add margin, padding, and colors to content.
* @see https://theme-ui.com/components/box
Expand Down Expand Up @@ -116,20 +55,13 @@ export const Box = forwardRef<any, BoxProps>(function Box(props, ref) {

const sxPropStyles = css(sx)(theme)

const systemPropsStyles = css(pickSystemProps(rest))(theme)

const style: ArrayInterpolation<unknown> = [
baseStyles,
__cssStyles,
variantStyles,
sxPropStyles,
systemPropsStyles,
cssProp,
]

boxSystemProps.forEach((name) => {
delete (rest as Record<string, unknown>)[name]
})

return <Component ref={ref} css={style} {...rest} />
})
11 changes: 7 additions & 4 deletions packages/components/src/Checkbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import React from 'react'

import { Box, BoxOwnProps } from './Box'
import { SVG, SVGProps } from './SVG'
import { Assign, ForwardRef } from './types'
import type { Assign, ForwardRef } from './types'
import type { ThemeUICSSObject } from '@theme-ui/css'
import { __internalProps } from './util'

const CheckboxChecked = (props: SVGProps) => (
Expand Down Expand Up @@ -45,7 +46,9 @@ const CheckboxIcon = (props: SVGProps) => (
)

export interface CheckboxProps
extends Assign<React.ComponentPropsWithRef<'input'>, BoxOwnProps> {}
extends Assign<React.ComponentPropsWithRef<'input'>, BoxOwnProps> {
containerSx?: ThemeUICSSObject
}

/**
* Form checkbox input component
Expand All @@ -56,11 +59,11 @@ export interface CheckboxProps
*/
export const Checkbox: ForwardRef<HTMLInputElement, CheckboxProps> =
React.forwardRef(function Checkbox(
{ className, sx, variant = 'checkbox', children, ...props },
{ className, sx, containerSx, variant = 'checkbox', children, ...props },
ref
) {
return (
<Box sx={{ minWidth: 'min-content' }}>
<Box sx={{ minWidth: 'min-content', ...containerSx }}>
<Box
ref={ref}
as="input"
Expand Down
10 changes: 3 additions & 7 deletions packages/components/src/Embed.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
import React, { ComponentPropsWithoutRef } from 'react'

import { Box, BoxOwnProps, __isBoxStyledSystemProp } from './Box'
import { Box, BoxOwnProps } from './Box'
import { Assign, ForwardRef } from './types'
import { getProps, __internalProps } from './util'

const getContainerProps = getProps(__isBoxStyledSystemProp)
const getIframeProps = getProps((str) => !__isBoxStyledSystemProp(str))
import { __internalProps } from './util'

export interface EmbedProps
extends Assign<React.ComponentPropsWithRef<'iframe'>, BoxOwnProps> {
Expand Down Expand Up @@ -47,14 +44,13 @@ export const Embed: ForwardRef<HTMLIFrameElement, EmbedProps> =
frameBorder,
allowFullScreen,
allow,
...getIframeProps(rest),
...rest,
}

return (
<Box
variant={variant}
sx={sx}
{...getContainerProps(rest)}
{...__internalProps({
__css: {
width: '100%',
Expand Down
10 changes: 6 additions & 4 deletions packages/components/src/Field.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ import React from 'react'
import { Box } from './Box'
import { Label } from './Label'
import { Input, InputProps } from './Input'
import { getMargin, MarginProps, omitMargin } from './util'
import type { ThemeUICSSObject } from '@theme-ui/css'

export interface FieldOwnProps extends MarginProps {
export interface FieldOwnProps {
/**
* Text for Label component
*/
Expand All @@ -14,6 +14,7 @@ export interface FieldOwnProps extends MarginProps {
* Used for the for, id, and name attributes
*/
name?: string
containerSx?: ThemeUICSSObject
}

export type FieldProps<T extends React.ElementType> = FieldOwnProps &
Expand All @@ -39,6 +40,7 @@ export const Field = React.forwardRef(function Field<
label,
id,
name,
containerSx,
...rest
}: FieldProps<T>,
ref: React.ForwardedRef<unknown>
Expand All @@ -49,11 +51,11 @@ export const Field = React.forwardRef(function Field<
ref,
name,
id: fieldIdentifier,
...omitMargin(rest),
...rest,
} as React.ComponentPropsWithRef<T>

return (
<Box {...getMargin(rest)}>
<Box sx={containerSx}>
<Label htmlFor={fieldIdentifier}>{label}</Label>
<Control {...controlProps} />
</Box>
Expand Down
4 changes: 2 additions & 2 deletions packages/components/src/Message.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import React from 'react'
import { ThemeUICSSObject } from '@theme-ui/css'
import type { ThemeUICSSObject } from '@theme-ui/css'

import { Box, BoxProps } from './Box'
import { ForwardRef } from './types'
import type { ForwardRef } from './types'
import { __internalProps } from './util'

export type MessageProps = BoxProps
Expand Down
2 changes: 1 addition & 1 deletion packages/components/src/Progress.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react'

import { ThemeUICSSObject } from '@theme-ui/css'
import type { ThemeUICSSObject } from '@theme-ui/css'

import { Box, BoxOwnProps, BoxProps } from './Box'
import type { Assign, ForwardRef } from './types'
Expand Down
11 changes: 6 additions & 5 deletions packages/components/src/Select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import { get, ThemeUICSSObject } from '@theme-ui/css'

import { Box, BoxOwnProps, BoxProps } from './Box'
import { SVG, SVGProps } from './SVG'
import { getMargin, omitMargin, __internalProps } from './util'
import { Assign, ForwardRef } from './types'
import { __internalProps } from './util'
import type { Assign, ForwardRef } from './types'

const DownArrow = (props: SVGProps) => (
<SVG {...props}>
Expand All @@ -16,6 +16,7 @@ const DownArrow = (props: SVGProps) => (
export interface SelectProps
extends Assign<React.ComponentPropsWithRef<'select'>, BoxOwnProps> {
arrow?: React.ReactElement
containerSx?: ThemeUICSSObject
}

/**
Expand All @@ -24,7 +25,7 @@ export interface SelectProps
* @see https://theme-ui.com/components/select/
*/
export const Select: ForwardRef<HTMLSelectElement, SelectProps> =
React.forwardRef(function Select({ arrow, ...props }, ref) {
React.forwardRef(function Select({ arrow, containerSx, ...props }, ref) {
const __css: ThemeUICSSObject = {
display: 'block',
width: '100%',
Expand All @@ -41,16 +42,16 @@ export const Select: ForwardRef<HTMLSelectElement, SelectProps> =

return (
<Box
{...getMargin(props)}
sx={{
display: 'flex',
...containerSx,
}}
>
<Box
ref={ref}
as="select"
variant="select"
{...(omitMargin(props) as BoxProps)}
{...(props as BoxProps)}
{...__internalProps({ __themeKey: 'forms', __css })}
/>
{arrow || (
Expand Down
5 changes: 3 additions & 2 deletions packages/components/src/Switch.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const SIZE = 18
export interface SwitchProps
extends Assign<React.ComponentPropsWithRef<'input'>, BoxOwnProps> {
label?: string
containerSx?: ThemeUICSSObject
}

/**
Expand All @@ -23,7 +24,7 @@ export interface SwitchProps
*/
export const Switch: ForwardRef<HTMLInputElement, SwitchProps> =
React.forwardRef(function Switch(
{ className, label, sx, variant = 'switch', ...rest },
{ className, label, sx, containerSx, variant = 'switch', ...rest },
ref
) {
const __css: ThemeUICSSObject = {
Expand Down Expand Up @@ -59,7 +60,7 @@ export const Switch: ForwardRef<HTMLInputElement, SwitchProps> =
}

return (
<Label sx={{ cursor: 'pointer' }}>
<Label sx={{ cursor: 'pointer', ...containerSx }}>
<Box
ref={ref}
as="input"
Expand Down
23 changes: 0 additions & 23 deletions packages/components/src/util.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,5 @@
import type { ThemeUICSSObject, ThemeUICSSProperties } from '@theme-ui/css'

export const getProps =
(test: (k: string) => boolean) =>
<T extends object>(props: T): T => {
const next: Partial<T> = {}
for (const key in props) {
if (test(key || '')) next[key] = props[key]
}
return next as T
}

const MRE = /^m[trblxy]?$/

export interface MarginProps
extends Pick<
ThemeUICSSProperties,
'm' | 'mt' | 'mr' | 'mb' | 'ml' | 'mx' | 'my'
> {}

export const getMargin: (props: MarginProps) => MarginProps = getProps((k) =>
MRE.test(k)
)
export const omitMargin = getProps((k) => !MRE.test(k))

/** @internal */
export function __internalProps(props: __ThemeUIComponentsInternalProps) {
return props as {}
Expand Down
25 changes: 2 additions & 23 deletions packages/components/test/Box.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,30 +14,10 @@ import { __internalProps } from '../src/util'

describe('Box', () => {
test('renders', () => {
const json = renderJSON(<Box p={2}>Hello</Box>)
const json = renderJSON(<Box>Hello</Box>)
expect(json).toMatchSnapshot()
})

test('renders with padding props', () => {
const json = renderJSON(<Box px={2} py={4} />)
expect(json).toHaveStyleRule('padding-left', '8px')
expect(json).toHaveStyleRule('padding-right', '8px')
expect(json).toHaveStyleRule('padding-top', '32px')
expect(json).toHaveStyleRule('padding-bottom', '32px')
})

test('renders with margin props', () => {
const json = renderJSON(<Box m={3} mb={4} />)
expect(json).toHaveStyleRule('margin', '16px')
expect(json).toHaveStyleRule('margin-bottom', '32px')
})

test('renders with color props', () => {
const json = renderJSON(<Box color="tomato" bg="black" />)
expect(json).toHaveStyleRule('color', 'tomato')
expect(json).toHaveStyleRule('background-color', 'black')
})

test('renders with sx prop', () => {
const json = renderJSON(
<Box
Expand All @@ -64,8 +44,7 @@ describe('Box', () => {
test('renders with base styles', () => {
const json = renderJSON(
<Box
bg="cyan"
sx={{ color: 'tomato' }}
sx={{ bg: 'cyan', color: 'tomato' }}
{...__internalProps({
__css: {
p: 4,
Expand Down
Loading