Skip to content
This repository has been archived by the owner on Dec 13, 2018. It is now read-only.

Commit

Permalink
feat(css): allow the css prop to accept fns and strings
Browse files Browse the repository at this point in the history
**What**: Closes #170

**Why**: enables code reuse and potentially "Ahead of Time compilation"

**How**:

- Reusing the same logic for `cssOverrides` as we use for
`styles` in `get-glamor-classname.js`. Tiny refactor there.
- Adding tests to cover all the cases for the API.
  • Loading branch information
Kent C. Dodds committed Jun 9, 2017
1 parent 844d2af commit acfe0c2
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 26 deletions.
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -467,8 +467,10 @@ const myCustomGlamorStyles = glamor.css({fontSize: 2})

##### using `css`

This is an object and if provided, it will be merged with this component's and
take highest priority over the component's predefined styles.
This can be the same type as any of the styles provided
(as in `glamorous.div(...styles)`). If specified, it will be merged with this
component's styles and take highest priority over the component's predefined
styles.

```jsx
const myCustomGlamorStyles = glamor.css({fontSize: 2, padding: 2})
Expand Down
45 changes: 43 additions & 2 deletions src/__tests__/__snapshots__/index.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ exports[`can be configured to use the displayName in the className 1`] = `
/>
`;

exports[`can use pre-glamorous components with css attributes 1`] = `
exports[`can use pre-built glamorous components with css attributes 1`] = `
.css-1t62idy,
[data-css-1t62idy] {
-webkit-flex-direction: column;
Expand All @@ -79,7 +79,7 @@ exports[`can use pre-glamorous components with css attributes 1`] = `
/>
`;

exports[`can use pre-glamorous components with css prop 1`] = `
exports[`can use pre-built glamorous components with css prop 1`] = `
.css-1n96jtr,
[data-css-1n96jtr] {
-webkit-flex-direction: column;
Expand All @@ -102,6 +102,47 @@ exports[`can use pre-glamorous components with css prop 1`] = `
/>
`;

exports[`css prop with a className 1`] = `
<section
class="css-nil abc-123"
/>
`;

exports[`css prop with a function 1`] = `
.css-1xnhj1e,
[data-css-1xnhj1e] {
padding: 20px;
}
<section
class="css-1xnhj1e"
/>
`;

exports[`css prop with an array 1`] = `
.css-10ql5rd,
[data-css-10ql5rd] {
margin-top: 1px;
margin-right: 2px;
margin-bottom: 2px;
}
<section
class="css-10ql5rd"
/>
`;

exports[`css prop with an object 1`] = `
.css-1dmiui7,
[data-css-1dmiui7] {
font-size: 12px;
}
<section
class="css-1dmiui7"
/>
`;

exports[`forwards props when the GlamorousComponent.rootEl is known 1`] = `
.css-mhpxxj,
[data-css-mhpxxj] {
Expand Down
48 changes: 37 additions & 11 deletions src/__tests__/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ test('sanity test', () => {
expect(render(<Div />)).toMatchSnapshotWithGlamor()
})

test('can use pre-glamorous components with css attributes', () => {
test('can use pre-built glamorous components with css attributes', () => {
expect(
render(
<glamorous.A
Expand All @@ -39,7 +39,7 @@ test('can use pre-glamorous components with css attributes', () => {
).toMatchSnapshotWithGlamor()
})

test('can use pre-glamorous components with css prop', () => {
test('can use pre-built glamorous components with css prop', () => {
const computed = 'background'
expect(
render(
Expand All @@ -57,6 +57,38 @@ test('can use pre-glamorous components with css prop', () => {
).toMatchSnapshotWithGlamor()
})

test('the css prop accepts "GlamorousStyles"', () => {
const object = {fontSize: 12}
const array = [
{marginTop: 1, marginRight: 1},
{marginRight: 2, marginBottom: 2},
]
// this one's weird, but could enable some Ahead of Time
// compilation in the future
const className = 'abc-123'
const fn = jest.fn(() => ({padding: 20}))
expect(render(<glamorous.Section css={object} />)).toMatchSnapshotWithGlamor(
'css prop with an object',
)
expect(render(<glamorous.Section css={array} />)).toMatchSnapshotWithGlamor(
'css prop with an array',
)
expect(
render(<glamorous.Section css={className} />),
).toMatchSnapshotWithGlamor('css prop with a className')
const props = {css: fn, otherThing: 43, theme: {color: 'red'}}
expect(render(<glamorous.Section {...props} />)).toMatchSnapshotWithGlamor(
'css prop with a function',
)
expect(fn).toHaveBeenCalledTimes(1)
const context = {__glamorous__: undefined}
expect(fn).toHaveBeenCalledWith(
expect.objectContaining(props),
expect.objectContaining(props.theme),
expect.objectContaining(context),
)
})

test('merges composed component styles for reasonable overrides', () => {
const Parent = glamorous.div({
marginTop: 1,
Expand Down Expand Up @@ -235,9 +267,7 @@ test('forwards props when the GlamorousComponent.rootEl is known', () => {
})()
// no need to pass anything. This will just create be a no-op class,
// no problem
const MyWrappedVersionMock = jest.fn(props => (
<MyWrappedVersion {...props} />
))
const MyWrappedVersionMock = jest.fn(props => <MyWrappedVersion {...props} />)

// from there we can use our wrapped version and it will function the
// same as the original
Expand Down Expand Up @@ -291,9 +321,7 @@ test('renders a component with theme properties', () => {
},
(props, theme) => ({padding: theme.padding}),
)
expect(
render(<Comp theme={{padding: '10px'}} />),
).toMatchSnapshotWithGlamor()
expect(render(<Comp theme={{padding: '10px'}} />)).toMatchSnapshotWithGlamor()
})

test('in development mode the theme is frozen and cannot be changed', () => {
Expand Down Expand Up @@ -404,9 +432,7 @@ test('can accept classNames instead of style objects', () => {
// this is to support a babel plugin to pre-compile static styles
const className1 = glamor.css({paddingTop: 1, paddingRight: 1}).toString()
const styles2 = {paddingRight: 2, paddingBottom: 2}
const className3 = glamor
.css({paddingBottom: 3, paddingLeft: 3})
.toString()
const className3 = glamor.css({paddingBottom: 3, paddingLeft: 3}).toString()
const styles4 = {paddingLeft: 4}
const Comp = glamorous.div(
className1,
Expand Down
37 changes: 26 additions & 11 deletions src/get-glamor-classname.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,31 @@ function extractGlamorStyles(className = '') {
export default getGlamorClassName

function getGlamorClassName(styles, props, cssOverrides, theme, context) {
const {mappedArgs, nonGlamorClassNames} = handleStyles(
styles,
props,
theme,
context,
)
const {
mappedArgs: cssOverridesArgs,
nonGlamorClassNames: cssOverridesClassNames,
} = handleStyles([cssOverrides], props, theme, context)
const {
glamorStyles: parentGlamorStyles,
glamorlessClassName,
} = extractGlamorStyles(props.className)

const glamorClassName = css(
...mappedArgs,
...parentGlamorStyles,
...cssOverridesArgs,
).toString()
const extras = nonGlamorClassNames.concat(cssOverridesClassNames).join(' ')
return `${glamorlessClassName} ${glamorClassName} ${extras}`.trim()
}

function handleStyles(styles, props, theme, context) {
let current
const mappedArgs = []
const nonGlamorClassNames = []
Expand All @@ -44,17 +69,7 @@ function getGlamorClassName(styles, props, cssOverrides, theme, context) {
mappedArgs.push(current)
}
}
const {
glamorStyles: parentGlamorStyles,
glamorlessClassName,
} = extractGlamorStyles(props.className)
const glamorClassName = css(
...mappedArgs,
...parentGlamorStyles,
cssOverrides,
).toString()
const extras = nonGlamorClassNames.join(' ')
return `${glamorlessClassName} ${glamorClassName} ${extras}`.trim()
return {mappedArgs, nonGlamorClassNames}
}

function processStringClass(str, mappedArgs, nonGlamorClassNames) {
Expand Down

0 comments on commit acfe0c2

Please sign in to comment.