From 6864818f442d79a18038129f13e8c015015595b0 Mon Sep 17 00:00:00 2001 From: Benjamin Otto Date: Thu, 27 Oct 2016 11:45:02 +0200 Subject: [PATCH] add support for propMerge() in react package --- docs/composition.md | 8 ++++++++ react.d.ts | 3 ++- src/react.js | 41 +++++++++++++++++++++++++++++++++++++++++ tests/index.js | 36 +++++++++++++++++++++++++++++++++++- 4 files changed, 86 insertions(+), 2 deletions(-) diff --git a/docs/composition.md b/docs/composition.md index 748e9b4..52674d8 100644 --- a/docs/composition.md +++ b/docs/composition.md @@ -40,6 +40,14 @@ let Button = ({ type, children, onClick = ::console.log }) => +// compose glamor styled react components (with propMerge the order of css rules/styles doesn't matter +// because it will take care of a proper merge) +const specificStyle = style({ height: '100px' }); +const defaultStyle = style({ height: '200px' }); + +let DefaultContainer = (props) =>
+let SpecificContainer = (props) => {props.children}
+ // or make your own helper function alá aphrodite et al let sheet = createSheet({ container: {...}, diff --git a/react.d.ts b/react.d.ts index aad474b..6ca7eef 100644 --- a/react.d.ts +++ b/react.d.ts @@ -1,6 +1,7 @@ -export * from './index.d.ts'; +import { CSSProperties, StyleAttribute } from './index'; export const createElement: any; export const dom: any; export const vars: any; export const makeTheme: any; +export function propMerge(styles: StyleAttribute | CSSProperties, obj: T): T; diff --git a/src/react.js b/src/react.js index e561838..9694f87 100644 --- a/src/react.js +++ b/src/react.js @@ -101,3 +101,44 @@ export function makeTheme() { return fn } + +function toStyle(s) { + return s!= null && isLikeRule(s) ? s : style(s); +} + +// propMerge will take an arbitrary object "props", filter out glamor data-css-* styles and merge it with "mergeStyle" +// use it for react components composing +export function propMerge(mergeStyle, props) { + const glamorStyleKeys = Object.keys(props).filter(x => !!/data\-css\-([a-zA-Z0-9]+)/.exec(x)) + + // no glamor styles in obj + if (glamorStyleKeys.length === 0) { + return { + ...props, + ...toStyle(mergeStyle) + } + } + + if (glamorStyleKeys.length > 1) { + console.warn('[glamor] detected multiple data attributes on an element. This may lead to unexpected style because of css insertion order.'); + + // just append "mergeStyle" to props, because we dunno in which order glamor styles were added to props + return { + ...props, + ...toStyle(mergeStyle) + } + } + + const dataCssKey= glamorStyleKeys[0] + const cssData = props[dataCssKey] + + const mergedStyles = merge(mergeStyle, { [dataCssKey]: cssData }) + + const restProps = Object.assign({}, props) + delete restProps[dataCssKey] + + return { + ...restProps, + ...mergedStyles + } +} diff --git a/tests/index.js b/tests/index.js index e5ceed6..da7fe23 100644 --- a/tests/index.js +++ b/tests/index.js @@ -25,6 +25,8 @@ import { style, hover, nthChild, firstLetter, media, merge, compose, select, vi flush, styleSheet, rehydrate } from '../src' +import { propMerge } from '../src/react' + import clean from '../src/clean' import { View } from '../src/jsxstyle' @@ -697,9 +699,41 @@ describe('plugins', () => { }) describe('react', () => { + let node + beforeEach(() => { + node = document.createElement('div') + document.body.appendChild(node) + }) + + afterEach(() => { + unmountComponentAtNode(node) + document.body.removeChild(node) + flush() + }) + it('dom elements accept css prop') it('can use vars to set/unset values vertically on the dom-tree') - it('can use themes to compose styles vertically on the dom-tree') + it('can use themes to compose styles vertically on the dom-tree') + + it('propMerge will merge styles with react props', () => { + // the order of the styles matter here + // thats how css works :/ + const specificStyle = style({ height: '100px' }) + const defaultStyle = style({ height: '200px' }) + const dummyStyle = style({ color: 'green' }) + + let DefaultContainer = (props) =>
+ let SpecificContainer = (props) => + + render(, node, () => { + expect(childStyle(node).height).toEqual('100px') + }) + + // this would only work properly if we use propMerge also on definition + render(, node, () => { + expect(childStyle(node).height).toEqual('200px') + }) + }) }) describe('aphrodite', () => {