Skip to content

Commit 3525f07

Browse files
authored
Merge pull request #662 from system-ui/typescript-spike
Spike out potential TypeScript conversion
2 parents 09a0b0a + 4513356 commit 3525f07

File tree

8 files changed

+274
-27
lines changed

8 files changed

+274
-27
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@ package-lock.json
44
node_modules
55
dist
66
coverage
7-
.DS_Store
7+
.DS_Store
8+
.rts2_cache*

babel.config.js

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
module.exports = {
2-
presets: ['@babel/env', '@babel/react'],
2+
presets: ['@babel/env', '@babel/react', '@babel/preset-typescript'],
33
env: {
44
test: {
5-
plugins: [
6-
'@babel/plugin-transform-runtime',
7-
],
5+
plugins: ['@babel/plugin-transform-runtime'],
86
},
97
},
108
}

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
"@babel/plugin-transform-runtime": "^7.7.6",
2323
"@babel/preset-env": "^7.4.5",
2424
"@babel/preset-react": "^7.0.0",
25+
"@babel/preset-typescript": "^7.8.3",
2526
"@babel/runtime": "^7.7.7",
2627
"@testing-library/react": "^9.1.3",
2728
"babel-jest": "^24.9.0",

packages/core/package.json

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
{
22
"name": "@theme-ui/core",
33
"version": "0.3.1",
4+
"source": "src/index.ts",
45
"main": "dist/index.js",
56
"module": "dist/index.esm.js",
7+
"types": "dist/index.d.ts",
68
"sideEffects": false,
79
"scripts": {
8-
"prepare": "microbundle --no-compress",
9-
"watch": "microbundle watch --no-compress"
10+
"prepare": "microbundle --no-compress --tsconfig tsconfig.json",
11+
"watch": "microbundle watch --no-compress --tsconfig tsconfig.json"
1012
},
1113
"repository": "system-ui/theme-ui",
1214
"author": "Brent Jackson",
@@ -23,6 +25,7 @@
2325
"react": "^16.11.0"
2426
},
2527
"devDependencies": {
28+
"@types/react": "^16.9.19",
2629
"react": "^16.11.0"
2730
}
2831
}

packages/core/src/index.js renamed to packages/core/src/index.ts

Lines changed: 31 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
import {
22
jsx as emotion,
33
ThemeContext as EmotionContext,
4+
InterpolationWithTheme,
45
} from '@emotion/core'
5-
import { css, get } from '@theme-ui/css'
6+
import { css } from '@theme-ui/css'
67
import React from 'react'
78
import deepmerge from 'deepmerge'
89
import { version as __EMOTION_VERSION__ } from '@emotion/core/package.json'
10+
import { Theme } from './theme'
911

