diff --git a/packages/components/package.json b/packages/components/package.json index 849616e59..d7f97dda6 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -1,12 +1,14 @@ { "name": "@theme-ui/components", "version": "0.3.1", + "source": "src/index.ts", "main": "dist/index.js", "module": "dist/index.esm.js", + "types": "dist/index.d.ts", "sideEffects": false, "scripts": { - "prepare": "microbundle --no-compress --jsx React.createElement", - "watch": "microbundle watch --no-compress --jsx React.createElement" + "prepare": "microbundle --no-compress --jsx React.createElement --tsconfig tsconfig.json", + "watch": "microbundle watch --no-compress --jsx React.createElement --tsconfig tsconfig.json" }, "dependencies": { "@emotion/core": "^10.0.0", diff --git a/packages/components/src/Alert.js b/packages/components/src/Alert.js deleted file mode 100644 index 6a71f6864..000000000 --- a/packages/components/src/Alert.js +++ /dev/null @@ -1,20 +0,0 @@ -import React from 'react' -import Box from './Box' - -export const Alert = React.forwardRef((props, ref) => ( - -)) diff --git a/packages/components/src/Alert.tsx b/packages/components/src/Alert.tsx new file mode 100644 index 000000000..c7d7fd028 --- /dev/null +++ b/packages/components/src/Alert.tsx @@ -0,0 +1,30 @@ +import React from 'react' +import Box, { BoxProps, ForwardRef } from './Box' + +type AlertProps = BoxProps +/** + * Component for displaying messages, notifications, or other application state. + * + * Alert variants can be defined in `theme.alerts`. + * The Alert component uses `theme.alerts.primary` as its default variant. + */ + +export const Alert: ForwardRef = React.forwardRef( + (props, ref) => ( + + ) +) diff --git a/packages/components/src/AspectImage.js b/packages/components/src/AspectImage.js deleted file mode 100644 index 6459a3674..000000000 --- a/packages/components/src/AspectImage.js +++ /dev/null @@ -1,15 +0,0 @@ -import React from 'react' -import { AspectRatio } from './AspectRatio' -import { Image } from './Image' - -export const AspectImage = React.forwardRef(({ ratio, ...props }, ref) => ( - - - -)) diff --git a/packages/components/src/AspectImage.tsx b/packages/components/src/AspectImage.tsx new file mode 100644 index 000000000..255871578 --- /dev/null +++ b/packages/components/src/AspectImage.tsx @@ -0,0 +1,27 @@ +import React from 'react' +import { AspectRatio } from './AspectRatio' +import { Image, ImageProps } from './Image' +import { ForwardRef } from './Box' + +interface AspectImageProps extends ImageProps { + ratio?: number +} +/** + * Image component constrained by as aspect ratio. + * @see https://theme-ui.com/components/aspect-image + */ + +export const AspectImage: ForwardRef< + HTMLImageElement, + AspectImageProps +> = React.forwardRef(({ ratio, ...props }, ref) => ( + + + +)) diff --git a/packages/components/src/AspectRatio.js b/packages/components/src/AspectRatio.js deleted file mode 100644 index 8c563097f..000000000 --- a/packages/components/src/AspectRatio.js +++ /dev/null @@ -1,32 +0,0 @@ -import React from 'react' -import Box from './Box' - -export const AspectRatio = React.forwardRef( - ({ ratio = 4 / 3, children, ...props }, ref) => ( - - - - {children} - - - ) -) diff --git a/packages/components/src/AspectRatio.tsx b/packages/components/src/AspectRatio.tsx new file mode 100644 index 000000000..441b54583 --- /dev/null +++ b/packages/components/src/AspectRatio.tsx @@ -0,0 +1,41 @@ +import React from 'react' +import Box, { BoxProps, ForwardRef } from './Box' + +interface AspectRatioProps extends BoxProps { + ratio?: number +} +/** + * Component for maintaining a fluid-width aspect ratio + * @see https://theme-ui.com/components/aspect-ratio + */ + +export const AspectRatio: ForwardRef< + HTMLDivElement, + AspectRatioProps +> = React.forwardRef(({ ratio = 4 / 3, children, ...props }, ref) => ( + + + + {children} + + +)) diff --git a/packages/components/src/Avatar.js b/packages/components/src/Avatar.js deleted file mode 100644 index ff7a0110b..000000000 --- a/packages/components/src/Avatar.js +++ /dev/null @@ -1,15 +0,0 @@ -import React from 'react' -import { Image } from './Image' - -export const Avatar = React.forwardRef(({ size = 48, ...props }, ref) => ( - -)) diff --git a/packages/components/src/Avatar.tsx b/packages/components/src/Avatar.tsx new file mode 100644 index 000000000..1d40c9bbc --- /dev/null +++ b/packages/components/src/Avatar.tsx @@ -0,0 +1,23 @@ +import React from 'react' +import { Image, ImageProps } from './Image' +import { ForwardRef } from './Box' + +interface AvatarProps extends ImageProps { + size?: number | string +} + +export const Avatar: ForwardRef< + HTMLImageElement, + AvatarProps +> = React.forwardRef(({ size = 48, ...props }, ref) => ( + +)) diff --git a/packages/components/src/Badge.js b/packages/components/src/Badge.js deleted file mode 100644 index 912f59ead..000000000 --- a/packages/components/src/Badge.js +++ /dev/null @@ -1,21 +0,0 @@ -import React from 'react' -import Box from './Box' - -export const Badge = React.forwardRef((props, ref) => ( - -)) diff --git a/packages/components/src/Badge.tsx b/packages/components/src/Badge.tsx new file mode 100644 index 000000000..9669066b5 --- /dev/null +++ b/packages/components/src/Badge.tsx @@ -0,0 +1,25 @@ +import React from 'react' +import Box, { BoxProps, ForwardRef } from './Box' + +export type BadgeProps = BoxProps + +export const Badge: ForwardRef = React.forwardRef( + (props, ref) => ( + + ) +) diff --git a/packages/components/src/Box.js b/packages/components/src/Box.js deleted file mode 100644 index c4c0c0bfa..000000000 --- a/packages/components/src/Box.js +++ /dev/null @@ -1,33 +0,0 @@ -import styled from '@emotion/styled' -import { css, get } from '@theme-ui/css' -import { createShouldForwardProp } from '@styled-system/should-forward-prop' -import space from '@styled-system/space' -import color from '@styled-system/color' - -const shouldForwardProp = createShouldForwardProp([ - ...space.propNames, - ...color.propNames, -]) - -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))) - -export const Box = styled('div', { - shouldForwardProp, -})( - { - boxSizing: 'border-box', - margin: 0, - minWidth: 0, - }, - base, - variant, - space, - color, - sx, - props => props.css -) - -export default Box diff --git a/packages/components/src/Box.tsx b/packages/components/src/Box.tsx new file mode 100644 index 000000000..c70fe6c4c --- /dev/null +++ b/packages/components/src/Box.tsx @@ -0,0 +1,72 @@ +import styled from '@emotion/styled' +import { css, get } from '@theme-ui/css' +import { createShouldForwardProp } from '@styled-system/should-forward-prop' +import space from '@styled-system/space' +import color from '@styled-system/color' + +import { StyledComponent } from '@emotion/styled' +import { InterpolationWithTheme } from '@emotion/core' +import { SxStyleProp } from 'theme-ui' +import { SpaceProps, ColorProps } from 'styled-system' + +export type Omit = Pick> + +export type Assign = { + [P in keyof (T & U)]: P extends keyof T + ? T[P] + : P extends keyof U + ? U[P] + : never +} + +export type ForwardRef = React.ForwardRefExoticComponent< + React.PropsWithoutRef

