Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

fela

Package Overview
Dependencies
Maintainers
1
Versions
123
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

fela - npm Package Compare versions

Comparing version 1.0.0-alpha.5 to 1.0.0-alpha.6

dist/fela-server.js

847

dist/fela.js

@@ -38,2 +38,17 @@ (function (global, factory) {

babelHelpers.defineProperty = function (obj, key, value) {
if (key in obj) {
Object.defineProperty(obj, key, {
value: value,
enumerable: true,
configurable: true,
writable: true
});
} else {
obj[key] = value;
}
return obj;
};
babelHelpers.extends = Object.assign || function (target) {

@@ -55,13 +70,738 @@ for (var i = 1; i < arguments.length; i++) {

var Selector = function () {
function __commonjs(fn, module) { return module = { exports: {} }, fn(module, module.exports), module.exports; }
var emptyFunction = __commonjs(function (module) {
"use strict";
/**
* Copyright (c) 2013-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*
*/
function makeEmptyFunction(arg) {
return function () {
return arg;
};
}
/**
* This function accepts and discards inputs; it has no side effects. This is
* primarily useful idiomatically for overridable function endpoints which
* always need to be callable, since JS lacks a null-call idiom ala Cocoa.
*/
var emptyFunction = function emptyFunction() {};
emptyFunction.thatReturns = makeEmptyFunction;
emptyFunction.thatReturnsFalse = makeEmptyFunction(false);
emptyFunction.thatReturnsTrue = makeEmptyFunction(true);
emptyFunction.thatReturnsNull = makeEmptyFunction(null);
emptyFunction.thatReturnsThis = function () {
return this;
};
emptyFunction.thatReturnsArgument = function (arg) {
return arg;
};
module.exports = emptyFunction;
});
var require$$0 = (emptyFunction && typeof emptyFunction === 'object' && 'default' in emptyFunction ? emptyFunction['default'] : emptyFunction);
var warning = __commonjs(function (module) {
/**
* Copyright 2014-2015, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
'use strict';
var emptyFunction = require$$0;
/**
* Similar to invariant but only logs a warning if the condition is not met.
* This can be used to log issues in development environments in critical
* paths. Removing the logging code for production environments will keep the
* same logic and follow the same code paths.
*/
var warning = emptyFunction;
if (true) {
warning = function warning(condition, format) {
for (var _len = arguments.length, args = Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) {
args[_key - 2] = arguments[_key];
}
if (format === undefined) {
throw new Error('`warning(condition, format, ...args)` requires a warning ' + 'message argument');
}
if (format.indexOf('Failed Composite propType: ') === 0) {
return; // Ignore CompositeComponent proptype check.
}
if (!condition) {
var argIndex = 0;
var message = 'Warning: ' + format.replace(/%s/g, function () {
return args[argIndex++];
});
if (typeof console !== 'undefined') {
console.error(message);
}
try {
// --- Welcome to debugging React ---
// This error was thrown as a convenience so that you can use this stack
// to find the callsite that caused this warning to fire.
throw new Error(message);
} catch (x) {}
}
};
}
module.exports = warning;
});
var warning$1 = (warning && typeof warning === 'object' && 'default' in warning ? warning['default'] : warning);
/**
* converts camel cased to dash cased properties
*
* @param {string} property - camel cased CSS property
* @returns {string} dash cased CSS property
*/
function camelToDashCase(property) {
return property.replace(/([a-z]|^)([A-Z])/g, function (match, p1, p2) {
return p1 + '-' + p2.toLowerCase();
}).replace('ms-', '-ms-');
}
/**
* generates a valid CSS string containing styles
*
* @param {Object} styles - object containing CSS declarations
* @returns {string} valid CSS string with dash cased properties
*/
function cssifyObject(styles) {
return Object.keys(styles).reduce(function (css, prop) {
// prevents the semicolon after
// the last rule declaration
if (css.length > 0) {
css += ';';
}
css += camelToDashCase(prop) + ':' + styles[prop];
return css;
}, '');
}
/**
* generates a hashcode from a string
* taken from http://stackoverflow.com/a/7616484
*
* @param {string} str - str used to generate the unique hash code
* @return {string} compressed content hash
*/
function generateHash(str) {
var hash = 0;
var iterator = 0;
var char = void 0;
var length = str.length;
// return a `s` for empty strings
// to symbolize `static`
if (length === 0) {
return '';
}
for (; iterator < length; ++iterator) {
char = str.charCodeAt(iterator);
hash = (hash << 5) - hash + char;
hash |= 0;
}
return '-' + hash.toString(36);
}
/**
* stringifies an object without any special character
* uses a sort version of the obj to get same hash codes
*
* @param {Object} obj - obj that gets stringified
* @return {string} stringyfied sorted object
*/
function sortedStringify(obj) {
if (obj === undefined) {
return '';
}
return Object.keys(obj).sort().reduce(function (str, prop) {
// only concatenate property and value
// without any special characters
str += prop + obj[prop];
return str;
}, '');
}
var isPseudo = (function (property) {
return property.charAt(0) === ':';
})
var isMediaQuery = (function (property) {
return property.substr(0, 6) === '@media';
})
var StyleSheet = function () {
/**
* Selector is a dynamic style container
* StyleSheet is a low-level container to cache Selectors
* Keyframes and FontFaces which optimizes styles
*/
function StyleSheet() {
var config = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
babelHelpers.classCallCheck(this, StyleSheet);
this.listeners = new Set();
this.keyframePrefixes = config.keyframePrefixes || ['-webkit-', '-moz-', ''];
this.plugins = config.plugins || [];
this._init();
}
/**
* clears the sheet's cache but keeps all listeners
*/
babelHelpers.createClass(StyleSheet, [{
key: 'clear',
value: function clear() {
this._init();
}
/**
* renders all cached selector styles into a single valid CSS string
* clusters media query styles into groups to reduce output size
*/
}, {
key: 'renderToString',
value: function renderToString() {
var _this = this;
var css = '';
this.fontFaces.forEach(function (fontFace) {
return css += fontFace;
});
this.keyframes.forEach(function (variation) {
variation.forEach(function (markup) {
return css += markup;
});
});
css += this._renderCache(this.cache);
this.mediaCache.forEach(function (cache, media) {
css += '@media ' + media + '{' + _this._renderCache(cache) + '}';
});
return css;
}
/**
* Adds a new subscription to get notified on every rerender
*
* @param {Function} callback - callback function which will be executed
* @return {Object} equivalent unsubscribe method
*/
}, {
key: 'subscribe',
value: function subscribe(callback) {
var _this2 = this;
this.listeners.add(callback);
return {
unsubscribe: function unsubscribe() {
return _this2.listeners.delete(callback);
}
};
}
/**
* calls each listener with the current CSS markup of all caches
* gets only called if the markup actually changes
*
* @param {Function} callback - callback function which will be executed
* @return {Object} equivalent unsubscribe method
*/
}, {
key: '_emitChange',
value: function _emitChange() {
var css = this.renderToString();
this.listeners.forEach(function (listener) {
return listener(css);
});
}
/**
* initializes the stylesheet by setting up the caches
*/
}, {
key: '_init',
value: function _init() {
this.cache = new Map();
this.mediaCache = new Map();
this.fontFaces = new Set();
this.keyframes = new Map();
this.ids = new Map();
this._counter = -1;
}
/**
* renders a new font-face and caches it
*
* @param {FontFace} fontFace - fontFace which gets rendered
* @return {string} fontFamily reference
*/
}, {
key: '_renderFontFace',
value: function _renderFontFace(fontFace) {
if (!this.fontFaces.has(fontFace)) {
var renderedFontFace = '@font-face {' + cssifyObject(fontFace.render()) + '}';
this.fontFaces.add(renderedFontFace);
this._emitChange();
}
return fontFace.fontFamily;
}
/**
* renders a new keyframe variation and caches the result
*
* @param {Keyframe} keyframe - Keyframe which gets rendered
* @param {Object?} props - properties used to render
* @param {Function[]?} plugins - array of plugins to process styles
* @return {string} animationName to reference the rendered keyframe
*/
}, {
key: '_renderKeyframeVariation',
value: function _renderKeyframeVariation(keyframe) {
var props = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1];
var plugins = arguments.length <= 2 || arguments[2] === undefined ? [] : arguments[2];
// rendering a Keyframe for the first time
// will create cache entries and an ID reference
if (!this.keyframes.has(keyframe)) {
this.keyframes.set(keyframe, new Map());
this.ids.set(keyframe, ++this._counter);
}
var cachedKeyframe = this.keyframes.get(keyframe);
var propsReference = this._generatePropsReference(props);
var animationName = 'k' + this.ids.get(keyframe) + propsReference;
// only if the cached selector has not already been rendered
// with a specific set of properties it actually renders
if (!cachedKeyframe.has(propsReference)) {
var pluginInterface = {
plugins: this.plugins.concat(plugins),
processStyles: this._processStyles,
styles: keyframe.render(props),
props: props
};
var processedKeyframe = this._processStyles(pluginInterface);
cachedKeyframe.set(propsReference, this._renderKeyframe(processedKeyframe, animationName));
this._emitChange();
}
return animationName;
}
/**
* renders a new selector variation and caches the result
*
* @param {Selector|Function} selector - Selector which gets rendered
* @param {Object?} props - properties used to render
* @param {Function[]?} plugins - array of plugins to process styles
* @return {string} className to reference the rendered selector
*/
}, {
key: '_renderSelectorVariation',
value: function _renderSelectorVariation(selector) {
var _this3 = this;
var props = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1];
var plugins = arguments.length <= 2 || arguments[2] === undefined ? [] : arguments[2];
// rendering a Selector for the first time
// will create cache entries and an ID reference
if (!this.cache.has(selector)) {
this.ids.set(selector, ++this._counter);
this.cache.set(selector, new Map());
// directly render the static base styles to be able
// to diff future dynamic styles with those
this._renderSelectorVariation(selector, {}, plugins);
}
var cachedSelector = this.cache.get(selector);
var propsReference = this._generatePropsReference(props);
// uses the reference ID and the props to generate an unique className
var className = 'c' + this.ids.get(selector) + propsReference;
// only if the cached selector has not already been rendered
// with a specific set of properties it actually renders
if (!cachedSelector.has(propsReference)) {
(function () {
// get the render method of either class-like selectors
// or pure functional selectors without a constructor
var pluginInterface = {
plugins: _this3.plugins.concat(plugins),
processStyles: _this3._processStyles,
styles: selector(props),
props: props
};
var preparedStyles = _this3._prepareStyles(pluginInterface, cachedSelector.get('static'), propsReference);
var clusteredStyles = _this3._clusterStyles(preparedStyles);
if (Object.keys(clusteredStyles).length === 0) {
cachedSelector.set(propsReference, '');
}
Object.keys(clusteredStyles).forEach(function (media) {
var renderedStyles = _this3._renderClusteredStyles(clusteredStyles[media], className);
if (media === '') {
cachedSelector.set(propsReference, renderedStyles);
} else {
if (!_this3.mediaCache.has(media)) {
_this3.mediaCache.set(media, new Map([[selector, new Map()]]));
}
if (!_this3.mediaCache.get(media).has(selector)) {
_this3.mediaCache.get(media).set(selector, new Map());
}
_this3.mediaCache.get(media).get(selector).set(propsReference, renderedStyles);
}
});
// keep static styles to diff dynamic onces later on
if (propsReference === '') {
cachedSelector.set('static', preparedStyles);
}
// emit changes as the styles stack changed
_this3._emitChange();
})();
}
var baseClassName = 'c' + this.ids.get(selector);
if (cachedSelector.get(propsReference) === '') {
return baseClassName;
}
// returns either the base className or both the base and the dynamic part
return className !== baseClassName ? baseClassName + ' ' + className : className;
}
/**
* executes each plugin using a predefined plugin interface
*
* @param {Object} pluginInterface - interface containing relevant processing data
* @return {Object} processed styles
*/
}, {
key: '_processStyles',
value: function _processStyles(pluginInterface) {
var plugins = pluginInterface.plugins;
var styles = pluginInterface.styles;
// pipes each plugin by passes the plugin interface
// NOTE: as the styles are passed directly they're editable
// therefore the plugin order might matter
plugins.forEach(function (plugin) {
return styles = plugin(pluginInterface);
});
return styles;
}
/**
* extracts all dynamic styles by diffing with the static base styles
*
* @param {Object} styles - dynamic styles
* @param {Object} base - static base styles to diff
* @return {Object} encapsulated dynamic styles
*/
}, {
key: '_extractDynamicStyles',
value: function _extractDynamicStyles(styles, base) {
var _this4 = this;
Object.keys(styles).forEach(function (property) {
var value = styles[property];
if (value instanceof Object && !Array.isArray(value)) {
// also diff inner objects such as pseudo classes
styles[property] = _this4._extractDynamicStyles(styles[property], base[property]);
if (Object.keys(styles[property]).length === 0) {
delete styles[property];
}
// checks if the base styles has the property and if the value is equal
} else if (base.hasOwnProperty(property) && base[property] === value) {
delete styles[property];
}
});
return styles;
}
/**
* removes every invalid property except pseudo class objects
*
* @param {Object} styles - styles to be validated
* @return {Object} validated styles
*/
}, {
key: '_validateStyles',
value: function _validateStyles(styles) {
var _this5 = this;
Object.keys(styles).forEach(function (property) {
var value = styles[property];
if (value instanceof Object && !Array.isArray(value)) {
styles[property] = isPseudo(property) || isMediaQuery(property) ? _this5._validateStyles(value) : {};
if (Object.keys(styles[property]).length === 0) {
delete styles[property];
}
} else if (typeof value !== 'string' && typeof value !== 'number') {
delete styles[property];
}
});
return styles;
}
/**
* flattens nested pseudo classes
* removes all invalid properties that are not either a string or a number
*
* @param {Object} styles - dynamic styles
* @return {Object} flat and validated styles
*/
}, {
key: '_clusterStyles',
value: function _clusterStyles(styles) {
var pseudo = arguments.length <= 1 || arguments[1] === undefined ? '' : arguments[1];
var _this6 = this;
var media = arguments.length <= 2 || arguments[2] === undefined ? '' : arguments[2];
var out = arguments.length <= 3 || arguments[3] === undefined ? {} : arguments[3];
Object.keys(styles).forEach(function (property) {
var value = styles[property];
if (value instanceof Object && !Array.isArray(value)) {
if (isPseudo(property)) {
_this6._clusterStyles(value, pseudo + property, media, out);
} else if (isMediaQuery(property)) {
var query = property.slice(6).trim();
var nestedMedia = media !== '' ? media + ' and ' + query : query;
_this6._clusterStyles(value, pseudo, nestedMedia, out);
}
} else {
if (!out[media]) {
out[media] = babelHelpers.defineProperty({}, pseudo, {});
}
if (!out[media][pseudo]) {
out[media][pseudo] = {};
}
out[media][pseudo][property] = value;
}
});
return out;
}
/**
* processes, flattens, normalizes and diffs styles
*
* @param {Object} pluginInterface - plugin interface to process styles
* @param {Object} baseStyles - static base styles
* @return {Object} processed styles
*/
}, {
key: '_prepareStyles',
value: function _prepareStyles(pluginInterface, baseStyles, propsReference) {
var processedStyles = this._processStyles(pluginInterface);
var validatedStyles = this._validateStyles(processedStyles);
// only diff and extract dynamic styles
// if not actually rendering the base styles
if (propsReference !== '') {
return this._extractDynamicStyles(validatedStyles, baseStyles);
}
return validatedStyles;
}
/**
* generates an unique reference id by content hashing props
*
* @param {Object} props - props that get hashed
* @return {string} reference - unique props reference
*/
}, {
key: '_generatePropsReference',
value: function _generatePropsReference(props) {
return generateHash(sortedStringify(props));
}
/**
* renders clustered styles into a CSS string
*
* @param {Object} styles - prepared styles with pseudo keys
* @param {string} className - className reference to render
* @return {string} valid CSS string
*/
}, {
key: '_renderClusteredStyles',
value: function _renderClusteredStyles(styles, className) {
return Object.keys(styles).reduce(function (css, pseudo) {
return css + '.' + className + pseudo + '{' + cssifyObject(styles[pseudo]) + '}';
}, '');
}
/**
* renders keyframes into a CSS string with all prefixes
*
* @param {Object} frames - validated frame declarations
* @param {string} animationName - animation reference naming
* @return {string} valid CSS string
*/
}, {
key: '_renderKeyframe',
value: function _renderKeyframe(frames, animationName) {
var _this7 = this;
var keyframe = Object.keys(frames).reduce(function (css, percentage) {
return css + percentage + '{' + cssifyObject(_this7._validateStyles(frames[percentage])) + '}';
}, '');
return this.keyframePrefixes.reduce(function (css, prefix) {
return css + '@' + prefix + 'keyframes ' + animationName + '{' + keyframe + '}';
}, '');
}
/**
* renders a whole cache into a single CSS string
*
* @param {Map} cache - cache including all selector variations
* @return {string} valid CSS string
*/
}, {
key: '_renderCache',
value: function _renderCache(cache) {
var css = '';
cache.forEach(function (variation) {
variation.forEach(function (markup, propsReference) {
if (propsReference !== 'static') {
css += markup;
}
});
});
return css;
}
}]);
return StyleSheet;
}();
var formats = {
'.woff': 'woff',
'.eof': 'eof',
'.ttf': 'truetype',
'.svg': 'svg'
};
// Returns the font format for a specific font source
function getFontFormat(src) {
return Object.keys(formats).reduce(function (format, extension) {
if (src.indexOf(extension) > -1) {
format = formats[extension];
}
return format; // eslint-disable-line
}, undefined);
}
var FontFace = function () {
function FontFace(family, files) {
var properties = arguments.length <= 2 || arguments[2] === undefined ? {} : arguments[2];
babelHelpers.classCallCheck(this, FontFace);
this.family = family;
this.files = files;
this.properties = properties;
}
babelHelpers.createClass(FontFace, [{
key: 'render',
value: function render() {
var _this = this;
var font = {
fontFamily: '\'' + this.family + '\'',
src: this.files.map(function (src) {
return 'url(\'' + src + '\') format(\'' + getFontFormat(src) + '\')';
}).join(',')
};
var fontProperties = ['fontWeight', 'fontStretch', 'fontStyle', 'unicodeRange'];
Object.keys(this.properties).filter(function (prop) {
return fontProperties.indexOf(prop) > -1;
}).forEach(function (fontProp) {
return font[fontProp] = _this.properties[fontProp];
});
return font;
}
}]);
return FontFace;
}();
var Keyframe = function () {
/**
* Keyframe is a dynamic keyframe animation container
*
* @param {Function} composer - values to resolve dynamic styles
* @param {Function} keyframeComposer - composer function
*/
function Selector(composer) {
babelHelpers.classCallCheck(this, Selector);
function Keyframe(keyframeComposer) {
babelHelpers.classCallCheck(this, Keyframe);
this.composer = composer;
this.keyframeComposer = keyframeComposer;
}

@@ -77,3 +817,3 @@

babelHelpers.createClass(Selector, [{
babelHelpers.createClass(Keyframe, [{
key: "render",

@@ -83,32 +823,81 @@ value: function render() {

return this.composer(props);
return this.keyframeComposer(props);
}
}]);
return Selector;
return Keyframe;
}();
/**
* Enhances a Renderer to automatically render with a set of plugins
* @param {FelaRenderer} renderer - renderer that gets enhanced
* @param {function[]} plugins - array of plugin functions
* @return enhanced renderer
*/
function enhanceWithPlugins(renderer, plugins) {
// cache the initial render function to later refer to
// it would else get overwritten directly
var existingRenderFunction = renderer.render.bind(renderer);
renderer.render = function (selector, props) {
var additionalPlugins = arguments.length <= 2 || arguments[2] === undefined ? [] : arguments[2];
var NODE_TYPE = 1;
var NODE_NAME = 'STYLE';
// concat enhancing plugins with additional plugins to allow multiple
// enhancing cycles without loosing the ability to render with additional plugins
return existingRenderFunction(selector, props, plugins.concat(additionalPlugins));
};
var Renderer = function () {
function Renderer(node, config) {
var _this = this;
return renderer;
}
babelHelpers.classCallCheck(this, Renderer);
// Check if the passed node is a valid element node which allows
// setting the `textContent` property to update the node's content
if (node.nodeType !== NODE_TYPE || node.textContent === undefined || node.setAttribute instanceof Function === false) {
throw new Error('You need to specify a valid element node (nodeType = 1) to render into.');
}
warning$1(node.nodeName === NODE_NAME, 'You are using a node other than `<style>`. Your styles might not get applied correctly.');
warning$1(!node.hasAttribute('data-fela-stylesheet'), 'This node is already used by another renderer. Rendering might overwrite other styles.');
node.setAttribute('data-fela-stylesheet', '');
this.node = node;
this.stylesheet = new StyleSheet(config);
this.stylesheet.subscribe(function (css) {
return _this.node.textContent = css;
});
}
/**
* renders a Selector variation of props into a DOM node
*
* @param {Selector} selector - Selector instance that is rendered
* @param {Object?} props - list of props to render
* @param {Function[]?} plugins - array of plugins to process styles
* @return {string} className reference of the rendered selector
*/
babelHelpers.createClass(Renderer, [{
key: 'render',
value: function render(selector, props, plugins) {
if (selector instanceof FontFace) {
return this.stylesheet._renderFontFace(selector);
}
if (selector instanceof Keyframe) {
return this.stylesheet._renderKeyframeVariation(selector, props, plugins);
}
// renders the passed selector variation into the stylesheet which
// adds the variation to the cache and updates the DOM automatically
// if the variation has already been added it will do nothing but return
// the cached className to reference the mounted CSS selector
return this.stylesheet._renderSelectorVariation(selector, props, plugins);
}
/**
* clears the stylesheet associated with a DOM node
*/
}, {
key: 'clear',
value: function clear() {
this.stylesheet.clear();
this.node.textContent = '';
}
}]);
return Renderer;
}();
var fela = {
Selector: Selector,
enhanceWithPlugins: enhanceWithPlugins
Renderer: Renderer,
Keyframe: Keyframe,
FontFace: FontFace
};

@@ -115,0 +904,0 @@

2

dist/fela.min.js

@@ -1,1 +0,1 @@

!function(e,n){"object"==typeof exports&&"undefined"!=typeof module?module.exports=n():"function"==typeof define&&define.amd?define(n):e.Fela=n()}(this,function(){"use strict";function e(e,n){var t=e.render.bind(e);return e.render=function(e,r){var o=arguments.length<=2||void 0===arguments[2]?[]:arguments[2];return t(e,r,n.concat(o))},e}var n={};n["typeof"]="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol?"symbol":typeof e},n.classCallCheck=function(e,n){if(!(e instanceof n))throw new TypeError("Cannot call a class as a function")},n.createClass=function(){function e(e,n){for(var t=0;t<n.length;t++){var r=n[t];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(e,r.key,r)}}return function(n,t,r){return t&&e(n.prototype,t),r&&e(n,r),n}}(),n["extends"]=Object.assign||function(e){for(var n=1;n<arguments.length;n++){var t=arguments[n];for(var r in t)Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r])}return e};var t=function(){function e(t){n.classCallCheck(this,e),this.composer=t}return n.createClass(e,[{key:"render",value:function(){var e=arguments.length<=0||void 0===arguments[0]?{}:arguments[0];return this.composer(e)}}]),e}(),r={Selector:t,enhanceWithPlugins:e};return r});
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):e.Fela=t()}(this,function(){"use strict";function e(e,t){return t={exports:{}},e(t,t.exports),t.exports}function t(e){return e.replace(/([a-z]|^)([A-Z])/g,function(e,t,n){return t+"-"+n.toLowerCase()}).replace("ms-","-ms-")}function n(e){return Object.keys(e).reduce(function(n,r){return n.length>0&&(n+=";"),n+=t(r)+":"+e[r]},"")}function r(e){var t=0,n=0,r=void 0,i=e.length;if(0===i)return"";for(;i>n;++n)r=e.charCodeAt(n),t=(t<<5)-t+r,t|=0;return"-"+t.toString(36)}function i(e){return void 0===e?"":Object.keys(e).sort().reduce(function(t,n){return t+=n+e[n]},"")}function s(e){return Object.keys(h).reduce(function(t,n){return e.indexOf(n)>-1&&(t=h[n]),t},void 0)}var a={};a["typeof"]="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol?"symbol":typeof e},a.classCallCheck=function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")},a.createClass=function(){function e(e,t){for(var n=0;n<t.length;n++){var r=t[n];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(e,r.key,r)}}return function(t,n,r){return n&&e(t.prototype,n),r&&e(t,r),t}}(),a.defineProperty=function(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e},a["extends"]=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e};var o=e(function(e){function t(e){return function(){return e}}var n=function(){};n.thatReturns=t,n.thatReturnsFalse=t(!1),n.thatReturnsTrue=t(!0),n.thatReturnsNull=t(null),n.thatReturnsThis=function(){return this},n.thatReturnsArgument=function(e){return e},e.exports=n}),c=o&&"object"==typeof o&&"default"in o?o["default"]:o,u=(e(function(e){var t=c,n=t;e.exports=n}),function(e){return":"===e.charAt(0)}),f=function(e){return"@media"===e.substr(0,6)},l=function(){function e(){var t=arguments.length<=0||void 0===arguments[0]?{}:arguments[0];a.classCallCheck(this,e),this.listeners=new Set,this.keyframePrefixes=t.keyframePrefixes||["-webkit-","-moz-",""],this.plugins=t.plugins||[],this._init()}return a.createClass(e,[{key:"clear",value:function(){this._init()}},{key:"renderToString",value:function(){var e=this,t="";return this.fontFaces.forEach(function(e){return t+=e}),this.keyframes.forEach(function(e){e.forEach(function(e){return t+=e})}),t+=this._renderCache(this.cache),this.mediaCache.forEach(function(n,r){t+="@media "+r+"{"+e._renderCache(n)+"}"}),t}},{key:"subscribe",value:function(e){var t=this;return this.listeners.add(e),{unsubscribe:function(){return t.listeners["delete"](e)}}}},{key:"_emitChange",value:function(){var e=this.renderToString();this.listeners.forEach(function(t){return t(e)})}},{key:"_init",value:function(){this.cache=new Map,this.mediaCache=new Map,this.fontFaces=new Set,this.keyframes=new Map,this.ids=new Map,this._counter=-1}},{key:"_renderFontFace",value:function(e){if(!this.fontFaces.has(e)){var t="@font-face {"+n(e.render())+"}";this.fontFaces.add(t),this._emitChange()}return e.fontFamily}},{key:"_renderKeyframeVariation",value:function(e){var t=arguments.length<=1||void 0===arguments[1]?{}:arguments[1],n=arguments.length<=2||void 0===arguments[2]?[]:arguments[2];this.keyframes.has(e)||(this.keyframes.set(e,new Map),this.ids.set(e,++this._counter));var r=this.keyframes.get(e),i=this._generatePropsReference(t),s="k"+this.ids.get(e)+i;if(!r.has(i)){var a={plugins:this.plugins.concat(n),processStyles:this._processStyles,styles:e.render(t),props:t},o=this._processStyles(a);r.set(i,this._renderKeyframe(o,s)),this._emitChange()}return s}},{key:"_renderSelectorVariation",value:function(e){var t=this,n=arguments.length<=1||void 0===arguments[1]?{}:arguments[1],r=arguments.length<=2||void 0===arguments[2]?[]:arguments[2];this.cache.has(e)||(this.ids.set(e,++this._counter),this.cache.set(e,new Map),this._renderSelectorVariation(e,{},r));var i=this.cache.get(e),s=this._generatePropsReference(n),a="c"+this.ids.get(e)+s;i.has(s)||!function(){var o={plugins:t.plugins.concat(r),processStyles:t._processStyles,styles:e(n),props:n},c=t._prepareStyles(o,i.get("static"),s),u=t._clusterStyles(c);0===Object.keys(u).length&&i.set(s,""),Object.keys(u).forEach(function(n){var r=t._renderClusteredStyles(u[n],a);""===n?i.set(s,r):(t.mediaCache.has(n)||t.mediaCache.set(n,new Map([[e,new Map]])),t.mediaCache.get(n).has(e)||t.mediaCache.get(n).set(e,new Map),t.mediaCache.get(n).get(e).set(s,r))}),""===s&&i.set("static",c),t._emitChange()}();var o="c"+this.ids.get(e);return""===i.get(s)?o:a!==o?o+" "+a:a}},{key:"_processStyles",value:function(e){var t=e.plugins,n=e.styles;return t.forEach(function(t){return n=t(e)}),n}},{key:"_extractDynamicStyles",value:function(e,t){var n=this;return Object.keys(e).forEach(function(r){var i=e[r];i instanceof Object&&!Array.isArray(i)?(e[r]=n._extractDynamicStyles(e[r],t[r]),0===Object.keys(e[r]).length&&delete e[r]):t.hasOwnProperty(r)&&t[r]===i&&delete e[r]}),e}},{key:"_validateStyles",value:function(e){var t=this;return Object.keys(e).forEach(function(n){var r=e[n];r instanceof Object&&!Array.isArray(r)?(e[n]=u(n)||f(n)?t._validateStyles(r):{},0===Object.keys(e[n]).length&&delete e[n]):"string"!=typeof r&&"number"!=typeof r&&delete e[n]}),e}},{key:"_clusterStyles",value:function(e){var t=arguments.length<=1||void 0===arguments[1]?"":arguments[1],n=this,r=arguments.length<=2||void 0===arguments[2]?"":arguments[2],i=arguments.length<=3||void 0===arguments[3]?{}:arguments[3];return Object.keys(e).forEach(function(s){var o=e[s];if(o instanceof Object&&!Array.isArray(o)){if(u(s))n._clusterStyles(o,t+s,r,i);else if(f(s)){var c=s.slice(6).trim(),l=""!==r?r+" and "+c:c;n._clusterStyles(o,t,l,i)}}else i[r]||(i[r]=a.defineProperty({},t,{})),i[r][t]||(i[r][t]={}),i[r][t][s]=o}),i}},{key:"_prepareStyles",value:function(e,t,n){var r=this._processStyles(e),i=this._validateStyles(r);return""!==n?this._extractDynamicStyles(i,t):i}},{key:"_generatePropsReference",value:function(e){return r(i(e))}},{key:"_renderClusteredStyles",value:function(e,t){return Object.keys(e).reduce(function(r,i){return r+"."+t+i+"{"+n(e[i])+"}"},"")}},{key:"_renderKeyframe",value:function(e,t){var r=this,i=Object.keys(e).reduce(function(t,i){return t+i+"{"+n(r._validateStyles(e[i]))+"}"},"");return this.keyframePrefixes.reduce(function(e,n){return e+"@"+n+"keyframes "+t+"{"+i+"}"},"")}},{key:"_renderCache",value:function(e){var t="";return e.forEach(function(e){e.forEach(function(e,n){"static"!==n&&(t+=e)})}),t}}]),e}(),h={".woff":"woff",".eof":"eof",".ttf":"truetype",".svg":"svg"},y=function(){function e(t,n){var r=arguments.length<=2||void 0===arguments[2]?{}:arguments[2];a.classCallCheck(this,e),this.family=t,this.files=n,this.properties=r}return a.createClass(e,[{key:"render",value:function(){var e=this,t={fontFamily:"'"+this.family+"'",src:this.files.map(function(e){return"url('"+e+"') format('"+s(e)+"')"}).join(",")},n=["fontWeight","fontStretch","fontStyle","unicodeRange"];return Object.keys(this.properties).filter(function(e){return n.indexOf(e)>-1}).forEach(function(n){return t[n]=e.properties[n]}),t}}]),e}(),d=function(){function e(t){a.classCallCheck(this,e),this.keyframeComposer=t}return a.createClass(e,[{key:"render",value:function(){var e=arguments.length<=0||void 0===arguments[0]?{}:arguments[0];return this.keyframeComposer(e)}}]),e}(),v=1,p=function(){function e(t,n){var r=this;if(a.classCallCheck(this,e),t.nodeType!==v||void 0===t.textContent||t.setAttribute instanceof Function==!1)throw new Error("You need to specify a valid element node (nodeType = 1) to render into.");t.setAttribute("data-fela-stylesheet",""),this.node=t,this.stylesheet=new l(n),this.stylesheet.subscribe(function(e){return r.node.textContent=e})}return a.createClass(e,[{key:"render",value:function(e,t,n){return e instanceof y?this.stylesheet._renderFontFace(e):e instanceof d?this.stylesheet._renderKeyframeVariation(e,t,n):this.stylesheet._renderSelectorVariation(e,t,n)}},{key:"clear",value:function(){this.stylesheet.clear(),this.node.textContent=""}}]),e}(),m={Renderer:p,Keyframe:d,FontFace:y};return m});

@@ -7,16 +7,21 @@ 'use strict';

var _Selector = require('./components/shared/Selector');
var _DOMRenderer = require('./renderers/dom/DOMRenderer');
var _Selector2 = _interopRequireDefault(_Selector);
var _DOMRenderer2 = _interopRequireDefault(_DOMRenderer);
var _enhanceWithPlugins = require('./helpers/enhanceWithPlugins');
var _Keyframe = require('./components/dom/Keyframe');
var _enhanceWithPlugins2 = _interopRequireDefault(_enhanceWithPlugins);
var _Keyframe2 = _interopRequireDefault(_Keyframe);
var _FontFace = require('./components/dom/FontFace');
var _FontFace2 = _interopRequireDefault(_FontFace);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
exports.default = {
Selector: _Selector2.default,
enhanceWithPlugins: _enhanceWithPlugins2.default
Renderer: _DOMRenderer2.default,
Keyframe: _Keyframe2.default,
FontFace: _FontFace2.default
};
module.exports = exports['default'];

@@ -13,2 +13,6 @@ 'use strict';

var _warning = require('fbjs/lib/warning');
var _warning2 = _interopRequireDefault(_warning);
var _unitlessCssProperty = require('unitless-css-property');

@@ -33,2 +37,4 @@

process.env.NODE_ENV !== "production" ? (0, _warning2.default)(unit.match(/ch|em|ex|rem|vh|vw|vmin|vmax|px|cm|mm|in|pc|pt|mozmm|%/) === null, 'You are using an invalid unit `' + unit + '`. Consider using one of the following ch, em, ex, rem, vh, vw, vmin, vmax, px, cm, mm, in, pc, pt, mozmm or %.') : void 0;
return function (pluginInterface) {

@@ -35,0 +41,0 @@ var styles = pluginInterface.styles;

@@ -9,2 +9,6 @@ 'use strict';

var _warning = require('fbjs/lib/warning');
var _warning2 = _interopRequireDefault(_warning);
var _StyleSheet = require('./StyleSheet');

@@ -14,2 +18,10 @@

var _FontFace = require('../../components/dom/FontFace');
var _FontFace2 = _interopRequireDefault(_FontFace);
var _Keyframe = require('../../components/dom/Keyframe');
var _Keyframe2 = _interopRequireDefault(_Keyframe);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

@@ -23,3 +35,3 @@

var Renderer = function () {
function Renderer(node) {
function Renderer(node, config) {
var _this = this;

@@ -31,23 +43,13 @@

// setting the `textContent` property to update the node's content
if (node.nodeType !== NODE_TYPE || node.textContent === undefined) {
console.error('You need to specify a valid element node (nodeType = 1) to render into.'); // eslint-disable-line
return false;
if (node.nodeType !== NODE_TYPE || node.textContent === undefined || node.setAttribute instanceof Function === false) {
throw new Error('You need to specify a valid element node (nodeType = 1) to render into.');
}
// TODO: DEV-MODE
// In dev-mode we should allow using elements other than <style> as
// one might want to render the CSS markup into a visible node to be able to
// validate and observe the styles on runtime
if (node.nodeName !== NODE_NAME) {
console.warn('You are using a node other than `<style>`. Your styles might not get applied correctly.'); // eslint-disable-line
}
process.env.NODE_ENV !== "production" ? (0, _warning2.default)(node.nodeName === NODE_NAME, 'You are using a node other than `<style>`. Your styles might not get applied correctly.') : void 0;
process.env.NODE_ENV !== "production" ? (0, _warning2.default)(!node.hasAttribute('data-fela-stylesheet'), 'This node is already used by another renderer. Rendering might overwrite other styles.') : void 0;
if (node.hasAttribute('data-fela-stylesheet')) {
console.warn('This node is already used by another renderer. Rendering might overwrite other styles.'); // eslint-disable-line
}
node.setAttribute('data-fela-stylesheet', '');
this.node = node;
this.stylesheet = new _StyleSheet2.default();
this.stylesheet = new _StyleSheet2.default(config);
this.stylesheet.subscribe(function (css) {

@@ -57,2 +59,3 @@ return _this.node.textContent = css;

}
/**

@@ -71,2 +74,10 @@ * renders a Selector variation of props into a DOM node

value: function render(selector, props, plugins) {
if (selector instanceof _FontFace2.default) {
return this.stylesheet._renderFontFace(selector);
}
if (selector instanceof _Keyframe2.default) {
return this.stylesheet._renderKeyframeVariation(selector, props, plugins);
}
// renders the passed selector variation into the stylesheet which

@@ -73,0 +84,0 @@ // adds the variation to the cache and updates the DOM automatically

@@ -13,2 +13,10 @@ 'use strict';

var _FontFace = require('../../components/dom/FontFace');
var _FontFace2 = _interopRequireDefault(_FontFace);
var _Keyframe = require('../../components/dom/Keyframe');
var _Keyframe2 = _interopRequireDefault(_Keyframe);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

@@ -19,7 +27,8 @@

var Renderer = function () {
function Renderer() {
function Renderer(config) {
_classCallCheck(this, Renderer);
this.stylesheet = new _StyleSheet2.default();
this.stylesheet = new _StyleSheet2.default(config);
}
/**

@@ -38,2 +47,10 @@ * renders a Selector variation of props into a DOM node

value: function render(selector, props, plugins) {
if (selector instanceof _FontFace2.default) {
return this.stylesheet._renderFontFace(selector);
}
if (selector instanceof _Keyframe2.default) {
return this.stylesheet._renderKeyframeVariation(selector, props, plugins);
}
// renders the passed selector variation into the stylesheet which

@@ -50,2 +67,3 @@ // adds the variation to the cache and updates the DOM automatically

}
/**

@@ -52,0 +70,0 @@ * clears the stylesheet

@@ -9,16 +9,26 @@ 'use strict';

var _cssifyObject = require('./utils/cssifyObject');
var _cssifyObject = require('../../utils/cssifyObject');
var _cssifyObject2 = _interopRequireDefault(_cssifyObject);
var _generateContentHash = require('./utils/generateContentHash');
var _generateContentHash = require('../../utils/generateContentHash');
var _generateContentHash2 = _interopRequireDefault(_generateContentHash);
var _sortedStringify = require('./utils/sortedStringify');
var _sortedStringify = require('../../utils/sortedStringify');
var _sortedStringify2 = _interopRequireDefault(_sortedStringify);
var _isPseudo = require('../../utils/isPseudo');
var _isPseudo2 = _interopRequireDefault(_isPseudo);
var _isMediaQuery = require('../../utils/isMediaQuery');
var _isMediaQuery2 = _interopRequireDefault(_isMediaQuery);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

@@ -28,9 +38,14 @@

/**
* StyleSheet is a low-level Selector container
* StyleSheet is a low-level container to cache Selectors
* Keyframes and FontFaces which optimizes styles
*/
function StyleSheet() {
var config = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
_classCallCheck(this, StyleSheet);
this.listeners = new Set();
this.keyframePrefixes = config.keyframePrefixes || ['-webkit-', '-moz-', ''];
this.plugins = config.plugins || [];
this._init();

@@ -60,6 +75,16 @@ }

var css = this._renderCache(this.cache);
var css = '';
this.fontFaces.forEach(function (fontFace) {
return css += fontFace;
});
this.keyframes.forEach(function (variation) {
variation.forEach(function (markup) {
return css += markup;
});
});
css += this._renderCache(this.cache);
this.mediaCache.forEach(function (cache, media) {
css += _this._renderMediaQuery(media, _this._renderCache(cache));
css += '@media ' + media + '{' + _this._renderCache(cache) + '}';
});

@@ -83,3 +108,2 @@

this.listeners.add(callback);
return {

@@ -118,2 +142,4 @@ unsubscribe: function unsubscribe() {

this.mediaCache = new Map();
this.fontFaces = new Set();
this.keyframes = new Map();
this.ids = new Map();

@@ -124,2 +150,65 @@ this._counter = -1;

/**
* renders a new font-face and caches it
*
* @param {FontFace} fontFace - fontFace which gets rendered
* @return {string} fontFamily reference
*/
}, {
key: '_renderFontFace',
value: function _renderFontFace(fontFace) {
if (!this.fontFaces.has(fontFace)) {
var renderedFontFace = '@font-face {' + (0, _cssifyObject2.default)(fontFace.render()) + '}';
this.fontFaces.add(renderedFontFace);
this._emitChange();
}
return fontFace.fontFamily;
}
/**
* renders a new keyframe variation and caches the result
*
* @param {Keyframe} keyframe - Keyframe which gets rendered
* @param {Object?} props - properties used to render
* @param {Function[]?} plugins - array of plugins to process styles
* @return {string} animationName to reference the rendered keyframe
*/
}, {
key: '_renderKeyframeVariation',
value: function _renderKeyframeVariation(keyframe) {
var props = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1];
var plugins = arguments.length <= 2 || arguments[2] === undefined ? [] : arguments[2];
// rendering a Keyframe for the first time
// will create cache entries and an ID reference
if (!this.keyframes.has(keyframe)) {
this.keyframes.set(keyframe, new Map());
this.ids.set(keyframe, ++this._counter);
}
var cachedKeyframe = this.keyframes.get(keyframe);
var propsReference = this._generatePropsReference(props);
var animationName = 'k' + this.ids.get(keyframe) + propsReference;
// only if the cached selector has not already been rendered
// with a specific set of properties it actually renders
if (!cachedKeyframe.has(propsReference)) {
var pluginInterface = {
plugins: this.plugins.concat(plugins),
processStyles: this._processStyles,
styles: keyframe.render(props),
props: props
};
var processedKeyframe = this._processStyles(pluginInterface);
cachedKeyframe.set(propsReference, this._renderKeyframe(processedKeyframe, animationName));
this._emitChange();
}
return animationName;
}
/**
* renders a new selector variation and caches the result

@@ -141,5 +230,2 @@ *

var isFunctionalSelector = selector instanceof Function;
var isMediaSelector = !isFunctionalSelector && selector.renderMedia instanceof Function;
// rendering a Selector for the first time

@@ -151,12 +237,5 @@ // will create cache entries and an ID reference

// iterate all used media strings to create
// selector caches for each media as well
if (isMediaSelector) {
selector.mediaStrings.forEach(function (media) {
if (!_this3.mediaCache.has(media)) {
_this3.mediaCache.set(media, new Map());
}
_this3.mediaCache.get(media).set(selector, new Map());
});
}
// directly render the static base styles to be able
// to diff future dynamic styles with those
this._renderSelectorVariation(selector, {}, plugins);
}

@@ -166,5 +245,4 @@

var propsReference = this._generatePropsReference(props);
// uses the reference ID and the props to generate an unique className
var className = this._renderClassName(this.ids.get(selector), propsReference);
var className = 'c' + this.ids.get(selector) + propsReference;

@@ -178,19 +256,34 @@ // only if the cached selector has not already been rendered

var pluginInterface = {
plugins: plugins,
plugins: _this3.plugins.concat(plugins),
processStyles: _this3._processStyles,
styles: isFunctionalSelector ? selector(props) : selector.render(props),
className: className,
styles: selector(props),
props: props
};
cachedSelector.set(propsReference, _this3._processStyles(pluginInterface));
var preparedStyles = _this3._prepareStyles(pluginInterface, cachedSelector.get('static'), propsReference);
var clusteredStyles = _this3._clusterStyles(preparedStyles);
if (isMediaSelector) {
selector.mediaStrings.forEach(function (media) {
pluginInterface.styles = selector.renderMedia(props, media);
pluginInterface.media = media;
if (Object.keys(clusteredStyles).length === 0) {
cachedSelector.set(propsReference, '');
}
var processedStyles = _this3._processStyles(pluginInterface);
_this3.mediaCache.get(media).get(selector).set(propsReference, processedStyles);
});
Object.keys(clusteredStyles).forEach(function (media) {
var renderedStyles = _this3._renderClusteredStyles(clusteredStyles[media], className);
if (media === '') {
cachedSelector.set(propsReference, renderedStyles);
} else {
if (!_this3.mediaCache.has(media)) {
_this3.mediaCache.set(media, new Map([[selector, new Map()]]));
}
if (!_this3.mediaCache.get(media).has(selector)) {
_this3.mediaCache.get(media).set(selector, new Map());
}
_this3.mediaCache.get(media).get(selector).set(propsReference, renderedStyles);
}
});
// keep static styles to diff dynamic onces later on
if (propsReference === '') {
cachedSelector.set('static', preparedStyles);
}

@@ -203,3 +296,9 @@

return className;
var baseClassName = 'c' + this.ids.get(selector);
if (cachedSelector.get(propsReference) === '') {
return baseClassName;
}
// returns either the base className or both the base and the dynamic part
return className !== baseClassName ? baseClassName + ' ' + className : className;
}

@@ -211,3 +310,3 @@

* @param {Object} pluginInterface - interface containing relevant processing data
* @return {Object} processed and validated styles
* @return {Object} processed styles
*/

@@ -220,3 +319,2 @@

var styles = pluginInterface.styles;
// pipes each plugin by passes the plugin interface

@@ -227,5 +325,4 @@ // NOTE: as the styles are passed directly they're editable

plugins.forEach(function (plugin) {
return plugin(pluginInterface);
return styles = plugin(pluginInterface);
});
return styles;

@@ -235,45 +332,94 @@ }

/**
* generates an unique reference id by content hashing props
* extracts all dynamic styles by diffing with the static base styles
*
* @param {Object} props - props that get hashed
* @return {string} reference - unique props reference
* @param {Object} styles - dynamic styles
* @param {Object} base - static base styles to diff
* @return {Object} encapsulated dynamic styles
*/
}, {
key: '_generatePropsReference',
value: function _generatePropsReference(props) {
return (0, _generateContentHash2.default)((0, _sortedStringify2.default)(props));
key: '_extractDynamicStyles',
value: function _extractDynamicStyles(styles, base) {
var _this4 = this;
Object.keys(styles).forEach(function (property) {
var value = styles[property];
if (value instanceof Object && !Array.isArray(value)) {
// also diff inner objects such as pseudo classes
styles[property] = _this4._extractDynamicStyles(styles[property], base[property]);
if (Object.keys(styles[property]).length === 0) {
delete styles[property];
}
// checks if the base styles has the property and if the value is equal
} else if (base.hasOwnProperty(property) && base[property] === value) {
delete styles[property];
}
});
return styles;
}
/**
* generates an unique className using a Selectors reference ID
* as well as a content hash of the passed props
* removes every invalid property except pseudo class objects
*
* @param {number} id - Selectors reference ID stored within the stylesheet
* @param {strng} reference - generated props reference
* @return {string} className - unique className reference
* @param {Object} styles - styles to be validated
* @return {Object} validated styles
*/
}, {
key: '_renderClassName',
value: function _renderClassName(id, reference) {
return 'c' + id + '-' + reference;
key: '_validateStyles',
value: function _validateStyles(styles) {
var _this5 = this;
Object.keys(styles).forEach(function (property) {
var value = styles[property];
if (value instanceof Object && !Array.isArray(value)) {
styles[property] = (0, _isPseudo2.default)(property) || (0, _isMediaQuery2.default)(property) ? _this5._validateStyles(value) : {};
if (Object.keys(styles[property]).length === 0) {
delete styles[property];
}
} else if (typeof value !== 'string' && typeof value !== 'number') {
delete styles[property];
}
});
return styles;
}
/**
* flattens nested pseudo classes
* removes all invalid properties that are not either a string or a number
*
* @param {Object} styles - dynamic styles
* @return {Object} flat and validated styles
*/
}, {
key: '_splitPseudoClasses',
value: function _splitPseudoClasses(styles) {
var _this4 = this;
key: '_clusterStyles',
value: function _clusterStyles(styles) {
var pseudo = arguments.length <= 1 || arguments[1] === undefined ? '' : arguments[1];
var out = arguments.length <= 2 || arguments[2] === undefined ? {} : arguments[2];
var _this6 = this;
var media = arguments.length <= 2 || arguments[2] === undefined ? '' : arguments[2];
var out = arguments.length <= 3 || arguments[3] === undefined ? {} : arguments[3];
Object.keys(styles).forEach(function (property) {
var value = styles[property];
if (value instanceof Object) {
_this4._splitPseudoClasses(value, pseudo + property, out);
if (value instanceof Object && !Array.isArray(value)) {
if ((0, _isPseudo2.default)(property)) {
_this6._clusterStyles(value, pseudo + property, media, out);
} else if ((0, _isMediaQuery2.default)(property)) {
var query = property.slice(6).trim();
var nestedMedia = media !== '' ? media + ' and ' + query : query;
_this6._clusterStyles(value, pseudo, nestedMedia, out);
}
} else {
if (!out[pseudo]) {
out[pseudo] = {};
if (!out[media]) {
out[media] = _defineProperty({}, pseudo, {});
}
out[pseudo][property] = value;
if (!out[media][pseudo]) {
out[media][pseudo] = {};
}
out[media][pseudo][property] = value;
}

@@ -286,34 +432,42 @@ });

/**
* renders a single ruleset into a CSS string
* processes, flattens, normalizes and diffs styles
*
* @param {string} className - rendered selector
* @param {Object} styles - style declarations
* @return {string} valid selector CSS string
* @param {Object} pluginInterface - plugin interface to process styles
* @param {Object} baseStyles - static base styles
* @return {Object} processed styles
*/
}, {
key: '_renderSelector',
value: function _renderSelector(className, styles) {
return '.' + className + '{' + (0, _cssifyObject2.default)(styles) + '}';
key: '_prepareStyles',
value: function _prepareStyles(pluginInterface, baseStyles, propsReference) {
var processedStyles = this._processStyles(pluginInterface);
var validatedStyles = this._validateStyles(processedStyles);
// only diff and extract dynamic styles
// if not actually rendering the base styles
if (propsReference !== '') {
return this._extractDynamicStyles(validatedStyles, baseStyles);
}
return validatedStyles;
}
/**
* renders a set of media styles into a CSS string
* generates an unique reference id by content hashing props
*
* @param {string} media - media string
* @param {string} selectors - CSS string of all selectors
* @return {string} valid media query CSS string
* @param {Object} props - props that get hashed
* @return {string} reference - unique props reference
*/
}, {
key: '_renderMediaQuery',
value: function _renderMediaQuery(media, selectors) {
return '@media(' + media + '){' + selectors + '}';
key: '_generatePropsReference',
value: function _generatePropsReference(props) {
return (0, _generateContentHash2.default)((0, _sortedStringify2.default)(props));
}
/**
* renders a whole cache into a CSS string
* clusters media queries into single @media groups
* renders clustered styles into a CSS string
*
* @param {Map} cache - cache including styles and media styles
* @param {Object} styles - prepared styles with pseudo keys
* @param {string} className - className reference to render
* @return {string} valid CSS string

@@ -323,18 +477,48 @@ */

}, {
key: '_renderClusteredStyles',
value: function _renderClusteredStyles(styles, className) {
return Object.keys(styles).reduce(function (css, pseudo) {
return css + '.' + className + pseudo + '{' + (0, _cssifyObject2.default)(styles[pseudo]) + '}';
}, '');
}
/**
* renders keyframes into a CSS string with all prefixes
*
* @param {Object} frames - validated frame declarations
* @param {string} animationName - animation reference naming
* @return {string} valid CSS string
*/
}, {
key: '_renderKeyframe',
value: function _renderKeyframe(frames, animationName) {
var _this7 = this;
var keyframe = Object.keys(frames).reduce(function (css, percentage) {
return css + percentage + '{' + (0, _cssifyObject2.default)(_this7._validateStyles(frames[percentage])) + '}';
}, '');
return this.keyframePrefixes.reduce(function (css, prefix) {
return css + '@' + prefix + 'keyframes ' + animationName + '{' + keyframe + '}';
}, '');
}
/**
* renders a whole cache into a single CSS string
*
* @param {Map} cache - cache including all selector variations
* @return {string} valid CSS string
*/
}, {
key: '_renderCache',
value: function _renderCache(cache) {
var _this5 = this;
var css = '';
cache.forEach(function (variation, selector) {
var id = _this5.ids.get(selector);
variation.forEach(function (styles, propsReference) {
var className = _this5._renderClassName(id, propsReference);
var splitPseudos = _this5._splitPseudoClasses(styles);
Object.keys(splitPseudos).forEach(function (pseudo) {
css += _this5._renderSelector(className + pseudo, splitPseudos[pseudo]);
});
cache.forEach(function (variation) {
variation.forEach(function (markup, propsReference) {
if (propsReference !== 'static') {
css += markup;
}
});

@@ -341,0 +525,0 @@ });

{
"name": "fela",
"version": "1.0.0-alpha.5",
"version": "1.0.0-alpha.6",
"description": "Fast, tiny & dynamic low-level API to handle Styling in JavaScript",
"main": "lib/fela.js",
"main": "index.js",
"files": [

@@ -7,0 +7,0 @@ "LICENSE",

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc