forked from Khan/aphrodite
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
805 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,3 @@ | ||
lib | ||
node_modules | ||
dist/*.map | ||
.nyc_output |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,199 @@ | ||
'use strict'; | ||
|
||
Object.defineProperty(exports, '__esModule', { | ||
value: true | ||
}); | ||
|
||
var _slicedToArray = (function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i['return']) _i['return'](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError('Invalid attempt to destructure non-iterable instance'); } }; })(); | ||
|
||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
|
||
var _inlineStylePrefixerStatic = require('inline-style-prefixer/static'); | ||
|
||
var _inlineStylePrefixerStatic2 = _interopRequireDefault(_inlineStylePrefixerStatic); | ||
|
||
var _util = require('./util'); | ||
|
||
/** | ||
* Generate CSS for a selector and some styles. | ||
* | ||
* This function handles the media queries, pseudo selectors, and descendant | ||
* styles that can be used in aphrodite styles. | ||
* | ||
* @param {string} selector: A base CSS selector for the styles to be generated | ||
* with. | ||
* @param {Object} styleTypes: A list of properties of the return type of | ||
* StyleSheet.create, e.g. [styles.red, styles.blue]. | ||
* @param stringHandlers: See `generateCSSRuleset` | ||
* @param useImportant: See `generateCSSRuleset` | ||
* | ||
* To actually generate the CSS special-construct-less styles are passed to | ||
* `generateCSSRuleset`. | ||
* | ||
* For instance, a call to | ||
* | ||
* generateCSSInner(".foo", { | ||
* color: "red", | ||
* "@media screen": { | ||
* height: 20, | ||
* ":hover": { | ||
* backgroundColor: "black" | ||
* } | ||
* }, | ||
* ":active": { | ||
* fontWeight: "bold", | ||
* ">>bar": { | ||
* _names: { "foo_bar": true }, | ||
* height: 10, | ||
* } | ||
* } | ||
* }); | ||
* | ||
* will make 5 calls to `generateCSSRuleset`: | ||
* | ||
* generateCSSRuleset(".foo", { color: "red" }, ...) | ||
* generateCSSRuleset(".foo:active", { fontWeight: "bold" }, ...) | ||
* generateCSSRuleset(".foo:active .foo_bar", { height: 10 }, ...) | ||
* // These 2 will be wrapped in @media screen {} | ||
* generateCSSRuleset(".foo", { height: 20 }, ...) | ||
* generateCSSRuleset(".foo:hover", { backgroundColor: "black" }, ...) | ||
*/ | ||
var generateCSS = function generateCSS(selector, styleTypes, stringHandlers, useImportant) { | ||
var merged = styleTypes.reduce(_util.recursiveMerge); | ||
|
||
var declarations = {}; | ||
var mediaQueries = {}; | ||
var pseudoStyles = {}; | ||
|
||
Object.keys(merged).forEach(function (key) { | ||
if (key[0] === ':') { | ||
pseudoStyles[key] = merged[key]; | ||
} else if (key[0] === '@') { | ||
mediaQueries[key] = merged[key]; | ||
} else { | ||
declarations[key] = merged[key]; | ||
} | ||
}); | ||
|
||
return generateCSSRuleset(selector, declarations, stringHandlers, useImportant) + Object.keys(pseudoStyles).map(function (pseudoSelector) { | ||
return generateCSSRuleset(selector + pseudoSelector, pseudoStyles[pseudoSelector], stringHandlers, useImportant); | ||
}).join("") + Object.keys(mediaQueries).map(function (mediaQuery) { | ||
var ruleset = generateCSS(selector, [mediaQueries[mediaQuery]], stringHandlers, useImportant); | ||
return mediaQuery + '{' + ruleset + '}'; | ||
}).join(""); | ||
}; | ||
|
||
exports.generateCSS = generateCSS; | ||
/** | ||
* Helper method of generateCSSRuleset to facilitate custom handling of certain | ||
* CSS properties. Used for e.g. font families. | ||
* | ||
* See generateCSSRuleset for usage and documentation of paramater types. | ||
*/ | ||
var runStringHandlers = function runStringHandlers(declarations, stringHandlers) { | ||
var result = {}; | ||
|
||
Object.keys(declarations).forEach(function (key) { | ||
// If a handler exists for this particular key, let it interpret | ||
// that value first before continuing | ||
if (stringHandlers && stringHandlers.hasOwnProperty(key)) { | ||
result[key] = stringHandlers[key](declarations[key]); | ||
} else { | ||
result[key] = declarations[key]; | ||
} | ||
}); | ||
|
||
return result; | ||
}; | ||
|
||
/** | ||
* Generate a CSS ruleset with the selector and containing the declarations. | ||
* | ||
* This function assumes that the given declarations don't contain any special | ||
* children (such as media queries, pseudo-selectors, or descendant styles). | ||
* | ||
* Note that this method does not deal with nesting used for e.g. | ||
* psuedo-selectors or media queries. That responsibility is left to the | ||
* `generateCSS` function. | ||
* | ||
* @param {string} selector: the selector associated with the ruleset | ||
* @param {Object} declarations: a map from camelCased CSS property name to CSS | ||
* property value. | ||
* @param {Object.<string, function>} stringHandlers: a map from camelCased CSS | ||
* property name to a function which will map the given value to the value | ||
* that is output. | ||
* @param {bool} useImportant: A boolean saying whether to append "!important" | ||
* to each of the CSS declarations. | ||
* @returns {string} A string of raw CSS. | ||
* | ||
* Examples: | ||
* | ||
* generateCSSRuleset(".blah", { color: "red" }) | ||
* -> ".blah{color: red !important;}" | ||
* generateCSSRuleset(".blah", { color: "red" }, {}, false) | ||
* -> ".blah{color: red}" | ||
* generateCSSRuleset(".blah", { color: "red" }, {color: c => c.toUpperCase}) | ||
* -> ".blah{color: RED}" | ||
* generateCSSRuleset(".blah:hover", { color: "red" }) | ||
* -> ".blah:hover{color: red}" | ||
*/ | ||
var generateCSSRuleset = function generateCSSRuleset(selector, declarations, stringHandlers, useImportant) { | ||
var handledDeclarations = runStringHandlers(declarations, stringHandlers); | ||
|
||
var prefixedDeclarations = (0, _inlineStylePrefixerStatic2['default'])(handledDeclarations); | ||
|
||
var prefixedRules = (0, _util.flatten)((0, _util.objectToPairs)(prefixedDeclarations).map(function (_ref) { | ||
var _ref2 = _slicedToArray(_ref, 2); | ||
|
||
var key = _ref2[0]; | ||
var value = _ref2[1]; | ||
|
||
if (Array.isArray(value)) { | ||
var _ret = (function () { | ||
// inline-style-prefix-all returns an array when there should be | ||
// multiple rules, we will flatten to single rules | ||
|
||
var prefixedValues = []; | ||
var unprefixedValues = []; | ||
|
||
value.forEach(function (v) { | ||
if (v.indexOf('-') === 0) { | ||
prefixedValues.push(v); | ||
} else { | ||
unprefixedValues.push(v); | ||
} | ||
}); | ||
|
||
prefixedValues.sort(); | ||
unprefixedValues.sort(); | ||
|
||
return { | ||
v: prefixedValues.concat(unprefixedValues).map(function (v) { | ||
return [key, v]; | ||
}) | ||
}; | ||
})(); | ||
|
||
if (typeof _ret === 'object') return _ret.v; | ||
} | ||
return [[key, value]]; | ||
})); | ||
|
||
var rules = prefixedRules.map(function (_ref3) { | ||
var _ref32 = _slicedToArray(_ref3, 2); | ||
|
||
var key = _ref32[0]; | ||
var value = _ref32[1]; | ||
|
||
var stringValue = (0, _util.stringifyValue)(key, value); | ||
var ret = (0, _util.kebabifyStyleName)(key) + ':' + stringValue + ';'; | ||
return useImportant === false ? ret : (0, _util.importantify)(ret); | ||
}).join(""); | ||
|
||
if (rules) { | ||
return selector + '{' + rules + '}'; | ||
} else { | ||
return ""; | ||
} | ||
}; | ||
exports.generateCSSRuleset = generateCSSRuleset; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
'use strict'; | ||
|
||
Object.defineProperty(exports, '__esModule', { | ||
value: true | ||
}); | ||
|
||
var _slicedToArray = (function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i['return']) _i['return'](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError('Invalid attempt to destructure non-iterable instance'); } }; })(); | ||
|
||
var _util = require('./util'); | ||
|
||
var _inject = require('./inject'); | ||
|
||
var StyleSheet = { | ||
create: function create(sheetDefinition) { | ||
return (0, _util.mapObj)(sheetDefinition, function (_ref) { | ||
var _ref2 = _slicedToArray(_ref, 2); | ||
|
||
var key = _ref2[0]; | ||
var val = _ref2[1]; | ||
|
||
return [key, { | ||
// TODO(emily): Make a 'production' mode which doesn't prepend | ||
// the class name here, to make the generated CSS smaller. | ||
_name: key + '_' + (0, _util.hashObject)(val), | ||
_definition: val | ||
}]; | ||
}); | ||
}, | ||
|
||
rehydrate: function rehydrate() { | ||
var renderedClassNames = arguments.length <= 0 || arguments[0] === undefined ? [] : arguments[0]; | ||
|
||
(0, _inject.addRenderedClassNames)(renderedClassNames); | ||
} | ||
}; | ||
|
||
/** | ||
* Utilities for using Aphrodite server-side. | ||
*/ | ||
var StyleSheetServer = { | ||
renderStatic: function renderStatic(renderFunc) { | ||
(0, _inject.reset)(); | ||
(0, _inject.startBuffering)(); | ||
var html = renderFunc(); | ||
var cssContent = (0, _inject.flushToString)(); | ||
|
||
return { | ||
html: html, | ||
css: { | ||
content: cssContent, | ||
renderedClassNames: (0, _inject.getRenderedClassNames)() | ||
} | ||
}; | ||
} | ||
}; | ||
|
||
/** | ||
* Utilities for using Aphrodite in tests. | ||
* | ||
* Not meant to be used in production. | ||
*/ | ||
var StyleSheetTestUtils = { | ||
/** | ||
* Prevent styles from being injected into the DOM. | ||
* | ||
* This is useful in situations where you'd like to test rendering UI | ||
* components which use Aphrodite without any of the side-effects of | ||
* Aphrodite happening. Particularly useful for testing the output of | ||
* components when you have no DOM, e.g. testing in Node without a fake DOM. | ||
* | ||
* Should be paired with a subsequent call to | ||
* clearBufferAndResumeStyleInjection. | ||
*/ | ||
suppressStyleInjection: function suppressStyleInjection() { | ||
(0, _inject.reset)(); | ||
(0, _inject.startBuffering)(); | ||
}, | ||
|
||
/** | ||
* Opposite method of preventStyleInject. | ||
*/ | ||
clearBufferAndResumeStyleInjection: function clearBufferAndResumeStyleInjection() { | ||
(0, _inject.reset)(); | ||
} | ||
}; | ||
|
||
var css = function css() { | ||
for (var _len = arguments.length, styleDefinitions = Array(_len), _key = 0; _key < _len; _key++) { | ||
styleDefinitions[_key] = arguments[_key]; | ||
} | ||
|
||
var useImportant = true; // Append !important to all style definitions | ||
return (0, _inject.injectAndGetClassName)(useImportant, styleDefinitions); | ||
}; | ||
|
||
var injectedGlobals = new WeakSet(); | ||
var cssGlobal = function cssGlobal(globalStyles) { | ||
if (injectedGlobals.has(globalStyles)) return; | ||
injectedGlobals.add(globalStyles); | ||
var selectors = Object.keys(globalStyles); | ||
for (var i = 0; i < selectors.length; i++) { | ||
var _name = selectors[i]; | ||
var value = globalStyles[_name]; | ||
(0, _inject.injectStyleOnce)(_name, _name, [value], false); | ||
} | ||
}; | ||
|
||
exports['default'] = { | ||
StyleSheet: StyleSheet, | ||
StyleSheetServer: StyleSheetServer, | ||
StyleSheetTestUtils: StyleSheetTestUtils, | ||
css: css, | ||
cssGlobal: cssGlobal | ||
}; | ||
module.exports = exports['default']; |
Oops, something went wrong.