Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Convert @emotion/primitives-core to TypeScript #2818

Merged
merged 5 commits into from
Jul 31, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/primitives-core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
},
"devDependencies": {
"@emotion/react": "11.9.3",
"@types/css-to-react-native": "^3.0.0",
srmagura marked this conversation as resolved.
Show resolved Hide resolved
"react": "16.14.0"
},
"homepage": "https://emotion.sh",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
import transform from 'css-to-react-native'
import transform, { Style } from 'css-to-react-native'
import { AbstractStyleSheet } from './types'
import { interleave } from './utils'

// this is for handleInterpolation
// they're reset on every call to css
// this is done so we don't create a new
// handleInterpolation function on every css call
let styles
let generated = {}
let styles: unknown[] | undefined
let generated: Record<string, unknown> = {}
let buffer = ''
let lastType
let lastType: string | undefined

function handleInterpolation(
interpolation,
i /*: number */,
arr /*: Array<*> */
this: unknown,
interpolation: any,
i: number,
arr: any[]
) {
let type = typeof interpolation

Expand Down Expand Up @@ -44,7 +46,7 @@ function handleInterpolation(
if (lastType === 'string' && (isRnStyle || isIrrelevant)) {
let converted = convertStyles(buffer)
if (converted !== undefined) {
styles.push(converted)
styles!.push(converted)
}
buffer = ''
}
Expand All @@ -58,13 +60,13 @@ function handleInterpolation(
if (arr.length - 1 === i) {
let converted = convertStyles(buffer)
if (converted !== undefined) {
styles.push(converted)
styles!.push(converted)
}
buffer = ''
}
}
if (isRnStyle) {
styles.push(interpolation)
styles!.push(interpolation)
}
if (Array.isArray(interpolation)) {
interpolation.forEach(handleInterpolation, this)
Expand All @@ -74,10 +76,10 @@ function handleInterpolation(

// Use platform specific StyleSheet method for creating the styles.
// This enables us to use the css``/css({}) in any environment (Native | Sketch | Web)
export function createCss(StyleSheet /*: Object */) {
return function css(...args) {
export function createCss(StyleSheet: AbstractStyleSheet) {
return function css(this: unknown, ...args: any[]) {
const prevBuffer = buffer
let vals
let vals: any[]

// these are declared earlier
// this is done so we don't create a new
Expand All @@ -89,7 +91,7 @@ export function createCss(StyleSheet /*: Object */) {
if (args[0] == null || args[0].raw === undefined) {
vals = args
} else {
vals = interleave(args)
vals = interleave(args as [any, ...any[]])
}

try {
Expand All @@ -111,7 +113,7 @@ export function createCss(StyleSheet /*: Object */) {

let propertyValuePattern = /\s*([^\s]+)\s*:\s*(.+?)\s*$/

function convertPropertyValue(style) {
function convertPropertyValue(this: [string, string][], style: string): void {
// Get prop name and prop value
let match = propertyValuePattern.exec(style)
// match[2] will be " " in cases where there is no value
Expand All @@ -121,14 +123,14 @@ function convertPropertyValue(style) {
// be the whole string so we remove it
match.shift()
// yes i know this looks funny
this.push(match)
this.push(match as unknown as [string, string])
}
}

function convertStyles(str /*: string */) {
function convertStyles(str: string): Style | undefined {
if (str.trim() === '') return

const stylePairs = []
const stylePairs: [string, string][] = []

const parsedString = str.split(';')

Expand All @@ -137,9 +139,9 @@ function convertStyles(str /*: string */) {
try {
return transform(stylePairs)
} catch (error) {
const msg = error.message
const msg = (error as { message?: string } | undefined)?.message

if (msg.includes('Failed to parse declaration')) {
if (msg && msg.includes('Failed to parse declaration')) {
const values = msg
.replace('Failed to parse declaration ', '')
.replace(/"/g, '')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,35 @@ import * as React from 'react'
import { interleave } from './utils'
import { ThemeContext } from '@emotion/react'
import { createCss } from './css'
import { AbstractStyleSheet } from './types'

let testOmitPropsOnComponent = prop => prop !== 'theme' && prop !== 'as'
let testOmitPropsOnComponent = (prop: string) =>
prop !== 'theme' && prop !== 'as'

/*
type CreateStyledOptions = {
getShouldForwardProp: (cmp: React.ElementType) => (prop: string) => boolean
interface CreateStyledOptions {
getShouldForwardProp(cmp: React.ElementType): (prop: string) => boolean
}

type StyledOptions = {
shouldForwardProp?: (prop: string) => boolean
interface StyledOptions {
shouldForwardProp?(prop: string): boolean
}

type StyledProps = Record<string, unknown> & {
as?: React.ElementType
}
*/

export function createStyled(
StyleSheet /*: Object */,
{
getShouldForwardProp = () => testOmitPropsOnComponent
} /*: CreateStyledOptions */ = {}
StyleSheet: AbstractStyleSheet,
options?: CreateStyledOptions
) {
const getShouldForwardProp =
options?.getShouldForwardProp ?? (() => testOmitPropsOnComponent)

const css = createCss(StyleSheet)

return function createEmotion(
component /*: React.ElementType */,
options /* ?: StyledOptions */
component: React.ElementType,
options?: StyledOptions
) {
let shouldForwardProp =
options && options.shouldForwardProp
Expand All @@ -35,17 +40,17 @@ export function createStyled(
shouldForwardProp || getShouldForwardProp(component)
let shouldUseAs = !defaultShouldForwardProp('as')

return function createStyledComponent(...rawStyles) {
let styles
return function createStyledComponent(...rawStyles: any[]) {
let styles: any[]

if (rawStyles[0] == null || rawStyles[0].raw === undefined) {
styles = rawStyles
} else {
styles = interleave(rawStyles)
styles = interleave(rawStyles as [any, ...any[]])
}

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

let mergedProps = props
Expand All @@ -62,7 +67,7 @@ export function createStyled(
? getShouldForwardProp(finalTag)
: defaultShouldForwardProp

let newProps = {}
let newProps: Record<string, unknown> = {}

for (let key in props) {
if (shouldUseAs && key === 'as') continue
Expand All @@ -77,17 +82,26 @@ export function createStyled(

return React.createElement(finalTag, newProps)
})
Styled.withComponent = (newComponent /*: React.ElementType */) =>
createEmotion(newComponent)(...styles)

Styled.displayName = `emotion(${getDisplayName(component)})`

return Styled
const withComponent = (newComponent: React.ElementType) =>
createEmotion(newComponent)(...styles)

const castedStyled = Styled as typeof Styled & {
withComponent: typeof withComponent
}

castedStyled.withComponent = withComponent

return castedStyled
}
}
}

const getDisplayName = primitive =>
const getDisplayName = (
primitive: string | { displayName?: string; name?: string }
) =>
typeof primitive === 'string'
? primitive
: primitive.displayName || primitive.name || 'Styled'
10 changes: 10 additions & 0 deletions packages/primitives-core/src/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
type NamedStyles<T> = { [P in keyof T]: unknown }

// This is based on the StyleSheet type from @types/react-native
export interface AbstractStyleSheet {
create<T extends NamedStyles<T> | NamedStyles<any>>(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, it's an interesting constraint. I can't say that I fully understand why it is written like this. I guess this will be OK or we'll just learn that it's not when converting @emotion/native and stuff 🤷‍♂️

styles: T | NamedStyles<T>
): T

flatten(style?: unknown[]): unknown
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
export function interleave(vals /*: Array */) {
export function interleave(
vals: [TemplateStringsArray, ...unknown[]]
): unknown[] {
let strings = vals[0]
let finalArray = [strings[0]]
let finalArray: unknown[] = [strings[0]]
for (let i = 1, len = vals.length; i < len; i++) {
finalArray.push(vals[i])
if (strings[i] !== undefined) {
Expand Down
18 changes: 14 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -5880,6 +5880,11 @@
resolved "https://registry.yarnpkg.com/@types/cors/-/cors-2.8.10.tgz#61cc8469849e5bcdd0c7044122265c39cec10cf4"
integrity sha512-C7srjHiVG3Ey1nR6d511dtDkCEjxuN9W1HWAEjGq8kpcwmNM6JJkpC0xvabM7BXTG2wDq8Eu33iH9aQKa7IvLQ==

"@types/css-to-react-native@^3.0.0":
version "3.0.0"
resolved "https://registry.yarnpkg.com/@types/css-to-react-native/-/css-to-react-native-3.0.0.tgz#63831e79c3855f78981217c745fb4bd7c8733d05"
integrity sha512-MjLLf4YKMQYKnZ7xPZisizAiC8C5EQUKSLeimtApbc82WJDDN0TQBCY+HhWJHsSQ8Le4509aD/O7MWV73jJykQ==

"@types/debug@^0.0.30":
version "0.0.30"
resolved "https://registry.yarnpkg.com/@types/debug/-/debug-0.0.30.tgz#dc1e40f7af3b9c815013a7860e6252f6352a84df"
Expand Down Expand Up @@ -9168,11 +9173,16 @@ caniuse-api@^3.0.0:
lodash.memoize "^4.1.2"
lodash.uniq "^4.5.0"

caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000844, caniuse-lite@^1.0.30000981, caniuse-lite@^1.0.30001010:
caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000981, caniuse-lite@^1.0.30001010:
version "1.0.30001012"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001012.tgz#653ec635e815b9e0fb801890923b0c2079eb34ec"
integrity sha512-7RR4Uh04t9K1uYRWzOJmzplgEOAXbfK72oVNokCdMzA67trrhPzy93ahKk1AWHiA0c58tD2P+NHqxrA8FZ+Trg==

caniuse-lite@^1.0.30000844:
version "1.0.30001373"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001373.tgz#2dc3bc3bfcb5d5a929bec11300883040d7b4b4be"
integrity sha512-pJYArGHrPp3TUqQzFYRmP/lwJlj8RCbVe3Gd3eJQkAV8SAC6b19XS9BjMvRdvaS8RMkaTN8ZhoHP6S1y8zzwEQ==

caniuse-lite@^1.0.30001109:
version "1.0.30001204"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001204.tgz#256c85709a348ec4d175e847a3b515c66e79f2aa"
Expand Down Expand Up @@ -11874,9 +11884,9 @@ ejs@^3.1.6:
jake "^10.6.1"

electron-to-chromium@^1.3.47:
version "1.3.212"
resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.212.tgz#15d81ba96edb8ae6f937cde0fdb18c1c3c2bfec5"
integrity sha512-H8z5Smi1s1u1zGegEBfbxUAzrxyk1JoRHHHrlNGfhxv3sTb+p/Jz7JDvrR4196Q/Ip8r4+XwWcLvKrUjFKoJAg==
version "1.4.206"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.206.tgz#580ff85b54d7ec0c05f20b1e37ea0becdd7b0ee4"
integrity sha512-h+Fadt1gIaQ06JaIiyqPsBjJ08fV5Q7md+V8bUvQW/9OvXfL2LRICTz2EcnnCP7QzrFTS6/27MRV6Bl9Yn97zA==

elegant-spinner@^1.0.1:
version "1.0.1"
Expand Down