diff --git a/examples/styled-components/src/App.tsx b/examples/styled-components/src/App.tsx index 3e0b4b2..5316579 100644 --- a/examples/styled-components/src/App.tsx +++ b/examples/styled-components/src/App.tsx @@ -1,11 +1,12 @@ import React from 'react'; import { ThemeProvider } from 'styled-components'; import { theme } from './theme'; -import { Box } from './Box'; +import { Box, css } from './Box'; const Button = (props) => { return ( { css?: CSSProp; } -const styles = system({ +const config = { ...color, ...border, ...background, @@ -52,30 +53,13 @@ const styles = system({ ...space, ...typography, ...extraProps, -}); - -const BaseElement = ({ - is: Component = 'div', - ...props -}: PropsWithChildren<{ is?: ElementType }>) => { - const rest = Object.keys(props).reduce((acc, curr) => { - if (shouldForwardProp(curr)) { - return { ...acc, [curr]: props[curr] }; - } - return acc; - }, {}); - - return ; }; -export const Box = ({ cx, ...props }: BoxProps) => { - return ( - - ); -}; +export const css = createCss(config); + +export const Box = styled('div').withConfig({ + shouldForwardProp: (prop, defaultValidtorFn) => + shouldForwardProp(prop) && + defaultValidtorFn(prop) && + !Object.keys(extraProps).includes(prop), +})({ boxSizing: 'border-box' }, system(config)); diff --git a/src/__tests__/exports.test.ts b/src/__tests__/exports.test.ts index 0bcdbf0..12d911f 100644 --- a/src/__tests__/exports.test.ts +++ b/src/__tests__/exports.test.ts @@ -6,7 +6,9 @@ test('package has expected exports', () => { "background", "border", "color", + "createCss", "createSystem", + "css", "flexContainer", "flexItem", "flexbox", diff --git a/src/core/createCss.ts b/src/core/createCss.ts index ddb1801..9a1152c 100644 --- a/src/core/createCss.ts +++ b/src/core/createCss.ts @@ -1,7 +1,14 @@ import { get, memoizedGet } from './get'; -import { Theme, SystemConfig, PrefixOptions } from '../types'; +import { + PropConfigCollection, + Theme, + SystemConfig, + PrefixOptions, +} from '../types'; import { CSSObject } from '../css-prop'; import { merge } from './merge'; +import * as CSS from 'csstype'; +import { createStyleFunction } from './createStyleFunction'; type CSSFunctionArgs = | CSSObject @@ -12,9 +19,29 @@ export type CSSFunction = ( ) => (theme: Theme) => CSSObject | undefined; export const createCss = ( - config: { [x: string]: SystemConfig }, - tokenPrefix: 'all' | 'prefix' | 'noprefix' + propConfig: PropConfigCollection, + options: { tokenPrefix: PrefixOptions } = { tokenPrefix: 'prefix' } ) => { + const { tokenPrefix } = options; + const config: { [x: string]: SystemConfig } = {}; + + Object.keys(propConfig).forEach((key) => { + const conf = propConfig[key]; + if (conf === true) { + // shortcut definition + config[key] = createStyleFunction({ + property: key as keyof CSS.Properties, + scale: key, + tokenPrefix, + }); + return; + } + if (typeof conf === 'function') { + return; + } + config[key] = createStyleFunction({ ...conf, tokenPrefix }); + }); + const css: CSSFunction = (args) => ({ theme }) => { if (typeof args === 'undefined') { return; diff --git a/src/core/createSystem.ts b/src/core/createSystem.ts index 584f2d5..1e3ea30 100644 --- a/src/core/createSystem.ts +++ b/src/core/createSystem.ts @@ -8,21 +8,17 @@ import { Props, SomeObject, Cache, - PrefixDefault, - PrefixOptions, } from '../types'; import { sort } from './sort'; import { merge } from './merge'; import { pseudoSelectors as defaultPseudos } from '../pseudos'; import * as CSS from 'csstype'; -import { createCss, CSSFunction } from './createCss'; -export interface Parser { +export interface Parser { (...args: any[]): any; config: { [key: string]: SystemConfig }; propNames: string[]; cache: Cache; - css?: CSSFunction; } const createMediaQuery = (n: string) => `@media screen and (min-width: ${n})`; @@ -188,8 +184,6 @@ export const createSystem = ({ config[key] = createStyleFunction({ ...conf, tokenPrefix }); }); const parser = createParser(config, pseudoSelectors, strict); - const cssFunction = createCss(config, tokenPrefix); - parser.css = cssFunction; return parser; }; diff --git a/src/core/index.ts b/src/core/index.ts index da40d21..c76a382 100644 --- a/src/core/index.ts +++ b/src/core/index.ts @@ -1,2 +1,3 @@ export { get } from './get'; export { createSystem } from './createSystem'; +export { createCss } from './createCss'; diff --git a/src/core/tests/css.test.ts b/src/core/tests/css.test.ts new file mode 100644 index 0000000..078917a --- /dev/null +++ b/src/core/tests/css.test.ts @@ -0,0 +1,105 @@ +import { createCss } from '../createCss'; +import { space, color } from '../../props'; + +const breakpoints = [40, 52, 64].map((n) => n + 'em'); + +test('createCss returns a css parser', () => { + const testCss = createCss({ ...space, ...color }); + expect(typeof testCss).toBe('function'); + // @ts-ignore + const styles = testCss({ + color: 'tomato', + backgroundColor: '$primary', + mx: '$2', + opacity: 1, + ':hover': { + opacity: 0.5, + }, + $bp1: { + color: 'green', + }, + '@media and (min-width: 300px)': { + mx: '$3', + }, + })({ + theme: { + breakpoints, + mediaQueries: breakpoints.reduce((acc, bp, index) => { + return { ...acc, [`bp${index + 1}`]: `@media and (min-width: ${bp})` }; + }, {}), + space: ['0px', '4px', '8px', '16px', '32px'], + colors: { + primary: 'rebeccapurple', + }, + }, + }); + expect(styles).toEqual({ + color: 'tomato', + backgroundColor: 'rebeccapurple', + marginLeft: '8px', + marginRight: '8px', + opacity: 1, + ':hover': { + opacity: 0.5, + }, + '@media and (min-width: 40em)': { + color: 'green', + }, + '@media and (min-width: 300px)': { + marginLeft: '16px', + marginRight: '16px', + }, + }); +}); + +test('createCss takes option to change token prefix', () => { + const testCss = createCss( + { ...space, ...color }, + { tokenPrefix: 'noprefix' } + ); + expect(typeof testCss).toBe('function'); + // @ts-ignore + const styles = testCss({ + color: 'tomato', + backgroundColor: 'primary', + mx: 2, + opacity: 1, + ':hover': { + opacity: 0.5, + }, + bp1: { + color: 'green', + }, + '@media and (min-width: 300px)': { + mx: '3', + }, + })({ + theme: { + breakpoints, + mediaQueries: breakpoints.reduce((acc, bp, index) => { + return { ...acc, [`bp${index + 1}`]: `@media and (min-width: ${bp})` }; + }, {}), + space: ['0px', '4px', '8px', '16px', '32px'], + colors: { + primary: 'rebeccapurple', + }, + }, + }); + expect(styles).toEqual({ + color: 'tomato', + backgroundColor: 'rebeccapurple', + marginLeft: '8px', + marginRight: '8px', + opacity: 1, + ':hover': { + opacity: 0.5, + }, + '@media and (min-width: 40em)': { + color: 'green', + }, + '@media and (min-width: 300px)': { + marginLeft: '16px', + marginRight: '16px', + }, + }); +}); diff --git a/src/core/tests/system.test.ts b/src/core/tests/system.test.ts index 13f3671..383b32c 100644 --- a/src/core/tests/system.test.ts +++ b/src/core/tests/system.test.ts @@ -433,69 +433,3 @@ describe('tokenPrefix', () => { }); }); }); - -test('parser has a css property that also parses styles', () => { - const system = createSystem(); - const parser = system({ - color: true, - backgroundColor: { - property: 'backgroundColor', - scale: 'colors', - }, - mx: { - scale: 'space', - properties: ['marginLeft', 'marginRight'], - }, - size: { - properties: ['height', 'width'], - }, - }); - expect(typeof parser.css).toBe('function'); - // @ts-ignore - const styles = parser.css({ - color: 'tomato', - backgroundColor: '$primary', - mx: '$2', - size: '400px', - opacity: 1, - ':hover': { - opacity: 0.5, - }, - $bp1: { - color: 'green', - }, - '@media and (min-width: 300px)': { - mx: '$3', - }, - })({ - theme: { - breakpoints, - mediaQueries: breakpoints.reduce((acc, bp, index) => { - return { ...acc, [`bp${index + 1}`]: `@media and (min-width: ${bp})` }; - }, {}), - space: ['0px', '4px', '8px', '16px', '32px'], - colors: { - primary: 'rebeccapurple', - }, - }, - }); - expect(styles).toEqual({ - color: 'tomato', - backgroundColor: 'rebeccapurple', - marginLeft: '8px', - marginRight: '8px', - height: '400px', - width: '400px', - opacity: 1, - ':hover': { - opacity: 0.5, - }, - '@media and (min-width: 40em)': { - color: 'green', - }, - '@media and (min-width: 300px)': { - marginLeft: '16px', - marginRight: '16px', - }, - }); -}); diff --git a/src/index.ts b/src/index.ts index 450e329..b0eb4db 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,36 @@ -export { createSystem } from './core/createSystem'; +import { + background, + border, + color, + flexbox, + grid, + layout, + position, + shadow, + space, + transition, + typography, +} from './props'; +import { createCss } from './core'; +export const css = createCss( + { + ...background, + ...border, + ...color, + ...flexbox, + ...grid, + ...layout, + ...position, + ...shadow, + ...space, + ...transition, + ...typography, + }, + { tokenPrefix: 'prefix' } +); + +export { createSystem, createCss } from './core'; export * from './props'; export * from './pseudos'; export * from './propNames';