From b650890169d449bbe2f9d0a89af79c6b1876a120 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Le=20Ralec?= Date: Wed, 6 Jul 2022 23:03:45 +0200 Subject: [PATCH] refactor: getStyles function --- src/config/background.ts | 22 +++++++------- src/config/border.ts | 63 ++++++++++++++++++++------------------- src/config/color.ts | 19 ++++++------ src/config/flex.ts | 38 ++++++++++++----------- src/config/grid.ts | 37 ++++++++++++----------- src/config/layout.ts | 35 +++++++++++----------- src/config/other.ts | 24 ++++++++------- src/config/position.ts | 25 ++++++++-------- src/config/space.ts | 37 +++++++++++++---------- src/config/typography.ts | 28 +++++++++-------- src/types.ts | 6 ++++ src/utils/index.ts | 36 ++++++++++++++++++++-- test/config/color.test.ts | 9 ++++-- test/utils/index.test.ts | 36 ++++++++++++++++------ 14 files changed, 247 insertions(+), 168 deletions(-) diff --git a/src/config/background.ts b/src/config/background.ts index 8aae53b..759f03a 100644 --- a/src/config/background.ts +++ b/src/config/background.ts @@ -1,7 +1,7 @@ import type * as CSS from 'csstype' -import type { CSSObject } from 'styled-components' -import type { Props, ThemeProp } from '../types' +import type { Props, Config, ThemeProp } from '../types' +import { getStyles } from '../utils' export type BackgroundProps = Props<{ background: CSS.Property.Background @@ -11,12 +11,14 @@ export type BackgroundProps = Props<{ backgroundRepeat: CSS.Property.BackgroundRepeat }> -export const background = (props: BackgroundProps & ThemeProp): CSSObject => { - return { - background: props.background, - backgroundImage: props.backgroundImage, - backgroundSize: props.backgroundSize, - backgroundPosition: props.backgroundPosition, - backgroundRepeat: props.backgroundRepeat, - } +const config: Config[] = [ + { property: 'background' }, + { property: 'backgroundImage' }, + { property: 'backgroundSize' }, + { property: 'backgroundPosition' }, + { property: 'backgroundRepeat' }, +] + +export const background = (props: BackgroundProps & ThemeProp) => { + return getStyles(config, props) } diff --git a/src/config/border.ts b/src/config/border.ts index dfd1d14..ef4e2b4 100644 --- a/src/config/border.ts +++ b/src/config/border.ts @@ -1,8 +1,7 @@ import type * as CSS from 'csstype' -import type { CSSObject } from 'styled-components' -import type { Props, ThemeProp, ThemeValues } from '../types' -import { get } from '../utils' +import type { Props, ThemeProp, Config, ThemeValues } from '../types' +import { getStyles } from '../utils' export type BorderProps = Props<{ border: CSS.Property.Border @@ -32,32 +31,34 @@ export type BorderProps = Props<{ borderLeftColor: ThemeValues<'colors'> | CSS.Property.BorderLeftColor }> -export const border = (props: BorderProps & ThemeProp): CSSObject => { - return { - border: props.border, - borderWidth: get(props.borderWidth, props.theme, 'borderWidths'), - borderStyle: props.borderStyle, - borderColor: get(props.borderColor, props.theme, 'colors'), - borderRadius: get(props.borderRadius, props.theme, 'radii'), - borderTop: props.borderTop, - borderTopWidth: get(props.borderTopWidth, props.theme, 'borderWidths'), - borderTopStyle: props.borderTopStyle, - borderTopColor: get(props.borderTopColor, props.theme, 'colors'), - borderTopLeftRadius: get(props.borderTopLeftRadius, props.theme, 'radii'), - borderTopRightRadius: get(props.borderTopRightRadius, props.theme, 'radii'), - borderRight: props.borderRight, - borderRightWidth: get(props.borderRightWidth, props.theme, 'borderWidths'), - borderRightStyle: props.borderRightStyle, - borderRightColor: get(props.borderRightColor, props.theme, 'colors'), - borderBottom: props.borderBottom, - borderBottomWidth: get(props.borderBottomWidth, props.theme, 'borderWidths'), - borderBottomStyle: props.borderBottomStyle, - borderBottomColor: get(props.borderBottomColor, props.theme, 'colors'), - borderBottomLeftRadius: get(props.borderBottomLeftRadius, props.theme, 'radii'), - borderBottomRightRadius: get(props.borderBottomRightRadius, props.theme, 'radii'), - borderLeft: props.borderLeft, - borderLeftWidth: get(props.borderLeftWidth, props.theme, 'borderWidths'), - borderLeftStyle: props.borderLeftStyle, - borderLeftColor: get(props.borderLeftColor, props.theme, 'colors'), - } +const config: Config[] = [ + { property: 'border' }, + { property: 'borderWidth', scope: 'borderWidths' }, + { property: 'borderStyle' }, + { property: 'borderColor', scope: 'colors' }, + { property: 'borderRadius', scope: 'radii' }, + { property: 'borderTop' }, + { property: 'borderTopWidth', scope: 'borderWidths' }, + { property: 'borderTopStyle' }, + { property: 'borderTopColor', scope: 'colors' }, + { property: 'borderTopLeftRadius', scope: 'radii' }, + { property: 'borderTopRightRadius', scope: 'radii' }, + { property: 'borderRight' }, + { property: 'borderRightWidth', scope: 'borderWidths' }, + { property: 'borderRightStyle' }, + { property: 'borderRightColor', scope: 'colors' }, + { property: 'borderBottom' }, + { property: 'borderBottomWidth', scope: 'borderWidths' }, + { property: 'borderBottomStyle' }, + { property: 'borderBottomColor', scope: 'colors' }, + { property: 'borderBottomLeftRadius', scope: 'radii' }, + { property: 'borderBottomRightRadius', scope: 'radii' }, + { property: 'borderLeft' }, + { property: 'borderLeftWidth', scope: 'borderWidths' }, + { property: 'borderLeftStyle' }, + { property: 'borderLeftColor', scope: 'colors' }, +] + +export const border = (props: BorderProps & ThemeProp) => { + return getStyles(config, props) } diff --git a/src/config/color.ts b/src/config/color.ts index 283b6b0..42e938c 100644 --- a/src/config/color.ts +++ b/src/config/color.ts @@ -1,8 +1,7 @@ import type * as CSS from 'csstype' -import type { CSSObject } from 'styled-components' -import type { Props, ThemeProp, ThemeValues } from '../types' -import { get } from '../utils' +import type { Config, Props, ThemeProp, ThemeValues } from '../types' +import { getStyles } from '../utils' export type ColorProps = Props<{ color: ThemeValues<'colors'> | CSS.Property.Color @@ -10,10 +9,12 @@ export type ColorProps = Props<{ opacity: CSS.Property.Opacity }> -export const color = (props: ColorProps & ThemeProp): CSSObject => { - return { - color: get(props.color, props.theme, 'colors'), - backgroundColor: get(props.backgroundColor, props.theme, 'colors'), - opacity: props.opacity, - } +const config: Config[] = [ + { property: 'color', scope: 'colors' }, + { property: 'backgroundColor', scope: 'colors' }, + { property: 'opacity' }, +] + +export const color = (props: ColorProps & ThemeProp) => { + return getStyles(config, props) } diff --git a/src/config/flex.ts b/src/config/flex.ts index 8897040..0ff1ab3 100644 --- a/src/config/flex.ts +++ b/src/config/flex.ts @@ -1,7 +1,7 @@ import type * as CSS from 'csstype' -import type { CSSObject } from 'styled-components' -import type { Props, ThemeProp } from '../types' +import type { Config, Props, ThemeProp } from '../types' +import { getStyles } from '../utils' export type FlexProps = Props<{ alignItems: CSS.Property.AlignItems @@ -19,20 +19,22 @@ export type FlexProps = Props<{ order: CSS.Property.Order }> -export const flex = (props: FlexProps & ThemeProp): CSSObject => { - return { - alignItems: props.alignItems, - alignContent: props.alignContent, - justifyItems: props.justifyItems, - justifyContent: props.justifyContent, - flexWrap: props.flexWrap, - flexDirection: props.flexDirection, - flex: props.flex, - flexGrow: props.flexGrow, - flexShrink: props.flexShrink, - flexBasis: props.flexBasis, - justifySelf: props.justifySelf, - alignSelf: props.alignSelf, - order: props.order, - } +const config: Config[] = [ + { property: 'alignItems' }, + { property: 'alignContent' }, + { property: 'justifyItems' }, + { property: 'justifyContent' }, + { property: 'flex' }, + { property: 'flexBasis' }, + { property: 'flexDirection' }, + { property: 'flexGrow' }, + { property: 'flexShrink' }, + { property: 'flexWrap' }, + { property: 'justifySelf' }, + { property: 'alignSelf' }, + { property: 'order' }, +] + +export const flex = (props: FlexProps & ThemeProp) => { + return getStyles(config, props) } diff --git a/src/config/grid.ts b/src/config/grid.ts index b7c232e..dcdff3a 100644 --- a/src/config/grid.ts +++ b/src/config/grid.ts @@ -1,8 +1,7 @@ import type * as CSS from 'csstype' -import type { CSSObject } from 'styled-components' -import type { Props, ThemeProp, ThemeValues } from '../types' -import { get } from '../utils' +import type { Config, Props, ThemeProp, ThemeValues } from '../types' +import { getStyles } from '../utils' export type GridProps = Props<{ gridGap: ThemeValues<'spaces'> | CSS.Property.GridGap @@ -19,19 +18,21 @@ export type GridProps = Props<{ gridTemplateAreas: CSS.Property.Grid }> -export const grid = (props: GridProps & ThemeProp): CSSObject => { - return { - gridGap: get(props.gridGap, props.theme, 'spaces'), - gridRowGap: get(props.gridRowGap, props.theme, 'spaces'), - gridColumnGap: get(props.gridColumnGap, props.theme, 'spaces'), - gridColumn: props.gridColumn, - gridRow: props.gridRow, - gridArea: props.gridArea, - gridAutoFlow: props.gridAutoFlow, - gridAutoRows: props.gridAutoRows, - gridAutoColumns: props.gridAutoColumns, - gridTemplateRows: props.gridTemplateRows, - gridTemplateColumns: props.gridTemplateColumns, - gridTemplateAreas: props.gridTemplateAreas, - } +const config: Config[] = [ + { property: 'gridGap', scope: 'spaces' }, + { property: 'gridRowGap', scope: 'spaces' }, + { property: 'gridColumnGap', scope: 'spaces' }, + { property: 'gridColumn' }, + { property: 'gridRow' }, + { property: 'gridArea' }, + { property: 'gridAutoFlow' }, + { property: 'gridAutoRows' }, + { property: 'gridAutoColumns' }, + { property: 'gridTemplateRows' }, + { property: 'gridTemplateColumns' }, + { property: 'gridTemplateAreas' }, +] + +export const grid = (props: GridProps & ThemeProp) => { + return getStyles(config, props) } diff --git a/src/config/layout.ts b/src/config/layout.ts index 0d4b84d..e0fe438 100644 --- a/src/config/layout.ts +++ b/src/config/layout.ts @@ -1,8 +1,7 @@ import type * as CSS from 'csstype' -import type { CSSObject } from 'styled-components' -import type { Props, ThemeProp, ThemeValues } from '../types' -import { get } from '../utils' +import type { Config, Props, ThemeProp, ThemeValues } from '../types' +import { getStyles } from '../utils' export type LayoutProps = Props<{ w: ThemeValues<'sizes'> | CSS.Property.Width @@ -18,18 +17,20 @@ export type LayoutProps = Props<{ overflowY: CSS.Property.OverflowY }> -export const layout = (props: LayoutProps & ThemeProp): CSSObject => { - return { - width: get(props.w, props.theme, 'sizes'), - height: get(props.h, props.theme, 'sizes'), - minWidht: get(props.minW, props.theme, 'sizes'), - maxWidth: get(props.maxW, props.theme, 'sizes'), - minHeight: get(props.minH, props.theme, 'sizes'), - maxHeight: get(props.maxH, props.theme, 'sizes'), - display: props.display, - verticalAlign: props.verticalAlign, - overflow: props.overflow, - overflowX: props.overflowX, - overflowY: props.overflowY, - } +const config: Config[] = [ + { property: 'w', scope: 'sizes' }, + { property: 'h', scope: 'sizes' }, + { property: 'minW', scope: 'sizes' }, + { property: 'maxW', scope: 'sizes' }, + { property: 'minH', scope: 'sizes' }, + { property: 'maxH', scope: 'sizes' }, + { property: 'display' }, + { property: 'verticalAlign' }, + { property: 'overflow' }, + { property: 'overflowX' }, + { property: 'overflowY' }, +] + +export const layout = (props: LayoutProps & ThemeProp) => { + return getStyles(config, props) } diff --git a/src/config/other.ts b/src/config/other.ts index 5712cdf..6525186 100644 --- a/src/config/other.ts +++ b/src/config/other.ts @@ -1,7 +1,7 @@ import type * as CSS from 'csstype' -import type { CSSObject } from 'styled-components' -import type { Props, ThemeProp } from '../types' +import type { Config, Props, ThemeProp } from '../types' +import { getStyles } from '../utils' export type OtherProps = Props<{ cursor: CSS.Property.Cursor @@ -12,13 +12,15 @@ export type OtherProps = Props<{ visibility: CSS.Property.Visibility }> -export const other = (props: OtherProps & ThemeProp): CSSObject => { - return { - cursor: props.cursor, - float: props.float, - objectFit: props.objectFit, - objectPosition: props.objectPosition, - transform: props.transform, - visibility: props.visibility, - } +const config: Config[] = [ + { property: 'cursor' }, + { property: 'float' }, + { property: 'objectFit' }, + { property: 'objectPosition' }, + { property: 'transform' }, + { property: 'visibility' }, +] + +export const other = (props: OtherProps & ThemeProp) => { + return getStyles(config, props) } diff --git a/src/config/position.ts b/src/config/position.ts index 5716e14..e41e24c 100644 --- a/src/config/position.ts +++ b/src/config/position.ts @@ -1,8 +1,7 @@ import type * as CSS from 'csstype' -import type { CSSObject } from 'styled-components' -import type { Props, ThemeProp, ThemeValues } from '../types' -import { get } from '../utils' +import type { Config, Props, ThemeProp, ThemeValues } from '../types' +import { getStyles } from '../utils' export type PositionProps = Props<{ position: CSS.Property.Position @@ -13,13 +12,15 @@ export type PositionProps = Props<{ left: ThemeValues<'spaces'> | CSS.Property.Left }> -export const position = (props: PositionProps & ThemeProp): CSSObject => { - return { - position: props.position, - zIndex: props.zIndex, - top: get(props.top, props.theme, 'spaces'), - right: get(props.right, props.theme, 'spaces'), - bottom: get(props.bottom, props.theme, 'spaces'), - left: get(props.left, props.theme, 'spaces'), - } +const config: Config[] = [ + { property: 'position' }, + { property: 'zIndex' }, + { property: 'top', scope: 'spaces' }, + { property: 'right', scope: 'spaces' }, + { property: 'bottom', scope: 'spaces' }, + { property: 'left', scope: 'spaces' }, +] + +export const position = (props: PositionProps & ThemeProp) => { + return getStyles(config, props) } diff --git a/src/config/space.ts b/src/config/space.ts index b5e9674..8398c28 100644 --- a/src/config/space.ts +++ b/src/config/space.ts @@ -1,8 +1,7 @@ import type * as CSS from 'csstype' -import type { CSSObject } from 'styled-components' -import type { Props, ThemeProp, ThemeValues } from '../types' -import { get } from '../utils' +import type { Config, Props, ThemeProp, ThemeValues } from '../types' +import { getStyles } from '../utils' export type SpaceProps = Props<{ m: ThemeValues<'spaces'> | CSS.Property.Margin @@ -21,17 +20,23 @@ export type SpaceProps = Props<{ px: ThemeValues<'spaces'> | CSS.Property.Padding }> -export const space = (props: SpaceProps & ThemeProp): CSSObject => { - return { - margin: get(props.m, props.theme, 'spaces'), - marginTop: get(props.mt || props.my, props.theme, 'spaces'), - marginRight: get(props.mr || props.mx, props.theme, 'spaces'), - marginBottom: get(props.mb || props.mb, props.theme, 'spaces'), - marginLeft: get(props.ml || props.mx, props.theme, 'spaces'), - padding: get(props.p, props.theme, 'spaces'), - paddingTop: get(props.pt || props.py, props.theme, 'spaces'), - paddingRight: get(props.pr || props.px, props.theme, 'spaces'), - paddingBottom: get(props.pb || props.pb, props.theme, 'spaces'), - paddingLeft: get(props.pl || props.px, props.theme, 'spaces'), - } +const config: Config[] = [ + { property: 'm', scope: 'spaces' }, + { property: 'mt', scope: 'spaces' }, + { property: 'mr', scope: 'spaces' }, + { property: 'mb', scope: 'spaces' }, + { property: 'ml', scope: 'spaces' }, + { property: 'my', scope: 'spaces' }, + { property: 'mx', scope: 'spaces' }, + { property: 'p', scope: 'spaces' }, + { property: 'pt', scope: 'spaces' }, + { property: 'pr', scope: 'spaces' }, + { property: 'pb', scope: 'spaces' }, + { property: 'pl', scope: 'spaces' }, + { property: 'py', scope: 'spaces' }, + { property: 'px', scope: 'spaces' }, +] + +export const space = (props: SpaceProps & ThemeProp) => { + return getStyles(config, props) } diff --git a/src/config/typography.ts b/src/config/typography.ts index 4c7987a..c292b93 100644 --- a/src/config/typography.ts +++ b/src/config/typography.ts @@ -1,8 +1,7 @@ import type * as CSS from 'csstype' -import type { CSSObject } from 'styled-components' -import type { Props, ThemeProp, ThemeValues } from '../types' -import { get } from '../utils' +import type { Config, Props, ThemeProp, ThemeValues } from '../types' +import { getStyles } from '../utils' export type TypographyProps = Props<{ fontFamily: ThemeValues<'fonts'> | CSS.Property.FontFamily @@ -15,14 +14,17 @@ export type TypographyProps = Props<{ textDecoration: CSS.Property.TextDecoration }> -export const typography = (props: TypographyProps & ThemeProp): CSSObject => { - return { - fontFamily: get(props.fontFamily, props.theme, 'fonts'), - fontSize: get(props.fontSize, props.theme, 'fontSizes'), - fontWeight: get(props.fontWeight, props.theme, 'fontWeights'), - letterSpacing: get(props.letterSpacing, props.theme, 'letterSpacings'), - textAlign: props.textAlign, - fontStyle: props.fontStyle, - textDecoration: props.textDecoration, - } +const config: Config[] = [ + { property: 'fontFamily', scope: 'fonts' }, + { property: 'fontSize', scope: 'fontSizes' }, + { property: 'fontWeight', scope: 'fontWeights' }, + { property: 'lineHeight', scope: 'lineHeights' }, + { property: 'letterSpacing', scope: 'letterSpacings' }, + { property: 'textAlign' }, + { property: 'fontStyle' }, + { property: 'textDecoration' }, +] + +export const typography = (props: TypographyProps & ThemeProp) => { + return getStyles(config, props) } diff --git a/src/types.ts b/src/types.ts index 78189b4..a37a834 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,4 +1,5 @@ import type { Theme, ThemeKeys } from './theme' +import type { SystemProps } from './system' type ExcludeNumbers = { [Key in keyof T]: Exclude @@ -9,3 +10,8 @@ export type Props

= Partial> export type ThemeProp = Partial<{ theme: Theme }> export type ThemeValues = keyof Theme[Key] + +export type Config = { + property: keyof SystemProps + scope?: ThemeKeys +} diff --git a/src/utils/index.ts b/src/utils/index.ts index 9958af8..803bbb9 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -1,5 +1,37 @@ -import type { Theme } from '../theme' +import type { CSSObject } from 'styled-components' +import type { Theme, ThemeKeys } from '../theme' +import type { Config, ThemeProp } from '../types' +import type { SystemProps } from '../system' -export const get = (key: string, theme: T, scope: keyof T): string => { +const get = (key: string, theme: Theme, scope: ThemeKeys): string => { return theme?.[scope]?.[key] || key } + +// const createMediaQuery = (breakpoint: string) => `@media(min-width: ${breakpoint})` + +export const getStyles = (config: Config[], props: SystemProps & ThemeProp) => { + const styles: CSSObject = {} + + config.forEach(({ property, scope }) => { + const value = props[property] + + if (!value) return + + if (typeof value === 'string') { + styles[property as string] = get(value, props.theme, scope) + } + + // if (typeof value === 'object') { + // const { breakpoints } = props.theme + + // if (!breakpoints) return + + // Object.keys(value).forEach(breakpoint => { + // const v = value[breakpoint] + // styles[createMediaQuery(breakpoint)] = get(v, props.theme, scope) + // }) + // } + }) + + return styles +} diff --git a/test/config/color.test.ts b/test/config/color.test.ts index d35e254..ac7d64f 100644 --- a/test/config/color.test.ts +++ b/test/config/color.test.ts @@ -1,7 +1,6 @@ import { describe, it, expect } from 'vitest' import { color } from '../../src' -import type { Theme } from '../../src/theme' const props = { color: undefined, @@ -25,11 +24,17 @@ describe('color', () => { }) it('return primary.500 value with theme', () => { - const theme: Theme = { + const theme = { colors: { 'primary.500': 'tomato', }, } expect(color({ ...props, color: 'primary.500', theme })).toEqual({ ...props, color: 'tomato' }) }) + + // it('return responsive color', () => { + // const theme = { + // colors: {}, + // } + // }) }) diff --git a/test/utils/index.test.ts b/test/utils/index.test.ts index 5e756d9..ed0de26 100644 --- a/test/utils/index.test.ts +++ b/test/utils/index.test.ts @@ -1,24 +1,42 @@ -import { describe, it, expect } from 'vitest' +import { describe, it, expect, beforeEach } from 'vitest' -import type { Theme } from '../../src/theme' -import { get } from '../../src/utils' +import { getStyles } from '../../src/utils' +import type { Config } from '../../src/types' -const theme: Theme = { +const theme = { colors: { - 'primary.500': 'tomato', + primary: 'tomato', }, } -describe('get', () => { +const defaultProps = { color: 'primary', theme } +const defaultConfig: Config[] = [{ property: 'color', scope: 'colors' }] + +let props = {} +let config: Config[] = [] + +beforeEach(() => { + props = { ...defaultProps } + config = [...defaultConfig] +}) + +describe('getStyles', () => { it('should get theme value', () => { - expect(get('primary.500', theme, 'colors')).toBe(theme.colors?.['primary.500']) + expect(getStyles(config, props)).toEqual({ color: 'tomato' }) }) it('should fallback with unknown value', () => { - expect(get('secondary.500', theme, 'colors')).toBe('secondary.500') + props = { ...props, color: 'secondary' } + expect(getStyles(config, props)).toEqual({ color: 'secondary' }) }) it('should fallback with bad scope', () => { - expect(get('secondary.500', theme, 'spaces')).toBe('secondary.500') + config = [{ property: 'color', scope: 'spaces' }] + expect(getStyles(config, props)).toEqual({ color: 'primary' }) + }) + + it('should fallback without scope', () => { + config = [{ property: 'color' }] + expect(getStyles(config, props)).toEqual({ color: 'primary' }) }) })