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

Throw a nice error when using the styled shorthand without babel-plugin-emotion and remove duplication in component selector code #516

Merged
merged 4 commits into from
Jan 4, 2018
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
15 changes: 12 additions & 3 deletions packages/create-emotion-styled/src/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// @flow
import { STYLES_KEY, TARGET_KEY } from 'emotion-utils'
import { STYLES_KEY } from 'emotion-utils'
import type { Emotion, Interpolations } from 'create-emotion'
import { channel, contextTypes } from '../../emotion-theming/src/utils'
import type { ElementType } from 'react'
Expand All @@ -14,7 +14,7 @@ import {
} from './utils'

function createEmotionStyled(emotion: Emotion, view: ReactType) {
const createStyled: CreateStyled = (tag, options) => {
let createStyled: CreateStyled = (tag, options) => {
if (process.env.NODE_ENV !== 'production') {
if (tag === undefined) {
throw new Error(
Expand Down Expand Up @@ -133,7 +133,6 @@ function createEmotionStyled(emotion: Emotion, view: ReactType) {
Styled[STYLES_KEY] = styles
Styled.__emotion_base = baseTag
Styled.__emotion_real = Styled
Styled[TARGET_KEY] = stableClassName
Object.defineProperty(Styled, 'toString', {
enumerable: false,
value() {
Expand Down Expand Up @@ -165,6 +164,16 @@ function createEmotionStyled(emotion: Emotion, view: ReactType) {
return Styled
}
}
if (process.env.NODE_ENV !== 'production' && typeof Proxy !== 'undefined') {
createStyled = new Proxy(createStyled, {
Copy link
Member

Choose a reason for hiding this comment

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

Very cool! Great idea.

get(target, property) {
throw new Error(
`You're trying to use the styled shorthand without babel-plugin-emotion.` +
`\nPlease install and setup babel-plugin-emotion or use the function call syntax(\`styled('${property}')\` instead of \`styled.${property}\`)`
)
}
})
}
return createStyled
}

Expand Down
13 changes: 2 additions & 11 deletions packages/create-emotion/src/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// @flow
import { hashString, Stylis, STYLES_KEY, TARGET_KEY } from 'emotion-utils'
import { hashString, Stylis, STYLES_KEY } from 'emotion-utils'
import stylisRuleSheet from 'stylis-rule-sheet'
import {
processStyleName,
Expand Down Expand Up @@ -132,16 +132,7 @@ function createEmotion(
return ''
case 'function':
if (interpolation[STYLES_KEY] !== undefined) {
if (
process.env.NODE_ENV !== 'production' &&
interpolation[TARGET_KEY] === undefined
) {
throw new Error(
'Component selectors can only be used in conjunction with babel-plugin-emotion.'
)
}

return `.${interpolation[TARGET_KEY]}`
return interpolation.toString()
}
return handleInterpolation.call(
this,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -766,12 +766,6 @@ exports[`styled with higher order component that hoists statics 1`] = `
/>
`;

exports[`styled withComponent creates a new, unique stable class per invocation 1`] = `"e1x6erbc54"`;

exports[`styled withComponent creates a new, unique stable class per invocation 2`] = `"e1x6erbc55"`;

exports[`styled withComponent creates a new, unique stable class per invocation 3`] = `"e1x6erbc56"`;

exports[`styled withComponent will replace tags but keep styling classes 1`] = `
.emotion-0 {
color: green;
Expand Down
11 changes: 3 additions & 8 deletions packages/create-emotion/test/styled.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import * as emotion from './emotion-instance'
import { createSerializer } from 'jest-emotion'
import { ThemeProvider } from 'emotion-theming'
import hoistNonReactStatics from 'hoist-non-react-statics'
import { TARGET_KEY } from 'emotion-utils'
import { mount } from 'enzyme'
import enzymeToJson from 'enzyme-to-json'

Expand Down Expand Up @@ -1070,13 +1069,9 @@ describe('styled', () => {
const Subtitle = Title.withComponent('h2')
const Byline = Title.withComponent('span')

expect(Subtitle[TARGET_KEY]).not.toBe(Title[TARGET_KEY])
expect(Byline[TARGET_KEY]).not.toBe(Title[TARGET_KEY])
expect(Byline[TARGET_KEY]).not.toBe(Subtitle[TARGET_KEY])

expect(Title[TARGET_KEY]).toMatchSnapshot()
expect(Subtitle[TARGET_KEY]).toMatchSnapshot()
expect(Byline[TARGET_KEY]).toMatchSnapshot()
expect(Subtitle.toString()).not.toBe(Title.toString())
expect(Byline.toString()).not.toBe(Title.toString())
expect(Byline.toString()).not.toBe(Subtitle.toString())
})
test('name with class component', () => {
class SomeComponent extends React.Component<{ className: string }> {
Expand Down
1 change: 0 additions & 1 deletion packages/emotion-utils/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ export const memoize = (fn: string => any) => {
}

export const STYLES_KEY = '__emotion_styles'
export const TARGET_KEY = '__emotion_target'

export const unitless: { [string]: 1 } = {
animationIterationCount: 1,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,3 @@ exports[`component selector should be converted to use the emotion target classN
color: blue;
}"
`;

exports[`component selector should throw if the missing the static targeting property 1`] = `"Component selectors can only be used in conjunction with babel-plugin-emotion."`;
17 changes: 0 additions & 17 deletions packages/emotion/test/component-selector.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import React from 'react'
import styled from 'react-emotion'
import renderer from 'react-test-renderer'
import { css, flush, sheet } from 'emotion'
import { TARGET_KEY } from 'emotion-utils'

describe('component selector', () => {
afterEach(() => flush())
Expand All @@ -27,20 +26,4 @@ describe('component selector', () => {
expect(tree).toMatchSnapshot()
expect(sheet).toMatchSnapshot()
})

test('should throw if the missing the static targeting property', () => {
const FakeComponent = styled.div`
color: blue;
`

delete FakeComponent[TARGET_KEY]

expect(() => {
css`
${FakeComponent} {
color: red;
}
`
}).toThrowErrorMatchingSnapshot()
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ exports[`css @supports 1`] = `

exports[`css component as selectors (object syntax) 1`] = `"Component selectors can only be used in conjunction with babel-plugin-emotion."`;

exports[`css component selectors without target 1`] = `"Component selectors can only be used in conjunction with babel-plugin-emotion."`;

exports[`css composition 1`] = `
.emotion-0 {
display: -webkit-box;
Expand Down Expand Up @@ -229,3 +231,8 @@ exports[`css random expressions undefined return 1`] = `
hello world
</h1>
`;

exports[`css styled throws a nice error when using the styled shorthand without babel-plugin-emotion 1`] = `
"You're trying to use the styled shorthand without babel-plugin-emotion.
Please install and setup babel-plugin-emotion or use the function call syntax(\`styled('div')\` instead of \`styled.div\`)"
`;
18 changes: 18 additions & 0 deletions packages/emotion/test/no-babel/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,19 @@ describe('css', () => {
)
}).toThrowErrorMatchingSnapshot()
})
test('component selectors without target', () => {
const SomeComponent = styled('div')`
color: blue;
`

expect(() => {
css`
${SomeComponent} {
color: red;
}
`
}).toThrowErrorMatchingSnapshot()
})
test('glamorous style api & composition', () => {
const H1 = styled('h1')(props => ({ fontSize: props.fontSize }))
const H2 = styled(H1)(props => ({ flex: props.flex }), { display: 'flex' })
Expand Down Expand Up @@ -197,4 +210,9 @@ describe('css', () => {

expect(tree).toMatchSnapshot()
})
test('styled throws a nice error when using the styled shorthand without babel-plugin-emotion', () => {
expect(() => {
styled.div``
}).toThrowErrorMatchingSnapshot()
})
})
6 changes: 0 additions & 6 deletions packages/react-emotion/test/__snapshots__/index.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -796,12 +796,6 @@ exports[`styled with higher order component that hoists statics 1`] = `
/>
`;

exports[`styled withComponent creates a new, unique stable class per invocation 1`] = `"eldhy9955"`;

exports[`styled withComponent creates a new, unique stable class per invocation 2`] = `"eldhy9956"`;

exports[`styled withComponent creates a new, unique stable class per invocation 3`] = `"eldhy9957"`;

exports[`styled withComponent does not carry styles from flattened component 1`] = `
.emotion-0 {
color: hotpink;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ test('component as selector (object syntax)', () => {
})

test('component as selector function interpolation (object syntax)', () => {
const H1 = styled('h1')({}, props => ({
const H1 = styled('h1')(props => ({
fontSize: `${props.fontSize}px`
}))

Expand Down
16 changes: 0 additions & 16 deletions packages/react-emotion/test/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import renderer from 'react-test-renderer'
import styled, { css, flush } from 'react-emotion'
import { ThemeProvider } from 'emotion-theming'
import hoistNonReactStatics from 'hoist-non-react-statics'
import { TARGET_KEY } from 'emotion-utils'
import { mount } from 'enzyme'
import enzymeToJson from 'enzyme-to-json'

Expand Down Expand Up @@ -1072,21 +1071,6 @@ describe('styled', () => {
expect(enzymeToJson(wrapper)).toMatchSnapshot()
})

test('withComponent creates a new, unique stable class per invocation', () => {
const Title = styled('h1')`
color: ${props => props.color || 'green'};
`
const Subtitle = Title.withComponent('h2')
const Byline = Title.withComponent('span')

expect(Subtitle[TARGET_KEY]).not.toBe(Title[TARGET_KEY])
expect(Byline[TARGET_KEY]).not.toBe(Title[TARGET_KEY])
expect(Byline[TARGET_KEY]).not.toBe(Subtitle[TARGET_KEY])

expect(Title[TARGET_KEY]).toMatchSnapshot()
expect(Subtitle[TARGET_KEY]).toMatchSnapshot()
expect(Byline[TARGET_KEY]).toMatchSnapshot()
})
test('name with class component', () => {
class SomeComponent extends React.Component<{ className: string }> {
render() {
Expand Down