From 8227b64daa1e45e490d311730b7f504467446c8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Le=20Ralec?= Date: Wed, 6 Jul 2022 18:27:06 +0200 Subject: [PATCH] chore: theme declaration merging & ThemeValues helper --- .gitignore | 1 + README.md | 16 +++++++++++++++- src/config/border.ts | 33 ++++++++++++++++----------------- src/config/color.ts | 7 +++---- src/config/grid.ts | 9 ++++----- src/config/layout.ts | 15 +++++++-------- src/config/position.ts | 11 +++++------ src/config/space.ts | 31 +++++++++++++++---------------- src/config/typography.ts | 13 ++++++------- src/theme.ts | 18 ++++++++++++++++-- src/types.ts | 6 ++++-- src/utils/index.ts | 6 +++--- tsconfig.json | 2 +- 13 files changed, 96 insertions(+), 72 deletions(-) diff --git a/.gitignore b/.gitignore index a9e5cd3..7eee6fb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ node_modules dist +example *.tgz *.log \ No newline at end of file diff --git a/README.md b/README.md index 2ebfff1..d4f70cd 100644 --- a/README.md +++ b/README.md @@ -78,7 +78,7 @@ return ( ## ✨ Typescript -Thanks to [csstype](https://github.com/frenic/csstype), **jsx-to-styled** is fully typed. You will have autocomplete for all styled props with your theme values if provided or/and possible css values. +Thanks to [csstype](https://github.com/frenic/csstype), **jsx-to-styled** is fully typed. You will have autocomplete for all possible css values. ```tsx import system, { System } from 'jsx-to-styled' @@ -87,6 +87,20 @@ import system, { System } from 'jsx-to-styled' const Box = styled.div(system) ``` +If you want to access to your theme values, you have to redefine "Theme" interface with your custom theme like that: + +```ts +// theme.d.ts +import 'jsx-to-styled' +import { theme } from './theme' + +type MyTheme = typeof theme + +declare module 'jsx-to-styled' { + export interface Theme extends MyTheme {} +} +``` + ## 📕 Props > System is composed by all of props below diff --git a/src/config/border.ts b/src/config/border.ts index 40b52ae..dfd1d14 100644 --- a/src/config/border.ts +++ b/src/config/border.ts @@ -1,36 +1,35 @@ import type * as CSS from 'csstype' import type { CSSObject } from 'styled-components' -import type { Props, ThemeProp } from '../types' -import type { Theme } from '../theme' +import type { Props, ThemeProp, ThemeValues } from '../types' import { get } from '../utils' export type BorderProps = Props<{ border: CSS.Property.Border - borderWidth: keyof Theme['borderWidths'] | CSS.Property.BorderWidth + borderWidth: ThemeValues<'borderWidths'> | CSS.Property.BorderWidth borderStyle: CSS.Property.BorderStyle - borderColor: keyof Theme['colors'] | CSS.Property.BorderColor - borderRadius: keyof Theme['radii'] | CSS.Property.BorderRadius + borderColor: ThemeValues<'colors'> | CSS.Property.BorderColor + borderRadius: ThemeValues<'radii'> | CSS.Property.BorderRadius borderTop: CSS.Property.BorderTop - borderTopWidth: keyof Theme['borderWidths'] | CSS.Property.BorderTopWidth + borderTopWidth: ThemeValues<'borderWidths'> | CSS.Property.BorderTopWidth borderTopStyle: CSS.Property.BorderTopStyle - borderTopColor: keyof Theme['colors'] | CSS.Property.BorderTopColor - borderTopLeftRadius: keyof Theme['radii'] | CSS.Property.BorderTopLeftRadius - borderTopRightRadius: keyof Theme['radii'] | CSS.Property.BorderTopRightRadius + borderTopColor: ThemeValues<'colors'> | CSS.Property.BorderTopColor + borderTopLeftRadius: ThemeValues<'radii'> | CSS.Property.BorderTopLeftRadius + borderTopRightRadius: ThemeValues<'radii'> | CSS.Property.BorderTopRightRadius borderRight: CSS.Property.BorderRight - borderRightWidth: keyof Theme['borderWidths'] | CSS.Property.BorderRightWidth + borderRightWidth: ThemeValues<'borderWidths'> | CSS.Property.BorderRightWidth borderRightStyle: CSS.Property.BorderRightStyle - borderRightColor: keyof Theme['colors'] | CSS.Property.BorderRightColor + borderRightColor: ThemeValues<'colors'> | CSS.Property.BorderRightColor borderBottom: CSS.Property.BorderBottom - borderBottomWidth: keyof Theme['borderWidths'] | CSS.Property.BorderBottomWidth + borderBottomWidth: ThemeValues<'borderWidths'> | CSS.Property.BorderBottomWidth borderBottomStyle: CSS.Property.BorderBottomStyle - borderBottomColor: keyof Theme['colors'] | CSS.Property.BorderBottomColor - borderBottomLeftRadius: keyof Theme['radii'] | CSS.Property.BorderBottomLeftRadius - borderBottomRightRadius: keyof Theme['radii'] | CSS.Property.BorderBottomRightRadius + borderBottomColor: ThemeValues<'colors'> | CSS.Property.BorderBottomColor + borderBottomLeftRadius: ThemeValues<'radii'> | CSS.Property.BorderBottomLeftRadius + borderBottomRightRadius: ThemeValues<'radii'> | CSS.Property.BorderBottomRightRadius borderLeft: CSS.Property.BorderLeft - borderLeftWidth: keyof Theme['borderWidths'] | CSS.Property.BorderLeftWidth + borderLeftWidth: ThemeValues<'borderWidths'> | CSS.Property.BorderLeftWidth borderLeftStyle: CSS.Property.BorderLeftStyle - borderLeftColor: keyof Theme['colors'] | CSS.Property.BorderLeftColor + borderLeftColor: ThemeValues<'colors'> | CSS.Property.BorderLeftColor }> export const border = (props: BorderProps & ThemeProp): CSSObject => { diff --git a/src/config/color.ts b/src/config/color.ts index aceab94..283b6b0 100644 --- a/src/config/color.ts +++ b/src/config/color.ts @@ -1,13 +1,12 @@ import type * as CSS from 'csstype' import type { CSSObject } from 'styled-components' -import type { Props, ThemeProp } from '../types' -import type { Theme } from '../theme' +import type { Props, ThemeProp, ThemeValues } from '../types' import { get } from '../utils' export type ColorProps = Props<{ - color: keyof Theme['colors'] | CSS.Property.Color - backgroundColor: keyof Theme['colors'] | CSS.Property.BackgroundColor + color: ThemeValues<'colors'> | CSS.Property.Color + backgroundColor: ThemeValues<'colors'> | CSS.Property.BackgroundColor opacity: CSS.Property.Opacity }> diff --git a/src/config/grid.ts b/src/config/grid.ts index 4cdbc51..b7c232e 100644 --- a/src/config/grid.ts +++ b/src/config/grid.ts @@ -1,14 +1,13 @@ import type * as CSS from 'csstype' import type { CSSObject } from 'styled-components' -import type { Props, ThemeProp } from '../types' -import type { Theme } from '../theme' +import type { Props, ThemeProp, ThemeValues } from '../types' import { get } from '../utils' export type GridProps = Props<{ - gridGap: keyof Theme['spaces'] | CSS.Property.GridGap - gridRowGap: keyof Theme['spaces'] | CSS.Property.GridRowGap - gridColumnGap: keyof Theme['spaces'] | CSS.Property.GridColumnGap + gridGap: ThemeValues<'spaces'> | CSS.Property.GridGap + gridRowGap: ThemeValues<'spaces'> | CSS.Property.GridRowGap + gridColumnGap: ThemeValues<'spaces'> | CSS.Property.GridColumnGap gridColumn: CSS.Property.GridColumn gridRow: CSS.Property.GridRow gridArea: CSS.Property.GridArea diff --git a/src/config/layout.ts b/src/config/layout.ts index 71c4699..0d4b84d 100644 --- a/src/config/layout.ts +++ b/src/config/layout.ts @@ -1,17 +1,16 @@ import type * as CSS from 'csstype' import type { CSSObject } from 'styled-components' -import type { Props, ThemeProp } from '../types' -import type { Theme } from '../theme' +import type { Props, ThemeProp, ThemeValues } from '../types' import { get } from '../utils' export type LayoutProps = Props<{ - w: keyof Theme['sizes'] | CSS.Property.Width - h: keyof Theme['sizes'] | CSS.Property.Height - minW: keyof Theme['sizes'] | CSS.Property.MinWidth - maxW: keyof Theme['sizes'] | CSS.Property.MaxWidth - minH: keyof Theme['sizes'] | CSS.Property.MinHeight - maxH: keyof Theme['sizes'] | CSS.Property.MaxHeight + w: ThemeValues<'sizes'> | CSS.Property.Width + h: ThemeValues<'sizes'> | CSS.Property.Height + minW: ThemeValues<'sizes'> | CSS.Property.MinWidth + maxW: ThemeValues<'sizes'> | CSS.Property.MaxWidth + minH: ThemeValues<'sizes'> | CSS.Property.MinHeight + maxH: ThemeValues<'sizes'> | CSS.Property.MaxHeight display: CSS.Property.Display verticalAlign: CSS.Property.VerticalAlign overflow: CSS.Property.Overflow diff --git a/src/config/position.ts b/src/config/position.ts index a0f652e..5716e14 100644 --- a/src/config/position.ts +++ b/src/config/position.ts @@ -1,17 +1,16 @@ import type * as CSS from 'csstype' import type { CSSObject } from 'styled-components' -import type { Props, ThemeProp } from '../types' -import type { Theme } from '../theme' +import type { Props, ThemeProp, ThemeValues } from '../types' import { get } from '../utils' export type PositionProps = Props<{ position: CSS.Property.Position zIndex: CSS.Property.ZIndex - top: keyof Theme['spaces'] | CSS.Property.Top - right: keyof Theme['spaces'] | CSS.Property.Right - bottom: keyof Theme['spaces'] | CSS.Property.Bottom - left: keyof Theme['spaces'] | CSS.Property.Left + top: ThemeValues<'spaces'> | CSS.Property.Top + right: ThemeValues<'spaces'> | CSS.Property.Right + bottom: ThemeValues<'spaces'> | CSS.Property.Bottom + left: ThemeValues<'spaces'> | CSS.Property.Left }> export const position = (props: PositionProps & ThemeProp): CSSObject => { diff --git a/src/config/space.ts b/src/config/space.ts index 0cb6662..b5e9674 100644 --- a/src/config/space.ts +++ b/src/config/space.ts @@ -1,25 +1,24 @@ import type * as CSS from 'csstype' import type { CSSObject } from 'styled-components' -import type { Props, ThemeProp } from '../types' -import type { Theme } from '../theme' +import type { Props, ThemeProp, ThemeValues } from '../types' import { get } from '../utils' export type SpaceProps = Props<{ - m: keyof Theme['spaces'] | CSS.Property.Margin - mt: keyof Theme['spaces'] | CSS.Property.MarginTop - mr: keyof Theme['spaces'] | CSS.Property.MarginRight - mb: keyof Theme['spaces'] | CSS.Property.MarginBottom - ml: keyof Theme['spaces'] | CSS.Property.MarginLeft - my: keyof Theme['spaces'] | CSS.Property.Margin - mx: keyof Theme['spaces'] | CSS.Property.Margin - p: keyof Theme['spaces'] | CSS.Property.Padding - pt: keyof Theme['spaces'] | CSS.Property.PaddingTop - pr: keyof Theme['spaces'] | CSS.Property.PaddingRight - pb: keyof Theme['spaces'] | CSS.Property.PaddingBottom - pl: keyof Theme['spaces'] | CSS.Property.PaddingLeft - py: keyof Theme['spaces'] | CSS.Property.Padding - px: keyof Theme['spaces'] | CSS.Property.Padding + m: ThemeValues<'spaces'> | CSS.Property.Margin + mt: ThemeValues<'spaces'> | CSS.Property.MarginTop + mr: ThemeValues<'spaces'> | CSS.Property.MarginRight + mb: ThemeValues<'spaces'> | CSS.Property.MarginBottom + ml: ThemeValues<'spaces'> | CSS.Property.MarginLeft + my: ThemeValues<'spaces'> | CSS.Property.Margin + mx: ThemeValues<'spaces'> | CSS.Property.Margin + p: ThemeValues<'spaces'> | CSS.Property.Padding + pt: ThemeValues<'spaces'> | CSS.Property.PaddingTop + pr: ThemeValues<'spaces'> | CSS.Property.PaddingRight + pb: ThemeValues<'spaces'> | CSS.Property.PaddingBottom + pl: ThemeValues<'spaces'> | CSS.Property.PaddingLeft + py: ThemeValues<'spaces'> | CSS.Property.Padding + px: ThemeValues<'spaces'> | CSS.Property.Padding }> export const space = (props: SpaceProps & ThemeProp): CSSObject => { diff --git a/src/config/typography.ts b/src/config/typography.ts index bfe53b7..4c7987a 100644 --- a/src/config/typography.ts +++ b/src/config/typography.ts @@ -1,16 +1,15 @@ import type * as CSS from 'csstype' import type { CSSObject } from 'styled-components' -import type { Props, ThemeProp } from '../types' -import type { Theme } from '../theme' +import type { Props, ThemeProp, ThemeValues } from '../types' import { get } from '../utils' export type TypographyProps = Props<{ - fontFamily: keyof Theme['fonts'] | CSS.Property.FontFamily - fontSize: keyof Theme['fontSizes'] | CSS.Property.FontSize - fontWeight: keyof Theme['fontWeights'] | CSS.Property.FontWeight - lineHeight: keyof Theme['lineHeights'] | CSS.Property.LineHeight - letterSpacing: keyof Theme['letterSpacings'] | CSS.Property.LetterSpacing + fontFamily: ThemeValues<'fonts'> | CSS.Property.FontFamily + fontSize: ThemeValues<'fontSizes'> | CSS.Property.FontSize + fontWeight: ThemeValues<'fontWeights'> | CSS.Property.FontWeight + lineHeight: ThemeValues<'lineHeights'> | CSS.Property.LineHeight + letterSpacing: ThemeValues<'letterSpacings'> | CSS.Property.LetterSpacing textAlign: CSS.Property.TextAlign fontStyle: CSS.Property.FontStyle textDecoration: CSS.Property.TextDecoration diff --git a/src/theme.ts b/src/theme.ts index 87fc594..4aab0f2 100644 --- a/src/theme.ts +++ b/src/theme.ts @@ -1,3 +1,5 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ + export type ThemeKeys = | 'colors' | 'spaces' @@ -9,6 +11,18 @@ export type ThemeKeys = | 'letterSpacings' | 'borderWidths' | 'radii' + | (string & Record) -// eslint-disable-next-line @typescript-eslint/no-empty-interface -export interface Theme extends Partial>> {} +/** + * import 'jsx-to-styled' + * import { theme } from './index' + * + * type MyTheme = typeof theme + * + * declare module 'jsx-to-styled' { + * export interface Theme extends MyTheme {} + * } + */ +export interface Theme { + [key: string]: any +} diff --git a/src/types.ts b/src/types.ts index 18f1613..78189b4 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,9 +1,11 @@ -import type { Theme } from './theme' +import type { Theme, ThemeKeys } from './theme' type ExcludeNumbers = { - [Key in keyof T]: Exclude + [Key in keyof T]: Exclude } export type Props

= Partial> export type ThemeProp = Partial<{ theme: Theme }> + +export type ThemeValues = keyof Theme[Key] diff --git a/src/utils/index.ts b/src/utils/index.ts index 87d4cc9..9958af8 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -1,5 +1,5 @@ -import type { Theme, ThemeKeys } from '../theme' +import type { Theme } from '../theme' -export const get = (key: string, theme: Theme, scope: ThemeKeys): string => { - return theme?.[scope]?.[key as string] || key +export const get = (key: string, theme: T, scope: keyof T): string => { + return theme?.[scope]?.[key] || key } diff --git a/tsconfig.json b/tsconfig.json index bb36375..0f2f82d 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,7 +2,7 @@ "compilerOptions": { "outDir": "dist", "noImplicitAny": true, - "module": "es6", + "module": "esnext", "target": "es5", "jsx": "react", "allowJs": true,