1012
const getCSS = props => {
1113
if (!props.sx && !props.css) return undefined
@@ -18,7 +20,7 @@ const getCSS = props => {
1820

1921
const parseProps = props => {
2022
if (!props) return null
21-
const next = {}
23+
const next: typeof props & { css?: InterpolationWithTheme<any> } = {}
2224
for (let key in props) {
2325
if (key === 'sx') continue
2426
next[key] = props[key]
@@ -28,10 +30,14 @@ const parseProps = props => {
2830
return next
2931
}
3032

31-
export const jsx = (type, props, ...children) =>
33+
export const jsx: typeof React.createElement = (type, props, ...children) =>
3234
emotion.apply(undefined, [type, parseProps(props), ...children])
3335

34-
export const Context = React.createContext({
36+
export interface ContextValue {
37+
__EMOTION_VERSION__: string
38+
theme: Theme | null
39+
}
40+
export const Context = React.createContext<ContextValue>({
3541
__EMOTION_VERSION__,
3642
theme: null,
3743
})
@@ -54,24 +60,31 @@ const isMergeableObject = n => {
5460

5561
const arrayMerge = (destinationArray, sourceArray, options) => sourceArray
5662

57-
export const merge = (a, b) =>
63+
export const merge = <T>(a: Partial<T>, b: Partial<T>): T =>
5864
deepmerge(a, b, { isMergeableObject, arrayMerge })
5965

60-
merge.all = (...args) => deepmerge.all(args, { isMergeableObject, arrayMerge })
66+
merge.all = <T>(...args: Partial<T>[]) =>
67+
deepmerge.all<T>(args, { isMergeableObject, arrayMerge })
6168

62-
const BaseProvider = ({ context, children }) =>
69+
interface BaseProviderProps {
70+
context: ContextValue
71+
}
72+
const BaseProvider: React.FC<BaseProviderProps> = ({ context, children }) =>
6373
jsx(
64-
EmotionContext.Provider, { value: context.theme },
74+
EmotionContext.Provider,
75+
{ value: context.theme },
6576
jsx(Context.Provider, {
6677
value: context,
67-
children
78+
children,
6879
})
6980
)
7081

71-
export const ThemeProvider = ({
72-
theme,
73-
children
74-
}) => {
82+
export interface ThemeProviderProps {
83+
theme: Partial<Theme> | ((outerTheme: Theme) => Theme)
84+
children?: React.ReactNode
85+
}
86+
87+
export function ThemeProvider({ theme, children }: ThemeProviderProps) {
7588
const outer = useThemeUI()
7689

7790
if (process.env.NODE_ENV !== 'production') {
@@ -84,12 +97,10 @@ export const ThemeProvider = ({
8497
}
8598
}
8699

87-
const context = typeof theme === 'function'
88-
? { ...outer, theme: theme(outer.theme) }
89-
: merge.all({}, outer, { theme })
100+
const context =
101+
typeof theme === 'function'
102+
? { ...outer, theme: theme(outer.theme) }
103+
: merge.all<ContextValue>({}, outer, { theme })
90104

91-
return jsx(BaseProvider, {
92-
context,
93-
children
94-
})
105+
return jsx(BaseProvider, { context }, children)
95106
}

packages/core/src/theme.ts

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
import * as CSS from 'csstype'
2+
import { SystemStyleObject } from '@styled-system/css'
3+
import { Theme as StyledSystemTheme } from 'styled-system'
4+
5+
/**
6+
* The `sx` prop accepts a `SxStyleProp` object and properties that are part of
7+
* the `Theme` will be transformed to their corresponding values. Other valid
8+
* CSS properties are also allowed.
9+
*/
10+
export type SxStyleProp = SystemStyleObject
11+
12+
export interface SxProps {
13+
/**
14+
* The sx prop lets you style elements inline, using values from your
15+
* theme. To use the sx prop, add the custom pragma as a comment to the
16+
* top of your module and import the jsx function.
17+
*
18+
* ```ts
19+
* // @jsx jsx
20+
*
21+
* import { jsx } from 'theme-ui'
22+
* ```
23+
*/
24+
sx?: SxStyleProp
25+
}
26+
27+
export interface IntrinsicSxElements {
28+
p: JSX.IntrinsicElements['p'] & SxProps
29+
b: JSX.IntrinsicElements['b'] & SxProps
30+
i: JSX.IntrinsicElements['i'] & SxProps
31+
a: JSX.IntrinsicElements['a'] & SxProps
32+
h1: JSX.IntrinsicElements['h1'] & SxProps
33+
h2: JSX.IntrinsicElements['h2'] & SxProps
34+
h3: JSX.IntrinsicElements['h3'] & SxProps
35+
h4: JSX.IntrinsicElements['h4'] & SxProps
36+
h5: JSX.IntrinsicElements['h5'] & SxProps
37+
h6: JSX.IntrinsicElements['h6'] & SxProps
38+
img: JSX.IntrinsicElements['img'] & SxProps
39+
pre: JSX.IntrinsicElements['pre'] & SxProps
40+
code: JSX.IntrinsicElements['code'] & SxProps
41+
ol: JSX.IntrinsicElements['ol'] & SxProps
42+
ul: JSX.IntrinsicElements['ul'] & SxProps
43+
li: JSX.IntrinsicElements['li'] & SxProps
44+
blockquote: JSX.IntrinsicElements['blockquote'] & SxProps
45+
hr: JSX.IntrinsicElements['hr'] & SxProps
46+
table: JSX.IntrinsicElements['table'] & SxProps
47+
tr: JSX.IntrinsicElements['tr'] & SxProps
48+
th: JSX.IntrinsicElements['th'] & SxProps
49+
td: JSX.IntrinsicElements['td'] & SxProps
50+
em: JSX.IntrinsicElements['em'] & SxProps
51+
strong: JSX.IntrinsicElements['strong'] & SxProps
52+
div: JSX.IntrinsicElements['div'] & SxProps
53+
delete: JSX.IntrinsicElements['div'] & SxProps
54+
inlineCode: JSX.IntrinsicElements['div'] & SxProps
55+
thematicBreak: JSX.IntrinsicElements['div'] & SxProps
56+
root: JSX.IntrinsicElements['div'] & SxProps
57+
}
58+
type ObjectOrArray<T> = T[] | { [K: string]: T | ObjectOrArray<T> }
59+
type StyledTags = keyof IntrinsicSxElements
60+
61+
/**
62+
* To use Theme UI color modes, color scales should include at least a text
63+
* and background color. These values are used in the ColorMode component to
64+
* set body foreground and background colors. Color modes should be defined as
65+
* nested objects within a theme.colors.modes object. Each key in this object
66+
* should correspond to a color mode name, where the name can be anything, but
67+
* typically light and dark are used for applications with a dark mode. The
68+
* initialColorModeName key is required to enable color modes and will be used as
69+
* the name for the root color palette.
70+
*/
71+
export type ColorMode = {
72+
[k: string]: CSS.ColorProperty | ObjectOrArray<CSS.ColorProperty>
73+
} & {
74+
/**
75+
* Body background color
76+
*/
77+
background: CSS.ColorProperty
78+
79+
/**
80+
* Body foreground color
81+
*/
82+
text: CSS.ColorProperty
83+
84+
/**
85+
* Primary brand color for links, buttons, etc.
86+
*/
87+
primary?: CSS.ColorProperty
88+
89+
/**
90+
* A secondary brand color for alternative styling
91+
*/
92+
secondary?: CSS.ColorProperty
93+
94+
/**
95+
* A faint color for backgrounds, borders, and accents that do not require
96+
* high contrast with the background color
97+
*/
98+
muted?: CSS.ColorProperty
99+
100+
/**
101+
* A contrast color for emphasizing UI
102+
*/
103+
accent?: CSS.ColorProperty
104+
}
105+
106+
export interface Theme extends Omit<StyledSystemTheme, 'colors'> {
107+
/**
108+
* Enable/disable custom CSS properties/variables if lower browser
109+
* support is required (for eg. IE 11).
110+
*
111+
* References: https://theme-ui.com/color-modes/#turn-off-custom-properties
112+
*/
113+
useCustomProperties?: boolean
114+
115+
/**
116+
* Provide a value here to enable color modes
117+
*/
118+
initialColorModeName?: string
119+
120+
/**
121+
* Adds styles defined in theme.styles.root to the <body> element along with color and background-color
122+
*/
123+
useBodyStyles?: boolean
124+
125+
/**
126+
* Initializes the color mode based on the prefers-color-scheme media query
127+
*/
128+
useColorSchemeMediaQuery?: boolean
129+
130+
/**
131+
* Adds a global box-sizing: border-box style
132+
*/
133+
useBoxSizing?: boolean
134+
135+
/**
136+
* Define the colors that are available through this theme
137+
*/
138+
colors?: ColorMode & {
139+
/**
140+
* Nested color modes can provide overrides when used in conjunction with
141+
* `Theme.initialColorModeName and `useColorMode()`
142+
*/
143+
modes?: {
144+
[k: string]: ColorMode
145+
}
146+
}
147+
148+
/**
149+
* Styles for elements rendered in MDX can be added to the theme.styles
150+
* object. This is the primary, low-level way to control typographic and
151+
* other styles in markdown content. Styles within this object are processed
152+
* with @styled-system/css and have access to base theme values like colors,
153+
* fonts, etc.
154+
*/
155+
styles?: {
156+
[P in StyledTags]?: SystemStyleObject
157+
}
158+
}

packages/core/tsconfig.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"compilerOptions": {
3+
"resolveJsonModule": true,
4+
"esModuleInterop": true,
5+
"moduleResolution": "node"
6+
}
7+
}

0 commit comments

Comments
 (0)