& React.RefAttributes +> + +export interface BoxOwnProps extends SpaceProps, ColorProps { + as?: React.ElementType + variant?: string + sx?: SxStyleProp + css?: InterpolationWithTheme + __themeKey?: string //TODO is __themeKey a "keyof / typeof" from the theme spec? +} + +export interface BoxProps + extends Assign, BoxOwnProps> {} + +/** + * Use the Box component as a layout primitive to add margin, padding, and colors to content. + * @see https://theme-ui.com/components/box + */ + +const shouldForwardProp = createShouldForwardProp([ + ...space.propNames, + ...color.propNames, +]) + +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))) + +export const Box: StyledComponent< + React.ComponentProps<'div'>, + BoxOwnProps, + {} +> = styled('div', { + shouldForwardProp, +})( + { + boxSizing: 'border-box', + margin: 0, + minWidth: 0, + }, + base, + variant, + space, + color, + sx, + props => props.css +) + +export default Box diff --git a/packages/components/src/Button.js b/packages/components/src/Button.tsx similarity index 50% rename from packages/components/src/Button.js rename to packages/components/src/Button.tsx index 100224899..a22575a15 100644 --- a/packages/components/src/Button.js +++ b/packages/components/src/Button.tsx @@ -1,14 +1,24 @@ import React from 'react' -import Box from './Box' +import Box, { Assign, BoxOwnProps, ForwardRef } from './Box' -export const Button = React.forwardRef((props, ref) => ( +export interface ButtonProps + extends Assign, BoxOwnProps> {} +/** + * Primitive button component with variants + * @see https://theme-ui.com/components/button + */ + +export const Button: ForwardRef< + HTMLButtonElement, + ButtonProps +> = React.forwardRef((props, ref) => ( ( - -)) diff --git a/packages/components/src/Card.tsx b/packages/components/src/Card.tsx new file mode 100644 index 000000000..dfce34e05 --- /dev/null +++ b/packages/components/src/Card.tsx @@ -0,0 +1,16 @@ +import React from 'react' +import Box, { BoxProps, ForwardRef } from './Box' + +export type CardProps = BoxProps +/** + * Card style variants can be defined in the `theme.cards` object. + * By default the Card component uses the `theme.cards.primary` variant. + * @see https://theme-ui.com/components/card + */ + +export const Card: ForwardRef< + HTMLDivElement, + CardProps +> = React.forwardRef((props, ref) => ( + +)) diff --git a/packages/components/src/Checkbox.js b/packages/components/src/Checkbox.tsx similarity index 77% rename from packages/components/src/Checkbox.js rename to packages/components/src/Checkbox.tsx index 65803c655..29e506c4e 100644 --- a/packages/components/src/Checkbox.js +++ b/packages/components/src/Checkbox.tsx @@ -1,7 +1,17 @@ import React from 'react' -import Box from './Box' +import Box, { Assign, BoxOwnProps, ForwardRef } from './Box' import SVG from './SVG' +export interface CheckboxProps + extends Assign, BoxOwnProps> {} +/** + * Form checkbox input component + * + * Checkbox variants can be defined in `theme.forms` and the + * component uses the `theme.forms.checkbox` variant by default. + * @see https://theme-ui.com/components/checkbox/ + */ + const CheckboxChecked = props => ( @@ -37,7 +47,10 @@ const CheckboxIcon = props => ( ) -export const Checkbox = React.forwardRef( +export const Checkbox: ForwardRef< + HTMLInputElement, + CheckboxProps +> = React.forwardRef( ({ className, sx, variant = 'checkbox', ...props }, ref) => ( - - -) - -export const Close = React.forwardRef(({ size = 32, ...props }, ref) => ( - -)) diff --git a/packages/components/src/Close.tsx b/packages/components/src/Close.tsx new file mode 100644 index 000000000..1dc7707ca --- /dev/null +++ b/packages/components/src/Close.tsx @@ -0,0 +1,39 @@ +import React from 'react' +import { IconButton, IconButtonProps } from './IconButton' +import { ForwardRef } from './Box' + +interface CloseProps extends Omit {} +/** + * Button with close (×) icon. + * + * The Close component renders as a