Skip to content

Commit

Permalink
Convert @emotion/react's source code to TypeScript (#3281)
Browse files Browse the repository at this point in the history
* Convert `@emotion/react`'s source code to TypeScript

* add changeset

* limit `package.json['files']`

* fixed type issue

* try `esModuleInterop`

* add required cast

* use `resolveJsonModule` too

* fixed extra things

* fixed a silly mistake

* one extra thing

* fixed type error

* try building before running dtslint

* fixed import

* try to bump tested TS versions

* add extra ts-ignore

* make sure the ts-ignore is above the problematic line

* rewrite tests to stop relying on implementation detail

* fixed type error

* corrext tests

* fixed entrypoints types
  • Loading branch information
Andarist authored Dec 5, 2024
1 parent 8dc1a6d commit fc4d7bd
Show file tree
Hide file tree
Showing 59 changed files with 582 additions and 585 deletions.
5 changes: 5 additions & 0 deletions .changeset/rotten-baboons-knock.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@emotion/react': minor
---

Source code has been migrated to TypeScript. From now on type declarations will be emitted based on that, instead of being hand-written.
3 changes: 3 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -88,5 +88,8 @@ jobs:
- uses: actions/checkout@v3
- uses: ./.github/actions/ci-setup

- name: build
run: yarn build

- name: dtslint
run: yarn test:typescript
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@
"@testing-library/react": "13.0.0-alpha.5",
"@types/jest": "^29.5.12",
"@types/node": "^12.20.37",
"@types/react": "18.2.6",
"@types/react": "18.3.12",
"@typescript-eslint/eslint-plugin": "^7.13.0",
"@typescript-eslint/parser": "^7.13.0",
"babel-check-duplicated-nodes": "^1.0.0",
Expand Down
2 changes: 1 addition & 1 deletion packages/cache/types/index.d.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export * from '../src'
export * from '..'
2 changes: 0 additions & 2 deletions packages/css/test/no-babel/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import styled from '@emotion/styled'
let consoleError = console.error

afterEach(() => {
// $FlowFixMe
console.error = consoleError
})

Expand Down Expand Up @@ -146,7 +145,6 @@ describe('css', () => {
})

const spy = jest.fn()
// $FlowFixMe
console.error = spy

