Skip to content

Commit d1b44f6

Browse files
committed
initial commit
1 parent 1ac3818 commit d1b44f6

File tree

3 files changed

+428
-0
lines changed

3 files changed

+428
-0
lines changed

package.json

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
{
2+
"name": "react-css-builder",
3+
"version": "0.0.1",
4+
"description": "CSS builder to create react component style objects",
5+
"main": "react-css-builder.js",
6+
"directories": {
7+
"test": "tests"
8+
},
9+
"scripts": {
10+
"test": "mocha"
11+
},
12+
"repository": {
13+
"type": "git",
14+
"url": "https://github.com/jhudson8/react-css-builder.git"
15+
},
16+
"keywords": [
17+
"react",
18+
"css"
19+
],
20+
"author": "Joe Hudson <joehud@gmail.com>",
21+
"license": "MIT",
22+
"bugs": {
23+
"url": "https://github.com/jhudson8/react-css-builder/issues"
24+
},
25+
"homepage": "https://github.com/jhudson8/react-css-builder",
26+
"devDependencies": {
27+
"chai": "^1.10.0",
28+
"mocha": "^2.1.0"
29+
}
30+
}

react-css-builder.js

+249
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,249 @@
1+
2+
// main cache of style definitions
3+
var vars;
4+
var mixins = {};
5+
var styles = { global: {} };
6+
7+
// utility / helper functions
8+
9+
// extend the attributes of src into target
10+
function _extend(target, src) {
11+
if (src) {
12+
for (var name in src) {
13+
if (src.hasOwnProperty(name)) {
14+
target[name] = src[name];
15+
}
16+
}
17+
}
18+
return target;
19+
}
20+
21+
// return true if obj is a function
22+
function _isFunction(obj) {
23+
return typeof obj === 'function';
24+
}
25+
26+
function _isDeep(obj) {
27+
for (var name in obj) {
28+
if (obj.hasOwnProperty(name)) {
29+
if (typeof obj[name] === 'object') {
30+
return true;
31+
}
32+
}
33+
}
34+
}
35+
36+
37+
/**
38+
* Return a style set function that should be executed as
39+
* function(vars)
40+
*/
41+
var getStyleSet = function(path, optionalNamespace) {
42+
var paths = path.split('.');
43+
if (optionalNamespace) {
44+
paths.splice(0, 0, optionalNamespace);
45+
}
46+
var rtn = _getStyleSetFromBase(paths, 0, styles);
47+
if (!rtn) {
48+
if (optionalNamespace) {
49+
paths.splice(0, 1);
50+
rtn = _getStyleSetFromBase(paths, 0, styles);
51+
}
52+
if (!rtn) {
53+
throw new Error('Unknown style path "' + path + '"');
54+
}
55+
}
56+
if (!_isFunction(rtn)) {
57+
throw new Error('style path is not a valid styleset "' + path + '"');
58+
}
59+
return rtn;
60+
};
61+
62+
// recurse function used with getStyleSet
63+
var _getStyleSetFromBase = function(parts, index, base) {
64+
var part = parts[index],
65+
rtn = base[part] || (index === 0 && base.global[part]);
66+
if (!rtn) {
67+
return;
68+
}
69+
var nextIndex = index + 1;
70+
if (nextIndex >= parts.length) {
71+
return rtn;
72+
} else {
73+
return _getStyleSetFromBase(parts, nextIndex, rtn);
74+
}
75+
};
76+
77+
78+
/**
79+
* Normalize all stylesheet definitions
80+
*/
81+
function normalizeStyles(styles, base, namespace) {
82+
for (var key in styles) {
83+
if (styles.hasOwnProperty(key)) {
84+
base[key] = normalizeStyleAttributes(styles[key], namespace);
85+
}
86+
}
87+
}
88+
89+
/**
90+
* Normalize the styleset attributes when registering stylesets.
91+
* Recurse function for normalizeStyles
92+
*/
93+
function normalizeStyleAttributes(styleset, namespace) {
94+
var name;
95+
if (_isFunction(styleset)) {
96+
return function(vars) {
97+
return styleset(new StyleContext(vars, namespace), vars);
98+
};
99+
}
100+
101+
if (styleset.attributes) {
102+
// has nesting
103+
var rtn = normalizeStyleAttributes(styleset.attributes);
104+
for (name in styleset) {
105+
if (styleset.hasOwnProperty(name) && name !== 'attributes') {
106+
rtn[name] = normalizeStyleAttributes(styleset[name], namespace);
107+
}
108+
}
109+
return rtn;
110+
} else {
111+
if (_isDeep(styleset)) {
112+
// nesting container
113+
for (name in styleset) {
114+
if (styleset.hasOwnProperty(name)) {
115+
styleset[name] = normalizeStyleAttributes(styleset[name], namespace);
116+
}
117+
}
118+
return styleset;
119+
} else {
120+
// simple attributes
121+
return function() { return styleset; };
122+
}
123+
}
124+
}
125+
126+
127+
var rtn = {
128+
_reset: function() {
129+
vars = {};
130+
styles = { global: {} };
131+
},
132+
133+
// return an object with function calls for each named style
134+
register: function(namespace, _styles) {
135+
if (!_styles) {
136+
_styles = namespace;
137+
namespace = 'global';
138+
}
139+
if (_isFunction(_styles)) {
140+
_styles = _styles(rtn);
141+
}
142+
143+
var base = styles[namespace];
144+
if (!base) {
145+
base = styles[namespace] = {};
146+
}
147+
148+
normalizeStyles(_styles, base, namespace === 'global' ? undefined : namespace);
149+
},
150+
151+
mixin: function(name, mixin) {
152+
mixins[name] = mixin;
153+
return this;
154+
},
155+
156+
css: function(paths) {
157+
return new StyleSelector(paths).css();
158+
},
159+
160+
get: function(paths) {
161+
return new StyleSelector(paths);
162+
},
163+
164+
vars: function(_vars) {
165+
vars = vars || {};
166+
_extend(vars, _vars);
167+
return this;
168+
}
169+
};
170+
171+
172+
/**
173+
* Class used as the return response from calling "css" on exports.
174+
* Allows for chained commands to be completed by the "val" method
175+
* to return the final styleset values.
176+
*/
177+
var StyleSelector = function(paths) {
178+
this.paths = normalizePaths(paths);
179+
};
180+
_extend(StyleSelector.prototype, {
181+
attr: function(attrs) {
182+
this._attrs = _attrs;
183+
return this;
184+
},
185+
vars: function(vars) {
186+
this._vars = vars;
187+
return this;
188+
},
189+
css: function() {
190+
var _vars = this._vars;
191+
if (vars) {
192+
if (_vars) {
193+
_extend(_vars, vars);
194+
} else {
195+
_vars = vars;
196+
}
197+
}
198+
199+
if (this.paths.length === 1 && !this.attrs) {
200+
return getStyleSet(this.paths[0])(_vars);
201+
}
202+
203+
var attrs = {};
204+
for (var i=0; i<this.paths.length; i++) {
205+
_extend(attrs, getStyleSet(this.paths[i])(this, this.vars));
206+
}
207+
_.extend(attrs, this._attrs);
208+
return attrs;
209+
}
210+
});
211+
212+
function normalizePaths(paths) {
213+
return paths && (Array.isArray(paths) ? paths : paths.split(/\s+/));
214+
}
215+
216+
217+
/**
218+
* The style context object provided to styleset functions
219+
*/
220+
var StyleContext = function(vars, namespace) {
221+
this.vars = vars;
222+
this.namespace = namespace;
223+
this.attrs = {};
224+
};
225+
_extend(StyleContext.prototype, {
226+
include: function(path) {
227+
_extend(this.attrs, getStyleSet(path, this.namespace)(vars));
228+
return this;
229+
},
230+
mixin: function(name) {
231+
var args = Array.prototype.slice.call(arguments, 1),
232+
mixin = mixins[name];
233+
if (!mixin) {
234+
throw new Error('Unknown mixin "' + name + '"');
235+
}
236+
_extend(this.attrs, mixin.apply(this.vars, args));
237+
return this;
238+
},
239+
val: function(attr) {
240+
if (attr) {
241+
return _extend(this.attrs, attr);
242+
} else {
243+
return this.attrs;
244+
}
245+
246+
}
247+
});
248+
249+
module.exports = rtn;

0 commit comments

Comments
 (0)