/
react.js
144 lines (125 loc) · 3.76 KB
/
react.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
import React, { PropTypes } from 'react'
import { isLikeRule, style, merge } from './index.js'
export * from './index.js' // convenience
// allows for dom elements to have a 'css' prop
export function createElement(tag, allProps, ...children) {
// todo - pull ids from className as well?
if(typeof tag === 'string' && allProps && allProps.css) {
let { css, ...props } = allProps
return React.createElement(tag, {
...props,
...Array.isArray(css) ? merge(...css) :
isLikeRule(css) ? css :
style(css)
}, ...children)
}
return React.createElement(tag, allProps, ...children)
}
export const dom = createElement
// css vars, done right
// see examples/vars for usage
export function vars(value = {}) {
return function (Target) {
return class Vars extends React.Component {
static childContextTypes = {
glamorCssVars: PropTypes.object
}
static contextTypes = {
glamorCssVars: PropTypes.object
}
getChildContext() {
return {
glamorCssVars: {
...this.context.glamorCssVars,
...typeof value === 'function' ? value(this.props) : value
}
}
}
render() {
return React.createElement(Target,
{ ...this.props, vars: this.context.glamorCssVars || (typeof value === 'function' ? value(this.props) : value) },
this.props.children
)
}
}
}
}
let themeIndex = 0
export function makeTheme() {
let key = `data-glamor-theme-${themeIndex++}`
let fn = (_default) => {
return Target => {
return class Theme extends React.Component {
static contextTypes = {
[key]: PropTypes.arrayOf(PropTypes.object)
}
render() {
return React.createElement(Target, {
...this.props,
[key]: merge( typeof _default === 'function' ?
_default(this.props) :
_default,
...(this.context[key] || []) )
})
}
}
}
}
fn.key = key
fn.add = (_style) => {
return Target => {
return class ThemeOverride extends React.Component {
static contextTypes = {
[key]: PropTypes.arrayOf(PropTypes.object)
}
static childContextTypes = {
[key]: PropTypes.arrayOf(PropTypes.object)
}
getChildContext() {
return {
[key]: [ typeof _style === 'function' ?
_style(this.props) :
_style,
...this.context[key] || [] ]
}
}
render() {
return React.createElement(Target, this.props)
}
}
}
}
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
}
}