expect(() =>
Expand Down
2 changes: 0 additions & 2 deletions packages/css/test/sheet.dom.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { sheet } from '@emotion/css'
const consoleError = console.error

afterEach(() => {
// $FlowFixMe
console.error = consoleError
})

Expand Down Expand Up @@ -38,7 +37,6 @@ describe('sheet', () => {
test('throws', () => {
sheet.speedy(true)
const spy = jest.fn()
// $FlowFixMe
console.error = spy
sheet.insert('.asdfasdf4###112121211{')
expect(spy.mock.calls.length).toBe(1)
Expand Down
2 changes: 1 addition & 1 deletion packages/native/types/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Definitions by: Pat Sissons <https://github.com/patsissons>
// TypeScript Version: 3.4
// TypeScript Version: 4.1

import * as RN from 'react-native'
import { Theme } from '@emotion/react'
Expand Down
2 changes: 2 additions & 0 deletions packages/native/types/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
"jsx": "react",
"lib": ["es6", "dom"],
"module": "commonjs",
"esModuleInterop": true,
"resolveJsonModule": true,
"noEmit": true,
"strict": true,
"target": "es5",
Expand Down
3 changes: 2 additions & 1 deletion packages/primitives-core/src/styled.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ export function createStyled(

// do we really want to use the same infra as the web since it only really uses theming?
let Styled = React.forwardRef<unknown, StyledProps>((props, ref) => {
const finalTag = (shouldUseAs && props.as) || component
const finalTag =
(shouldUseAs && (props.as as React.ElementType)) || component

let mergedProps = props
if (props.theme == null) {
Expand Down
4 changes: 0 additions & 4 deletions packages/react/__tests__/element.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
// @flow
/** @jsx jsx */
import { render } from '@testing-library/react'
import { jsx, css, CacheProvider, ThemeProvider } from '@emotion/react'
import createCache from '@emotion/cache'

// $FlowFixMe
console.error = jest.fn()

beforeEach(() => {
// $FlowFixMe
document.head.innerHTML = ''
jest.clearAllMocks()
})
Expand All @@ -18,7 +15,6 @@ describe('EmotionElement', () => {
const theme = { color: 'blue' }
const cache = createCache({ key: 'context' })

// $FlowFixMe
const Comp = ({ flag }) => (
<ThemeProvider theme={theme}>
<CacheProvider value={cache}>
Expand Down
1 change: 0 additions & 1 deletion packages/react/__tests__/get-label-from-stack-trace.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
// @flow
import { getLabelFromStackTrace } from '../src/get-label-from-stack-trace'

/**
Expand Down
1 change: 0 additions & 1 deletion packages/react/__tests__/global.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import {
} from '@emotion/react'
import createCache from '@emotion/cache'

// $FlowFixMe
console.error = jest.fn()

beforeEach(() => {
Expand Down
1 change: 0 additions & 1 deletion packages/react/__tests__/import-prod.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ expect.addSnapshotSerializer({
const render = children =>
new Promise(resolve => {
const el = document.createElement('div')
// $FlowFixMe
document.body.appendChild(el)

if (ReactDOM.createRoot) {
Expand Down
1 change: 0 additions & 1 deletion packages/react/__tests__/theme-provider.dom.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import * as React from 'react'
import { jsx, ThemeProvider } from '@emotion/react'

beforeEach(() => {
// $FlowFixMe
document.head.innerHTML = ''
})

Expand Down
1 change: 1 addition & 0 deletions packages/react/_isolated-hnrs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"main": "dist/emotion-react-_isolated-hnrs.cjs.js",
"module": "dist/emotion-react-_isolated-hnrs.esm.js",
"umd:main": "dist/emotion-react-_isolated-hnrs.umd.min.js",
"types": "dist/emotion-react-_isolated-hnrs.cjs.d.ts",
"sideEffects": false,
"preconstruct": {
"umdName": "emotionHoistNonReactStatics"
Expand Down
2 changes: 1 addition & 1 deletion packages/react/jsx-dev-runtime/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"main": "dist/emotion-react-jsx-dev-runtime.cjs.js",
"module": "dist/emotion-react-jsx-dev-runtime.esm.js",
"umd:main": "dist/emotion-react-jsx-dev-runtime.umd.min.js",
"types": "../types/jsx-dev-runtime",
"types": "dist/emotion-react-jsx-dev-runtime.cjs.d.ts",
"sideEffects": false,
"preconstruct": {
"umdName": "emotionReactJSXDevRuntime"
Expand Down
2 changes: 1 addition & 1 deletion packages/react/jsx-runtime/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"main": "dist/emotion-react-jsx-runtime.cjs.js",
"module": "dist/emotion-react-jsx-runtime.esm.js",
"umd:main": "dist/emotion-react-jsx-runtime.umd.min.js",
"types": "../types/jsx-runtime",
"types": "dist/emotion-react-jsx-runtime.cjs.d.ts",
"sideEffects": false,
"preconstruct": {
"umdName": "emotionReactJSXRuntime"
Expand Down
27 changes: 14 additions & 13 deletions packages/react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"version": "11.13.5",
"main": "dist/emotion-react.cjs.js",
"module": "dist/emotion-react.esm.js",
"types": "dist/emotion-react.cjs.d.ts",
"exports": {
".": {
"types": {
Expand Down Expand Up @@ -232,25 +233,24 @@
},
"imports": {
"#is-development": {
"development": "./src/conditions/true.js",
"default": "./src/conditions/false.js"
"development": "./src/conditions/true.ts",
"default": "./src/conditions/false.ts"
},
"#is-browser": {
"edge-light": "./src/conditions/false.js",
"workerd": "./src/conditions/false.js",
"worker": "./src/conditions/false.js",
"browser": "./src/conditions/true.js",
"default": "./src/conditions/is-browser.js"
"edge-light": "./src/conditions/false.ts",
"workerd": "./src/conditions/false.ts",
"worker": "./src/conditions/false.ts",
"browser": "./src/conditions/true.ts",
"default": "./src/conditions/is-browser.ts"
}
},
"types": "types/index.d.ts",
"files": [
"src",
"dist",
"jsx-runtime",
"jsx-dev-runtime",
"_isolated-hnrs",
"types/*.d.ts",
"types/css-prop.d.ts",
"macro.*"
],
"sideEffects": false,
Expand Down Expand Up @@ -283,6 +283,7 @@
"@emotion/css-prettifier": "1.1.4",
"@emotion/server": "11.11.0",
"@emotion/styled": "11.13.5",
"@types/hoist-non-react-statics": "^3.3.5",
"html-tag-names": "^1.1.2",
"react": "16.14.0",
"svg-tag-names": "^1.1.1",
Expand All @@ -295,10 +296,10 @@
"umd:main": "dist/emotion-react.umd.min.js",
"preconstruct": {
"entrypoints": [
"./index.js",
"./jsx-runtime.js",
"./jsx-dev-runtime.js",
"./_isolated-hnrs.js"
"./index.ts",
"./jsx-runtime.ts",
"./jsx-dev-runtime.ts",
"./_isolated-hnrs.ts"
],
"umdName": "emotionReact",
"exports": {
Expand Down
3 changes: 0 additions & 3 deletions packages/react/src/_isolated-hnrs.d.ts

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,10 @@ import hoistNonReactStatics from 'hoist-non-react-statics'
// have to wrap it in a proxy function because Rollup is too damn smart
// and if this module doesn't actually contain any logic of its own
// then Rollup just use 'hoist-non-react-statics' directly in other chunks
export default (targetComponent, sourceComponent) =>
hoistNonReactStatics(targetComponent, sourceComponent)
export default <
T extends React.ComponentType<any>,
S extends React.ComponentType<any>
>(
targetComponent: T,
sourceComponent: S
) => hoistNonReactStatics(targetComponent, sourceComponent)
Original file line number Diff line number Diff line change
@@ -1,27 +1,29 @@
import * as React from 'react'
import {
EmotionCache,
getRegisteredStyles,
insertStyles,
registerStyles
registerStyles,
SerializedStyles
} from '@emotion/utils'
import { serializeStyles } from '@emotion/serialize'
import { CSSInterpolation, serializeStyles } from '@emotion/serialize'
import isDevelopment from '#is-development'
import { withEmotionCache } from './context'
import { ThemeContext } from './theming'
import { Theme, ThemeContext } from './theming'
import { useInsertionEffectAlwaysWithSyncFallback } from '@emotion/use-insertion-effect-with-fallbacks'
import isBrowser from '#is-browser'

/*
type ClassNameArg =
export interface ArrayClassNamesArg extends Array<ClassNamesArg> {}

export type ClassNamesArg =
| undefined
| null
| string
| boolean
| { [key: string]: boolean }
| Array<ClassNameArg>
| null
| void
*/
| { [className: string]: boolean | null | undefined }
| ArrayClassNamesArg

let classnames = (args /*: Array<ClassNameArg> */) /*: string */ => {
let classnames = (args: ArrayClassNamesArg): string => {
let len = args.length
let i = 0
let cls = ''
Expand Down Expand Up @@ -69,11 +71,11 @@ let classnames = (args /*: Array<ClassNameArg> */) /*: string */ => {
return cls
}
function merge(
registered /*: Object */,
css /*: (...args: Array<any>) => string */,
className /*: string */
registered: EmotionCache['registered'],
css: ClassNamesContent['css'],
className: string
) {
const registeredStyles = []
const registeredStyles: string[] = []

const rawClassName = getRegisteredStyles(
registered,
Expand All @@ -87,7 +89,13 @@ function merge(
return rawClassName + css(registeredStyles)
}

const Insertion = ({ cache, serializedArr }) => {
const Insertion = ({
cache,
serializedArr
}: {
cache: EmotionCache
serializedArr: SerializedStyles[]
}) => {
let rules = useInsertionEffectAlwaysWithSyncFallback(() => {
let rules = ''
for (let i = 0; i < serializedArr.length; i++) {
Expand All @@ -101,14 +109,14 @@ const Insertion = ({ cache, serializedArr }) => {
}
})

if (!isBrowser && rules.length !== 0) {
if (!isBrowser && rules!.length !== 0) {
return (
<style
{...{
[`data-emotion`]: `${cache.key} ${serializedArr
.map(serialized => serialized.name)
.join(' ')}`,
dangerouslySetInnerHTML: { __html: rules },
dangerouslySetInnerHTML: { __html: rules! },
nonce: cache.sheet.nonce
}}
/>
Expand All @@ -117,21 +125,23 @@ const Insertion = ({ cache, serializedArr }) => {
return null
}

/*
type Props = {
children: ({
css: (...args: any) => string,
cx: (...args: Array<ClassNameArg>) => string,
theme: Object
}) => React.Node
} */
export interface ClassNamesContent {
css(template: TemplateStringsArray, ...args: Array<CSSInterpolation>): string
css(...args: Array<CSSInterpolation>): string
cx(...args: Array<ClassNamesArg>): string
theme: Theme
}

export interface ClassNamesProps {
children(content: ClassNamesContent): React.ReactNode
}

export const ClassNames /*: React.AbstractComponent<Props>*/ =
/* #__PURE__ */ withEmotionCache((props, cache) => {
export const ClassNames = /* #__PURE__ */ withEmotionCache<ClassNamesProps>(
(props, cache) => {
let hasRendered = false
let serializedArr = []
let serializedArr: SerializedStyles[] = []

let css = (...args /*: Array<any> */) => {
let css: ClassNamesContent['css'] = (...args) => {
if (hasRendered && isDevelopment) {
throw new Error('css can only be used during render')
}
Expand All @@ -142,7 +152,7 @@ export const ClassNames /*: React.AbstractComponent<Props>*/ =
registerStyles(cache, serialized, false)
return `${cache.key}-${serialized.name}`
}
let cx = (...args /*: Array<ClassNameArg>*/) => {
let cx = (...args: Array<ClassNamesArg>) => {
if (hasRendered && isDevelopment) {
throw new Error('cx can only be used during render')
}
Expand All @@ -162,7 +172,8 @@ export const ClassNames /*: React.AbstractComponent<Props>*/ =
{ele}
</>
)
})
}
)

if (isDevelopment) {
ClassNames.displayName = 'EmotionClassNames'
Expand Down
File renamed without changes.
File renamed without changes.
Loading

0 comments on commit fc4d7bd

Please sign in to comment.