2295 lines
60 KiB
JavaScript
2295 lines
60 KiB
JavaScript
(function (global, factory) {
|
|
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
|
|
typeof define === 'function' && define.amd ? define(['exports'], factory) :
|
|
(factory((global.jss = {})));
|
|
}(this, (function (exports) { 'use strict';
|
|
|
|
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
|
|
|
|
var isBrowser = (typeof window === "undefined" ? "undefined" : _typeof(window)) === "object" && (typeof document === "undefined" ? "undefined" : _typeof(document)) === 'object' && document.nodeType === 9;
|
|
|
|
/**
|
|
* Link rule with CSSStyleRule and nested rules with corresponding nested cssRules if both exists.
|
|
*/
|
|
function linkRule(rule, cssRule) {
|
|
rule.renderable = cssRule;
|
|
if (rule.rules && cssRule.cssRules) rule.rules.link(cssRule.cssRules);
|
|
}
|
|
|
|
var global$1 = (typeof global !== "undefined" ? global :
|
|
typeof self !== "undefined" ? self :
|
|
typeof window !== "undefined" ? window : {});
|
|
|
|
if (typeof global$1.setTimeout === 'function') ;
|
|
if (typeof global$1.clearTimeout === 'function') ;
|
|
|
|
// from https://github.com/kumavis/browser-process-hrtime/blob/master/index.js
|
|
var performance = global$1.performance || {};
|
|
var performanceNow =
|
|
performance.now ||
|
|
performance.mozNow ||
|
|
performance.msNow ||
|
|
performance.oNow ||
|
|
performance.webkitNow ||
|
|
function(){ return (new Date()).getTime() };
|
|
|
|
/**
|
|
* 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 __DEV__ = "development" !== 'production';
|
|
|
|
var warning = function() {};
|
|
|
|
if (__DEV__) {
|
|
warning = function(condition, format, args) {
|
|
var len = arguments.length;
|
|
args = new Array(len > 2 ? len - 2 : 0);
|
|
for (var 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.length < 10 || (/^[s\W]*$/).test(format)) {
|
|
throw new Error(
|
|
'The warning format should be able to uniquely identify this ' +
|
|
'warning. Please, use a more descriptive format than: ' + format
|
|
);
|
|
}
|
|
|
|
if (!condition) {
|
|
var argIndex = 0;
|
|
var message = 'Warning: ' +
|
|
format.replace(/%s/g, function() {
|
|
return args[argIndex++];
|
|
});
|
|
if (typeof console !== 'undefined') {
|
|
console.error(message);
|
|
}
|
|
try {
|
|
// 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) {}
|
|
}
|
|
};
|
|
}
|
|
|
|
var warning_1 = warning;
|
|
|
|
var join = function join(value, by) {
|
|
var result = '';
|
|
for (var i = 0; i < value.length; i++) {
|
|
// Remove !important from the value, it will be readded later.
|
|
if (value[i] === '!important') break;
|
|
if (result) result += by;
|
|
result += value[i];
|
|
}
|
|
return result;
|
|
};
|
|
|
|
/**
|
|
* Converts array values to string.
|
|
*
|
|
* `margin: [['5px', '10px']]` > `margin: 5px 10px;`
|
|
* `border: ['1px', '2px']` > `border: 1px, 2px;`
|
|
* `margin: [['5px', '10px'], '!important']` > `margin: 5px 10px !important;`
|
|
* `color: ['red', !important]` > `color: red !important;`
|
|
*/
|
|
function toCssValue(value) {
|
|
var ignoreImportant = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
|
|
|
|
if (!Array.isArray(value)) return value;
|
|
|
|
var cssValue = '';
|
|
|
|
// Support space separated values via `[['5px', '10px']]`.
|
|
if (Array.isArray(value[0])) {
|
|
for (var i = 0; i < value.length; i++) {
|
|
if (value[i] === '!important') break;
|
|
if (cssValue) cssValue += ', ';
|
|
cssValue += join(value[i], ' ');
|
|
}
|
|
} else cssValue = join(value, ', ');
|
|
|
|
// Add !important, because it was ignored.
|
|
if (!ignoreImportant && value[value.length - 1] === '!important') {
|
|
cssValue += ' !important';
|
|
}
|
|
|
|
return cssValue;
|
|
}
|
|
|
|
/**
|
|
* Indent a string.
|
|
* http://jsperf.com/array-join-vs-for
|
|
*/
|
|
function indentStr(str, indent) {
|
|
var result = '';
|
|
for (var index = 0; index < indent; index++) {
|
|
result += ' ';
|
|
}return result + str;
|
|
}
|
|
|
|
/**
|
|
* Converts a Rule to CSS string.
|
|
*/
|
|
function toCss(selector, style) {
|
|
var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
|
|
var result = '';
|
|
|
|
if (!style) return result;
|
|
|
|
var _options$indent = options.indent,
|
|
indent = _options$indent === undefined ? 0 : _options$indent;
|
|
var fallbacks = style.fallbacks;
|
|
|
|
|
|
indent++;
|
|
|
|
// Apply fallbacks first.
|
|
if (fallbacks) {
|
|
// Array syntax {fallbacks: [{prop: value}]}
|
|
if (Array.isArray(fallbacks)) {
|
|
for (var index = 0; index < fallbacks.length; index++) {
|
|
var fallback = fallbacks[index];
|
|
for (var prop in fallback) {
|
|
var value = fallback[prop];
|
|
if (value != null) {
|
|
result += '\n' + indentStr(prop + ': ' + toCssValue(value) + ';', indent);
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
// Object syntax {fallbacks: {prop: value}}
|
|
for (var _prop in fallbacks) {
|
|
var _value = fallbacks[_prop];
|
|
if (_value != null) {
|
|
result += '\n' + indentStr(_prop + ': ' + toCssValue(_value) + ';', indent);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for (var _prop2 in style) {
|
|
var _value2 = style[_prop2];
|
|
if (_value2 != null && _prop2 !== 'fallbacks') {
|
|
result += '\n' + indentStr(_prop2 + ': ' + toCssValue(_value2) + ';', indent);
|
|
}
|
|
}
|
|
|
|
// Allow empty style in this case, because properties will be added dynamically.
|
|
if (!result && !options.allowEmpty) return result;
|
|
|
|
indent--;
|
|
result = indentStr(selector + ' {' + result + '\n', indent) + indentStr('}', indent);
|
|
|
|
return result;
|
|
}
|
|
|
|
var _typeof$1 = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) {
|
|
return typeof obj;
|
|
} : function (obj) {
|
|
return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
|
|
};
|
|
|
|
var classCallCheck = function (instance, Constructor) {
|
|
if (!(instance instanceof Constructor)) {
|
|
throw new TypeError("Cannot call a class as a function");
|
|
}
|
|
};
|
|
|
|
var createClass = function () {
|
|
function defineProperties(target, props) {
|
|
for (var i = 0; i < props.length; i++) {
|
|
var descriptor = props[i];
|
|
descriptor.enumerable = descriptor.enumerable || false;
|
|
descriptor.configurable = true;
|
|
if ("value" in descriptor) descriptor.writable = true;
|
|
Object.defineProperty(target, descriptor.key, descriptor);
|
|
}
|
|
}
|
|
|
|
return function (Constructor, protoProps, staticProps) {
|
|
if (protoProps) defineProperties(Constructor.prototype, protoProps);
|
|
if (staticProps) defineProperties(Constructor, staticProps);
|
|
return Constructor;
|
|
};
|
|
}();
|
|
|
|
var _extends = Object.assign || function (target) {
|
|
for (var i = 1; i < arguments.length; i++) {
|
|
var source = arguments[i];
|
|
|
|
for (var key in source) {
|
|
if (Object.prototype.hasOwnProperty.call(source, key)) {
|
|
target[key] = source[key];
|
|
}
|
|
}
|
|
}
|
|
|
|
return target;
|
|
};
|
|
|
|
var StyleRule = function () {
|
|
function StyleRule(key, style, options) {
|
|
classCallCheck(this, StyleRule);
|
|
this.type = 'style';
|
|
this.isProcessed = false;
|
|
var sheet = options.sheet,
|
|
Renderer = options.Renderer,
|
|
selector = options.selector;
|
|
|
|
this.key = key;
|
|
this.options = options;
|
|
this.style = style;
|
|
if (selector) this.selectorText = selector;
|
|
this.renderer = sheet ? sheet.renderer : new Renderer();
|
|
}
|
|
|
|
/**
|
|
* Set selector string.
|
|
* Attention: use this with caution. Most browsers didn't implement
|
|
* selectorText setter, so this may result in rerendering of entire Style Sheet.
|
|
*/
|
|
|
|
|
|
createClass(StyleRule, [{
|
|
key: 'prop',
|
|
|
|
|
|
/**
|
|
* Get or set a style property.
|
|
*/
|
|
value: function prop(name, value) {
|
|
// It's a getter.
|
|
if (value === undefined) return this.style[name];
|
|
|
|
// Don't do anything if the value has not changed.
|
|
if (this.style[name] === value) return this;
|
|
|
|
value = this.options.jss.plugins.onChangeValue(value, name, this);
|
|
|
|
var isEmpty = value == null || value === false;
|
|
var isDefined = name in this.style;
|
|
|
|
// Value is empty and wasn't defined before.
|
|
if (isEmpty && !isDefined) return this;
|
|
|
|
// We are going to remove this value.
|
|
var remove = isEmpty && isDefined;
|
|
|
|
if (remove) delete this.style[name];else this.style[name] = value;
|
|
|
|
// Renderable is defined if StyleSheet option `link` is true.
|
|
if (this.renderable) {
|
|
if (remove) this.renderer.removeProperty(this.renderable, name);else this.renderer.setProperty(this.renderable, name, value);
|
|
return this;
|
|
}
|
|
|
|
var sheet = this.options.sheet;
|
|
|
|
if (sheet && sheet.attached) {
|
|
warning_1(false, 'Rule is not linked. Missing sheet option "link: true".');
|
|
}
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Apply rule to an element inline.
|
|
*/
|
|
|
|
}, {
|
|
key: 'applyTo',
|
|
value: function applyTo(renderable) {
|
|
var json = this.toJSON();
|
|
for (var prop in json) {
|
|
this.renderer.setProperty(renderable, prop, json[prop]);
|
|
}return this;
|
|
}
|
|
|
|
/**
|
|
* Returns JSON representation of the rule.
|
|
* Fallbacks are not supported.
|
|
* Useful for inline styles.
|
|
*/
|
|
|
|
}, {
|
|
key: 'toJSON',
|
|
value: function toJSON() {
|
|
var json = {};
|
|
for (var prop in this.style) {
|
|
var value = this.style[prop];
|
|
if ((typeof value === 'undefined' ? 'undefined' : _typeof$1(value)) !== 'object') json[prop] = value;else if (Array.isArray(value)) json[prop] = toCssValue(value);
|
|
}
|
|
return json;
|
|
}
|
|
|
|
/**
|
|
* Generates a CSS string.
|
|
*/
|
|
|
|
}, {
|
|
key: 'toString',
|
|
value: function toString(options) {
|
|
var sheet = this.options.sheet;
|
|
|
|
var link = sheet ? sheet.options.link : false;
|
|
var opts = link ? _extends({}, options, { allowEmpty: true }) : options;
|
|
return toCss(this.selector, this.style, opts);
|
|
}
|
|
}, {
|
|
key: 'selector',
|
|
set: function set$$1(selector) {
|
|
if (selector === this.selectorText) return;
|
|
|
|
this.selectorText = selector;
|
|
|
|
if (!this.renderable) return;
|
|
|
|
var hasChanged = this.renderer.setSelector(this.renderable, selector);
|
|
|
|
// If selector setter is not implemented, rerender the rule.
|
|
if (!hasChanged && this.renderable) {
|
|
var renderable = this.renderer.replaceRule(this.renderable, this);
|
|
if (renderable) this.renderable = renderable;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get selector string.
|
|
*/
|
|
,
|
|
get: function get$$1() {
|
|
return this.selectorText;
|
|
}
|
|
}]);
|
|
return StyleRule;
|
|
}();
|
|
|
|
function unwrapExports (x) {
|
|
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
|
|
}
|
|
|
|
function createCommonjsModule(fn, module) {
|
|
return module = { exports: {} }, fn(module, module.exports), module.exports;
|
|
}
|
|
|
|
var ponyfill = createCommonjsModule(function (module, exports) {
|
|
|
|
Object.defineProperty(exports, "__esModule", {
|
|
value: true
|
|
});
|
|
exports['default'] = symbolObservablePonyfill;
|
|
function symbolObservablePonyfill(root) {
|
|
var result;
|
|
var _Symbol = root.Symbol;
|
|
|
|
if (typeof _Symbol === 'function') {
|
|
if (_Symbol.observable) {
|
|
result = _Symbol.observable;
|
|
} else {
|
|
result = _Symbol('observable');
|
|
_Symbol.observable = result;
|
|
}
|
|
} else {
|
|
result = '@@observable';
|
|
}
|
|
|
|
return result;
|
|
}});
|
|
|
|
unwrapExports(ponyfill);
|
|
|
|
var lib = createCommonjsModule(function (module, exports) {
|
|
|
|
Object.defineProperty(exports, "__esModule", {
|
|
value: true
|
|
});
|
|
|
|
|
|
|
|
var _ponyfill2 = _interopRequireDefault(ponyfill);
|
|
|
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
|
|
|
|
var root; /* global window */
|
|
|
|
|
|
if (typeof self !== 'undefined') {
|
|
root = self;
|
|
} else if (typeof window !== 'undefined') {
|
|
root = window;
|
|
} else if (typeof global$1 !== 'undefined') {
|
|
root = global$1;
|
|
} else {
|
|
root = module;
|
|
}
|
|
|
|
var result = (0, _ponyfill2['default'])(root);
|
|
exports['default'] = result;
|
|
});
|
|
|
|
unwrapExports(lib);
|
|
|
|
var symbolObservable = lib;
|
|
|
|
var isObservable = (function (value) {
|
|
return value && value[symbolObservable] && value === value[symbolObservable]();
|
|
});
|
|
|
|
var isArray = Array.isArray;
|
|
|
|
|
|
function cloneStyle(style) {
|
|
// Support empty values in case user ends up with them by accident.
|
|
if (style == null) return style;
|
|
|
|
// Support string value for SimpleRule.
|
|
var typeOfStyle = typeof style === 'undefined' ? 'undefined' : _typeof$1(style);
|
|
|
|
if (typeOfStyle === 'string' || typeOfStyle === 'number' || typeOfStyle === 'function') {
|
|
return style;
|
|
}
|
|
|
|
// Support array for FontFaceRule.
|
|
if (isArray(style)) return style.map(cloneStyle);
|
|
|
|
// Support Observable styles. Observables are immutable, so we don't need to
|
|
// copy them.
|
|
if (isObservable(style)) return style;
|
|
|
|
var newStyle = {};
|
|
for (var name in style) {
|
|
var value = style[name];
|
|
if ((typeof value === 'undefined' ? 'undefined' : _typeof$1(value)) === 'object') {
|
|
newStyle[name] = cloneStyle(value);
|
|
continue;
|
|
}
|
|
newStyle[name] = value;
|
|
}
|
|
|
|
return newStyle;
|
|
}
|
|
|
|
/**
|
|
* Create a rule instance.
|
|
*/
|
|
function createRule() {
|
|
var name = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'unnamed';
|
|
var decl = arguments[1];
|
|
var options = arguments[2];
|
|
var jss = options.jss;
|
|
|
|
var declCopy = cloneStyle(decl);
|
|
|
|
var rule = jss.plugins.onCreateRule(name, declCopy, options);
|
|
if (rule) return rule;
|
|
|
|
// It is an at-rule and it has no instance.
|
|
if (name[0] === '@') {
|
|
warning_1(false, '[JSS] Unknown at-rule %s', name);
|
|
}
|
|
|
|
return new StyleRule(name, declCopy, options);
|
|
}
|
|
|
|
var CSS = global$1.CSS;
|
|
|
|
var env$1 = "development";
|
|
|
|
var escapeRegex = /([[\].#*$><+~=|^:(),"'`])/g;
|
|
|
|
var escape = (function (str) {
|
|
// We don't need to escape it in production, because we are not using user's
|
|
// input for selectors, we are generating a valid selector.
|
|
if (env$1 === 'production') return str;
|
|
|
|
if (!CSS || !CSS.escape) {
|
|
return str.replace(escapeRegex, '\\$1');
|
|
}
|
|
|
|
return CSS.escape(str);
|
|
});
|
|
|
|
/**
|
|
* Contains rules objects and allows adding/removing etc.
|
|
* Is used for e.g. by `StyleSheet` or `ConditionalRule`.
|
|
*/
|
|
var RuleList = function () {
|
|
|
|
// Original styles object.
|
|
function RuleList(options) {
|
|
var _this = this;
|
|
|
|
classCallCheck(this, RuleList);
|
|
this.map = {};
|
|
this.raw = {};
|
|
this.index = [];
|
|
|
|
this.update = function (name, data) {
|
|
var _options = _this.options,
|
|
plugins = _options.jss.plugins,
|
|
sheet = _options.sheet;
|
|
|
|
if (typeof name === 'string') {
|
|
plugins.onUpdate(data, _this.get(name), sheet);
|
|
} else {
|
|
for (var index = 0; index < _this.index.length; index++) {
|
|
plugins.onUpdate(name, _this.index[index], sheet);
|
|
}
|
|
}
|
|
};
|
|
|
|
this.options = options;
|
|
this.classes = options.classes;
|
|
}
|
|
|
|
/**
|
|
* Create and register rule.
|
|
*
|
|
* Will not render after Style Sheet was rendered the first time.
|
|
*/
|
|
|
|
|
|
// Used to ensure correct rules order.
|
|
|
|
// Rules registry for access by .get() method.
|
|
// It contains the same rule registered by name and by selector.
|
|
|
|
|
|
createClass(RuleList, [{
|
|
key: 'add',
|
|
value: function add(name, decl, options) {
|
|
var _options2 = this.options,
|
|
parent = _options2.parent,
|
|
sheet = _options2.sheet,
|
|
jss = _options2.jss,
|
|
Renderer = _options2.Renderer,
|
|
generateClassName = _options2.generateClassName;
|
|
|
|
|
|
options = _extends({
|
|
classes: this.classes,
|
|
parent: parent,
|
|
sheet: sheet,
|
|
jss: jss,
|
|
Renderer: Renderer,
|
|
generateClassName: generateClassName
|
|
}, options);
|
|
|
|
if (!options.selector && this.classes[name]) {
|
|
options.selector = '.' + escape(this.classes[name]);
|
|
}
|
|
|
|
this.raw[name] = decl;
|
|
|
|
var rule = createRule(name, decl, options);
|
|
|
|
var className = void 0;
|
|
|
|
if (!options.selector && rule instanceof StyleRule) {
|
|
className = generateClassName(rule, sheet);
|
|
rule.selector = '.' + escape(className);
|
|
}
|
|
|
|
this.register(rule, className);
|
|
|
|
var index = options.index === undefined ? this.index.length : options.index;
|
|
this.index.splice(index, 0, rule);
|
|
|
|
return rule;
|
|
}
|
|
|
|
/**
|
|
* Get a rule.
|
|
*/
|
|
|
|
}, {
|
|
key: 'get',
|
|
value: function get$$1(name) {
|
|
return this.map[name];
|
|
}
|
|
|
|
/**
|
|
* Delete a rule.
|
|
*/
|
|
|
|
}, {
|
|
key: 'remove',
|
|
value: function remove(rule) {
|
|
this.unregister(rule);
|
|
this.index.splice(this.indexOf(rule), 1);
|
|
}
|
|
|
|
/**
|
|
* Get index of a rule.
|
|
*/
|
|
|
|
}, {
|
|
key: 'indexOf',
|
|
value: function indexOf(rule) {
|
|
return this.index.indexOf(rule);
|
|
}
|
|
|
|
/**
|
|
* Run `onProcessRule()` plugins on every rule.
|
|
*/
|
|
|
|
}, {
|
|
key: 'process',
|
|
value: function process() {
|
|
var plugins = this.options.jss.plugins;
|
|
// We need to clone array because if we modify the index somewhere else during a loop
|
|
// we end up with very hard-to-track-down side effects.
|
|
|
|
this.index.slice(0).forEach(plugins.onProcessRule, plugins);
|
|
}
|
|
|
|
/**
|
|
* Register a rule in `.map` and `.classes` maps.
|
|
*/
|
|
|
|
}, {
|
|
key: 'register',
|
|
value: function register(rule, className) {
|
|
this.map[rule.key] = rule;
|
|
if (rule instanceof StyleRule) {
|
|
this.map[rule.selector] = rule;
|
|
if (className) this.classes[rule.key] = className;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Unregister a rule.
|
|
*/
|
|
|
|
}, {
|
|
key: 'unregister',
|
|
value: function unregister(rule) {
|
|
delete this.map[rule.key];
|
|
if (rule instanceof StyleRule) {
|
|
delete this.map[rule.selector];
|
|
delete this.classes[rule.key];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Update the function values with a new data.
|
|
*/
|
|
|
|
}, {
|
|
key: 'link',
|
|
|
|
|
|
/**
|
|
* Link renderable rules with CSSRuleList.
|
|
*/
|
|
value: function link(cssRules) {
|
|
var map = this.options.sheet.renderer.getUnescapedKeysMap(this.index);
|
|
|
|
for (var i = 0; i < cssRules.length; i++) {
|
|
var cssRule = cssRules[i];
|
|
var _key = this.options.sheet.renderer.getKey(cssRule);
|
|
if (map[_key]) _key = map[_key];
|
|
var rule = this.map[_key];
|
|
if (rule) linkRule(rule, cssRule);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Convert rules to a CSS string.
|
|
*/
|
|
|
|
}, {
|
|
key: 'toString',
|
|
value: function toString(options) {
|
|
var str = '';
|
|
var sheet = this.options.sheet;
|
|
|
|
var link = sheet ? sheet.options.link : false;
|
|
|
|
for (var index = 0; index < this.index.length; index++) {
|
|
var rule = this.index[index];
|
|
var css = rule.toString(options);
|
|
|
|
// No need to render an empty rule.
|
|
if (!css && !link) continue;
|
|
|
|
if (str) str += '\n';
|
|
str += css;
|
|
}
|
|
|
|
return str;
|
|
}
|
|
}]);
|
|
return RuleList;
|
|
}();
|
|
|
|
/* eslint-disable-next-line no-use-before-define */
|
|
|
|
var StyleSheet = function () {
|
|
function StyleSheet(styles, options) {
|
|
var _this = this;
|
|
|
|
classCallCheck(this, StyleSheet);
|
|
|
|
this.update = function (name, data) {
|
|
if (typeof name === 'string') {
|
|
_this.rules.update(name, data);
|
|
} else {
|
|
_this.rules.update(name);
|
|
}
|
|
return _this;
|
|
};
|
|
|
|
this.attached = false;
|
|
this.deployed = false;
|
|
this.linked = false;
|
|
this.classes = {};
|
|
this.options = _extends({}, options, {
|
|
sheet: this,
|
|
parent: this,
|
|
classes: this.classes
|
|
});
|
|
this.renderer = new options.Renderer(this);
|
|
this.rules = new RuleList(this.options);
|
|
|
|
for (var _name in styles) {
|
|
this.rules.add(_name, styles[_name]);
|
|
}
|
|
|
|
this.rules.process();
|
|
}
|
|
|
|
/**
|
|
* Attach renderable to the render tree.
|
|
*/
|
|
|
|
|
|
createClass(StyleSheet, [{
|
|
key: 'attach',
|
|
value: function attach() {
|
|
if (this.attached) return this;
|
|
if (!this.deployed) this.deploy();
|
|
this.renderer.attach();
|
|
if (!this.linked && this.options.link) this.link();
|
|
this.attached = true;
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Remove renderable from render tree.
|
|
*/
|
|
|
|
}, {
|
|
key: 'detach',
|
|
value: function detach() {
|
|
if (!this.attached) return this;
|
|
this.renderer.detach();
|
|
this.attached = false;
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Add a rule to the current stylesheet.
|
|
* Will insert a rule also after the stylesheet has been rendered first time.
|
|
*/
|
|
|
|
}, {
|
|
key: 'addRule',
|
|
value: function addRule(name, decl, options) {
|
|
var queue = this.queue;
|
|
|
|
// Plugins can create rules.
|
|
// In order to preserve the right order, we need to queue all `.addRule` calls,
|
|
// which happen after the first `rules.add()` call.
|
|
|
|
if (this.attached && !queue) this.queue = [];
|
|
|
|
var rule = this.rules.add(name, decl, options);
|
|
this.options.jss.plugins.onProcessRule(rule);
|
|
|
|
if (this.attached) {
|
|
if (!this.deployed) return rule;
|
|
// Don't insert rule directly if there is no stringified version yet.
|
|
// It will be inserted all together when .attach is called.
|
|
if (queue) queue.push(rule);else {
|
|
this.insertRule(rule);
|
|
if (this.queue) {
|
|
this.queue.forEach(this.insertRule, this);
|
|
this.queue = undefined;
|
|
}
|
|
}
|
|
return rule;
|
|
}
|
|
|
|
// We can't add rules to a detached style node.
|
|
// We will redeploy the sheet once user will attach it.
|
|
this.deployed = false;
|
|
|
|
return rule;
|
|
}
|
|
|
|
/**
|
|
* Insert rule into the StyleSheet
|
|
*/
|
|
|
|
}, {
|
|
key: 'insertRule',
|
|
value: function insertRule(rule) {
|
|
var renderable = this.renderer.insertRule(rule);
|
|
if (renderable && this.options.link) linkRule(rule, renderable);
|
|
}
|
|
|
|
/**
|
|
* Create and add rules.
|
|
* Will render also after Style Sheet was rendered the first time.
|
|
*/
|
|
|
|
}, {
|
|
key: 'addRules',
|
|
value: function addRules(styles, options) {
|
|
var added = [];
|
|
for (var _name2 in styles) {
|
|
added.push(this.addRule(_name2, styles[_name2], options));
|
|
}
|
|
return added;
|
|
}
|
|
|
|
/**
|
|
* Get a rule by name.
|
|
*/
|
|
|
|
}, {
|
|
key: 'getRule',
|
|
value: function getRule(name) {
|
|
return this.rules.get(name);
|
|
}
|
|
|
|
/**
|
|
* Delete a rule by name.
|
|
* Returns `true`: if rule has been deleted from the DOM.
|
|
*/
|
|
|
|
}, {
|
|
key: 'deleteRule',
|
|
value: function deleteRule(name) {
|
|
var rule = this.rules.get(name);
|
|
|
|
if (!rule) return false;
|
|
|
|
this.rules.remove(rule);
|
|
|
|
if (this.attached && rule.renderable) {
|
|
return this.renderer.deleteRule(rule.renderable);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Get index of a rule.
|
|
*/
|
|
|
|
}, {
|
|
key: 'indexOf',
|
|
value: function indexOf(rule) {
|
|
return this.rules.indexOf(rule);
|
|
}
|
|
|
|
/**
|
|
* Deploy pure CSS string to a renderable.
|
|
*/
|
|
|
|
}, {
|
|
key: 'deploy',
|
|
value: function deploy() {
|
|
this.renderer.deploy();
|
|
this.deployed = true;
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Link renderable CSS rules from sheet with their corresponding models.
|
|
*/
|
|
|
|
}, {
|
|
key: 'link',
|
|
value: function link() {
|
|
var cssRules = this.renderer.getRules();
|
|
|
|
// Is undefined when VirtualRenderer is used.
|
|
if (cssRules) this.rules.link(cssRules);
|
|
this.linked = true;
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Update the function values with a new data.
|
|
*/
|
|
|
|
}, {
|
|
key: 'toString',
|
|
|
|
|
|
/**
|
|
* Convert rules to a CSS string.
|
|
*/
|
|
value: function toString(options) {
|
|
return this.rules.toString(options);
|
|
}
|
|
}]);
|
|
return StyleSheet;
|
|
}();
|
|
|
|
var PluginsRegistry = function () {
|
|
function PluginsRegistry() {
|
|
classCallCheck(this, PluginsRegistry);
|
|
this.hooks = {
|
|
onCreateRule: [],
|
|
onProcessRule: [],
|
|
onProcessStyle: [],
|
|
onProcessSheet: [],
|
|
onChangeValue: [],
|
|
onUpdate: []
|
|
|
|
/**
|
|
* Call `onCreateRule` hooks and return an object if returned by a hook.
|
|
*/
|
|
};
|
|
}
|
|
|
|
createClass(PluginsRegistry, [{
|
|
key: 'onCreateRule',
|
|
value: function onCreateRule(name, decl, options) {
|
|
for (var i = 0; i < this.hooks.onCreateRule.length; i++) {
|
|
var rule = this.hooks.onCreateRule[i](name, decl, options);
|
|
if (rule) return rule;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Call `onProcessRule` hooks.
|
|
*/
|
|
|
|
}, {
|
|
key: 'onProcessRule',
|
|
value: function onProcessRule(rule) {
|
|
if (rule.isProcessed) return;
|
|
var sheet = rule.options.sheet;
|
|
|
|
for (var i = 0; i < this.hooks.onProcessRule.length; i++) {
|
|
this.hooks.onProcessRule[i](rule, sheet);
|
|
}
|
|
|
|
// $FlowFixMe
|
|
if (rule.style) this.onProcessStyle(rule.style, rule, sheet);
|
|
|
|
rule.isProcessed = true;
|
|
}
|
|
|
|
/**
|
|
* Call `onProcessStyle` hooks.
|
|
*/
|
|
|
|
}, {
|
|
key: 'onProcessStyle',
|
|
value: function onProcessStyle(style, rule, sheet) {
|
|
var nextStyle = style;
|
|
|
|
for (var i = 0; i < this.hooks.onProcessStyle.length; i++) {
|
|
nextStyle = this.hooks.onProcessStyle[i](nextStyle, rule, sheet);
|
|
// $FlowFixMe
|
|
rule.style = nextStyle;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Call `onProcessSheet` hooks.
|
|
*/
|
|
|
|
}, {
|
|
key: 'onProcessSheet',
|
|
value: function onProcessSheet(sheet) {
|
|
for (var i = 0; i < this.hooks.onProcessSheet.length; i++) {
|
|
this.hooks.onProcessSheet[i](sheet);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Call `onUpdate` hooks.
|
|
*/
|
|
|
|
}, {
|
|
key: 'onUpdate',
|
|
value: function onUpdate(data, rule, sheet) {
|
|
for (var i = 0; i < this.hooks.onUpdate.length; i++) {
|
|
this.hooks.onUpdate[i](data, rule, sheet);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Call `onChangeValue` hooks.
|
|
*/
|
|
|
|
}, {
|
|
key: 'onChangeValue',
|
|
value: function onChangeValue(value, prop, rule) {
|
|
var processedValue = value;
|
|
for (var i = 0; i < this.hooks.onChangeValue.length; i++) {
|
|
processedValue = this.hooks.onChangeValue[i](processedValue, prop, rule);
|
|
}
|
|
return processedValue;
|
|
}
|
|
|
|
/**
|
|
* Register a plugin.
|
|
* If function is passed, it is a shortcut for `{onProcessRule}`.
|
|
*/
|
|
|
|
}, {
|
|
key: 'use',
|
|
value: function use(plugin) {
|
|
for (var name in plugin) {
|
|
if (this.hooks[name]) this.hooks[name].push(plugin[name]);else warning_1(false, '[JSS] Unknown hook "%s".', name);
|
|
}
|
|
}
|
|
}]);
|
|
return PluginsRegistry;
|
|
}();
|
|
|
|
var SimpleRule = function () {
|
|
function SimpleRule(key, value, options) {
|
|
classCallCheck(this, SimpleRule);
|
|
this.type = 'simple';
|
|
this.isProcessed = false;
|
|
|
|
this.key = key;
|
|
this.value = value;
|
|
this.options = options;
|
|
}
|
|
|
|
/**
|
|
* Generates a CSS string.
|
|
*/
|
|
// eslint-disable-next-line no-unused-vars
|
|
|
|
|
|
createClass(SimpleRule, [{
|
|
key: 'toString',
|
|
value: function toString(options) {
|
|
if (Array.isArray(this.value)) {
|
|
var str = '';
|
|
for (var index = 0; index < this.value.length; index++) {
|
|
str += this.key + ' ' + this.value[index] + ';';
|
|
if (this.value[index + 1]) str += '\n';
|
|
}
|
|
return str;
|
|
}
|
|
|
|
return this.key + ' ' + this.value + ';';
|
|
}
|
|
}]);
|
|
return SimpleRule;
|
|
}();
|
|
|
|
/**
|
|
* Rule for @keyframes
|
|
*/
|
|
var KeyframesRule = function () {
|
|
function KeyframesRule(key, frames, options) {
|
|
classCallCheck(this, KeyframesRule);
|
|
this.type = 'keyframes';
|
|
this.isProcessed = false;
|
|
|
|
this.key = key;
|
|
this.options = options;
|
|
this.rules = new RuleList(_extends({}, options, { parent: this }));
|
|
|
|
for (var name in frames) {
|
|
this.rules.add(name, frames[name], _extends({}, this.options, {
|
|
parent: this,
|
|
selector: name
|
|
}));
|
|
}
|
|
|
|
this.rules.process();
|
|
}
|
|
|
|
/**
|
|
* Generates a CSS string.
|
|
*/
|
|
|
|
|
|
createClass(KeyframesRule, [{
|
|
key: 'toString',
|
|
value: function toString() {
|
|
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : { indent: 1 };
|
|
|
|
var inner = this.rules.toString(options);
|
|
if (inner) inner += '\n';
|
|
return this.key + ' {\n' + inner + '}';
|
|
}
|
|
}]);
|
|
return KeyframesRule;
|
|
}();
|
|
|
|
/**
|
|
* Conditional rule for @media, @supports
|
|
*/
|
|
var ConditionalRule = function () {
|
|
function ConditionalRule(key, styles, options) {
|
|
classCallCheck(this, ConditionalRule);
|
|
this.type = 'conditional';
|
|
this.isProcessed = false;
|
|
|
|
this.key = key;
|
|
this.options = options;
|
|
this.rules = new RuleList(_extends({}, options, { parent: this }));
|
|
|
|
for (var name in styles) {
|
|
this.rules.add(name, styles[name]);
|
|
}
|
|
|
|
this.rules.process();
|
|
}
|
|
|
|
/**
|
|
* Get a rule.
|
|
*/
|
|
|
|
|
|
createClass(ConditionalRule, [{
|
|
key: 'getRule',
|
|
value: function getRule(name) {
|
|
return this.rules.get(name);
|
|
}
|
|
|
|
/**
|
|
* Get index of a rule.
|
|
*/
|
|
|
|
}, {
|
|
key: 'indexOf',
|
|
value: function indexOf(rule) {
|
|
return this.rules.indexOf(rule);
|
|
}
|
|
|
|
/**
|
|
* Create and register rule, run plugins.
|
|
*/
|
|
|
|
}, {
|
|
key: 'addRule',
|
|
value: function addRule(name, style, options) {
|
|
var rule = this.rules.add(name, style, options);
|
|
this.options.jss.plugins.onProcessRule(rule);
|
|
return rule;
|
|
}
|
|
|
|
/**
|
|
* Generates a CSS string.
|
|
*/
|
|
|
|
}, {
|
|
key: 'toString',
|
|
value: function toString() {
|
|
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : { indent: 1 };
|
|
|
|
var inner = this.rules.toString(options);
|
|
return inner ? this.key + ' {\n' + inner + '\n}' : '';
|
|
}
|
|
}]);
|
|
return ConditionalRule;
|
|
}();
|
|
|
|
var FontFaceRule = function () {
|
|
function FontFaceRule(key, style, options) {
|
|
classCallCheck(this, FontFaceRule);
|
|
this.type = 'font-face';
|
|
this.isProcessed = false;
|
|
|
|
this.key = key;
|
|
this.style = style;
|
|
this.options = options;
|
|
}
|
|
|
|
/**
|
|
* Generates a CSS string.
|
|
*/
|
|
|
|
|
|
createClass(FontFaceRule, [{
|
|
key: 'toString',
|
|
value: function toString(options) {
|
|
if (Array.isArray(this.style)) {
|
|
var str = '';
|
|
for (var index = 0; index < this.style.length; index++) {
|
|
str += toCss(this.key, this.style[index]);
|
|
if (this.style[index + 1]) str += '\n';
|
|
}
|
|
return str;
|
|
}
|
|
|
|
return toCss(this.key, this.style, options);
|
|
}
|
|
}]);
|
|
return FontFaceRule;
|
|
}();
|
|
|
|
var ViewportRule = function () {
|
|
function ViewportRule(key, style, options) {
|
|
classCallCheck(this, ViewportRule);
|
|
this.type = 'viewport';
|
|
this.isProcessed = false;
|
|
|
|
this.key = key;
|
|
this.style = style;
|
|
this.options = options;
|
|
}
|
|
|
|
/**
|
|
* Generates a CSS string.
|
|
*/
|
|
|
|
|
|
createClass(ViewportRule, [{
|
|
key: 'toString',
|
|
value: function toString(options) {
|
|
return toCss(this.key, this.style, options);
|
|
}
|
|
}]);
|
|
return ViewportRule;
|
|
}();
|
|
|
|
var classes = {
|
|
'@charset': SimpleRule,
|
|
'@import': SimpleRule,
|
|
'@namespace': SimpleRule,
|
|
'@keyframes': KeyframesRule,
|
|
'@media': ConditionalRule,
|
|
'@supports': ConditionalRule,
|
|
'@font-face': FontFaceRule,
|
|
'@viewport': ViewportRule,
|
|
'@-ms-viewport': ViewportRule
|
|
|
|
/**
|
|
* Generate plugins which will register all rules.
|
|
*/
|
|
};var plugins = Object.keys(classes).map(function (key) {
|
|
// https://jsperf.com/indexof-vs-substr-vs-regex-at-the-beginning-3
|
|
var re = new RegExp('^' + key);
|
|
var RuleClass = classes[key];
|
|
var onCreateRule = function onCreateRule(name, decl, options) {
|
|
return re.test(name) ? new RuleClass(name, decl, options) : null;
|
|
};
|
|
return { onCreateRule: onCreateRule };
|
|
});
|
|
|
|
var observablesPlugin = {
|
|
onCreateRule: function onCreateRule(name, decl, options) {
|
|
if (!isObservable(decl)) return null;
|
|
|
|
// Cast `decl` to `Observable`, since it passed the type guard.
|
|
var style$ = decl;
|
|
|
|
var rule = createRule(name, {}, options);
|
|
|
|
// TODO
|
|
// Call `stream.subscribe()` returns a subscription, which should be explicitly
|
|
// unsubscribed from when we know this sheet is no longer needed.
|
|
style$.subscribe(function (style) {
|
|
for (var prop in style) {
|
|
rule.prop(prop, style[prop]);
|
|
}
|
|
});
|
|
|
|
return rule;
|
|
},
|
|
onProcessRule: function onProcessRule(rule) {
|
|
if (!(rule instanceof StyleRule)) return;
|
|
var styleRule = rule;
|
|
var style = styleRule.style;
|
|
|
|
var _loop = function _loop(prop) {
|
|
var value = style[prop];
|
|
if (!isObservable(value)) return 'continue';
|
|
delete style[prop];
|
|
value.subscribe({
|
|
next: function next(nextValue) {
|
|
styleRule.prop(prop, nextValue);
|
|
}
|
|
});
|
|
};
|
|
|
|
for (var prop in style) {
|
|
var _ret = _loop(prop);
|
|
|
|
if (_ret === 'continue') continue;
|
|
}
|
|
}
|
|
};
|
|
|
|
// A symbol replacement.
|
|
var now = Date.now();
|
|
var fnValuesNs = 'fnValues' + now;
|
|
var fnStyleNs = 'fnStyle' + ++now;
|
|
|
|
var functionsPlugin = {
|
|
onCreateRule: function onCreateRule(name, decl, options) {
|
|
if (typeof decl !== 'function') return null;
|
|
var rule = createRule(name, {}, options);
|
|
rule[fnStyleNs] = decl;
|
|
return rule;
|
|
},
|
|
onProcessStyle: function onProcessStyle(style, rule) {
|
|
var fn = {};
|
|
for (var prop in style) {
|
|
var value = style[prop];
|
|
if (typeof value !== 'function') continue;
|
|
delete style[prop];
|
|
fn[prop] = value;
|
|
}
|
|
rule = rule;
|
|
rule[fnValuesNs] = fn;
|
|
return style;
|
|
},
|
|
onUpdate: function onUpdate(data, rule) {
|
|
// It is a rules container like for e.g. ConditionalRule.
|
|
if (rule.rules instanceof RuleList) {
|
|
rule.rules.update(data);
|
|
return;
|
|
}
|
|
if (!(rule instanceof StyleRule)) return;
|
|
|
|
rule = rule;
|
|
|
|
// If we have a fn values map, it is a rule with function values.
|
|
if (rule[fnValuesNs]) {
|
|
for (var prop in rule[fnValuesNs]) {
|
|
rule.prop(prop, rule[fnValuesNs][prop](data));
|
|
}
|
|
}
|
|
|
|
rule = rule;
|
|
|
|
var fnStyle = rule[fnStyleNs];
|
|
|
|
// If we have a style function, the entire rule is dynamic and style object
|
|
// will be returned from that function.
|
|
if (fnStyle) {
|
|
var style = fnStyle(data);
|
|
for (var _prop in style) {
|
|
rule.prop(_prop, style[_prop]);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Sheets registry to access them all at one place.
|
|
*/
|
|
var SheetsRegistry = function () {
|
|
function SheetsRegistry() {
|
|
classCallCheck(this, SheetsRegistry);
|
|
this.registry = [];
|
|
}
|
|
|
|
createClass(SheetsRegistry, [{
|
|
key: 'add',
|
|
|
|
|
|
/**
|
|
* Register a Style Sheet.
|
|
*/
|
|
value: function add(sheet) {
|
|
var registry = this.registry;
|
|
var index = sheet.options.index;
|
|
|
|
|
|
if (registry.indexOf(sheet) !== -1) return;
|
|
|
|
if (registry.length === 0 || index >= this.index) {
|
|
registry.push(sheet);
|
|
return;
|
|
}
|
|
|
|
// Find a position.
|
|
for (var i = 0; i < registry.length; i++) {
|
|
if (registry[i].options.index > index) {
|
|
registry.splice(i, 0, sheet);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Reset the registry.
|
|
*/
|
|
|
|
}, {
|
|
key: 'reset',
|
|
value: function reset() {
|
|
this.registry = [];
|
|
}
|
|
|
|
/**
|
|
* Remove a Style Sheet.
|
|
*/
|
|
|
|
}, {
|
|
key: 'remove',
|
|
value: function remove(sheet) {
|
|
var index = this.registry.indexOf(sheet);
|
|
this.registry.splice(index, 1);
|
|
}
|
|
|
|
/**
|
|
* Convert all attached sheets to a CSS string.
|
|
*/
|
|
|
|
}, {
|
|
key: 'toString',
|
|
value: function toString(options) {
|
|
return this.registry.filter(function (sheet) {
|
|
return sheet.attached;
|
|
}).map(function (sheet) {
|
|
return sheet.toString(options);
|
|
}).join('\n');
|
|
}
|
|
}, {
|
|
key: 'index',
|
|
|
|
|
|
/**
|
|
* Current highest index number.
|
|
*/
|
|
get: function get$$1() {
|
|
return this.registry.length === 0 ? 0 : this.registry[this.registry.length - 1].options.index;
|
|
}
|
|
}]);
|
|
return SheetsRegistry;
|
|
}();
|
|
|
|
/**
|
|
* This is a global sheets registry. Only DomRenderer will add sheets to it.
|
|
* On the server one should use an own SheetsRegistry instance and add the
|
|
* sheets to it, because you need to make sure to create a new registry for
|
|
* each request in order to not leak sheets across requests.
|
|
*/
|
|
var sheets = new SheetsRegistry();
|
|
|
|
var ns = '2f1acc6c3a606b082e5eef5e54414ffb';
|
|
if (global$1[ns] == null) global$1[ns] = 0;
|
|
|
|
// Bundle may contain multiple JSS versions at the same time. In order to identify
|
|
// the current version with just one short number and use it for classes generation
|
|
// we use a counter. Also it is more accurate, because user can manually reevaluate
|
|
// the module.
|
|
var moduleId = global$1[ns]++;
|
|
|
|
var maxRules = 1e10;
|
|
|
|
var env$2 = "development";
|
|
|
|
/**
|
|
* Returns a function which generates unique class names based on counters.
|
|
* When new generator function is created, rule counter is reseted.
|
|
* We need to reset the rule counter for SSR for each request.
|
|
*/
|
|
var createGenerateClassNameDefault = (function () {
|
|
var ruleCounter = 0;
|
|
var defaultPrefix = env$2 === 'production' ? 'c' : '';
|
|
|
|
return function (rule, sheet) {
|
|
ruleCounter += 1;
|
|
|
|
if (ruleCounter > maxRules) {
|
|
warning_1(false, '[JSS] You might have a memory leak. Rule counter is at %s.', ruleCounter);
|
|
}
|
|
|
|
var prefix = defaultPrefix;
|
|
var jssId = '';
|
|
|
|
if (sheet) {
|
|
prefix = sheet.options.classNamePrefix || defaultPrefix;
|
|
if (sheet.options.jss.id != null) jssId += sheet.options.jss.id;
|
|
}
|
|
|
|
if (env$2 === 'production') {
|
|
return '' + prefix + moduleId + jssId + ruleCounter;
|
|
}
|
|
|
|
return prefix + rule.key + '-' + moduleId + (jssId && '-' + jssId) + '-' + ruleCounter;
|
|
};
|
|
});
|
|
|
|
/**
|
|
* Cache the value from the first time a function is called.
|
|
*/
|
|
var memoize = function memoize(fn) {
|
|
var value = void 0;
|
|
return function () {
|
|
if (!value) value = fn();
|
|
return value;
|
|
};
|
|
};
|
|
|
|
/**
|
|
* Get a style property value.
|
|
*/
|
|
function getPropertyValue(cssRule, prop) {
|
|
try {
|
|
return cssRule.style.getPropertyValue(prop);
|
|
} catch (err) {
|
|
// IE may throw if property is unknown.
|
|
return '';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Set a style property.
|
|
*/
|
|
function setProperty(cssRule, prop, value) {
|
|
try {
|
|
var cssValue = value;
|
|
|
|
if (Array.isArray(value)) {
|
|
cssValue = toCssValue(value, true);
|
|
|
|
if (value[value.length - 1] === '!important') {
|
|
cssRule.style.setProperty(prop, cssValue, 'important');
|
|
return true;
|
|
}
|
|
}
|
|
|
|
cssRule.style.setProperty(prop, cssValue);
|
|
} catch (err) {
|
|
// IE may throw if property is unknown.
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Remove a style property.
|
|
*/
|
|
function removeProperty(cssRule, prop) {
|
|
try {
|
|
cssRule.style.removeProperty(prop);
|
|
} catch (err) {
|
|
warning_1(false, '[JSS] DOMException "%s" was thrown. Tried to remove property "%s".', err.message, prop);
|
|
}
|
|
}
|
|
|
|
var CSSRuleTypes = {
|
|
STYLE_RULE: 1,
|
|
KEYFRAMES_RULE: 7
|
|
|
|
/**
|
|
* Get the CSS Rule key.
|
|
*/
|
|
|
|
};var getKey = function () {
|
|
var extractKey = function extractKey(cssText) {
|
|
var from = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
|
|
return cssText.substr(from, cssText.indexOf('{') - 1);
|
|
};
|
|
|
|
return function (cssRule) {
|
|
if (cssRule.type === CSSRuleTypes.STYLE_RULE) return cssRule.selectorText;
|
|
if (cssRule.type === CSSRuleTypes.KEYFRAMES_RULE) {
|
|
var name = cssRule.name;
|
|
|
|
if (name) return '@keyframes ' + name;
|
|
|
|
// There is no rule.name in the following browsers:
|
|
// - IE 9
|
|
// - Safari 7.1.8
|
|
// - Mobile Safari 9.0.0
|
|
var cssText = cssRule.cssText;
|
|
|
|
return '@' + extractKey(cssText, cssText.indexOf('keyframes'));
|
|
}
|
|
|
|
// Conditionals.
|
|
return extractKey(cssRule.cssText);
|
|
};
|
|
}();
|
|
|
|
/**
|
|
* Set the selector.
|
|
*/
|
|
function setSelector(cssRule, selectorText) {
|
|
cssRule.selectorText = selectorText;
|
|
|
|
// Return false if setter was not successful.
|
|
// Currently works in chrome only.
|
|
return cssRule.selectorText === selectorText;
|
|
}
|
|
|
|
/**
|
|
* Gets the `head` element upon the first call and caches it.
|
|
*/
|
|
var getHead = memoize(function () {
|
|
return document.head || document.getElementsByTagName('head')[0];
|
|
});
|
|
|
|
/**
|
|
* Gets a map of rule keys, where the property is an unescaped key and value
|
|
* is a potentially escaped one.
|
|
* It is used to identify CSS rules and the corresponding JSS rules. As an identifier
|
|
* for CSSStyleRule we normally use `selectorText`. Though if original selector text
|
|
* contains escaped code points e.g. `:not(#\\20)`, CSSOM will compile it to `:not(# )`
|
|
* and so CSS rule's `selectorText` won't match JSS rule selector.
|
|
*
|
|
* https://www.w3.org/International/questions/qa-escapes#cssescapes
|
|
*/
|
|
var getUnescapedKeysMap = function () {
|
|
var style = void 0;
|
|
var isAttached = false;
|
|
|
|
return function (rules) {
|
|
var map = {};
|
|
// https://github.com/facebook/flow/issues/2696
|
|
if (!style) style = document.createElement('style');
|
|
for (var i = 0; i < rules.length; i++) {
|
|
var rule = rules[i];
|
|
if (!(rule instanceof StyleRule)) continue;
|
|
var selector = rule.selector;
|
|
// Only unescape selector over CSSOM if it contains a back slash.
|
|
|
|
if (selector && selector.indexOf('\\') !== -1) {
|
|
// Lazilly attach when needed.
|
|
if (!isAttached) {
|
|
getHead().appendChild(style);
|
|
isAttached = true;
|
|
}
|
|
style.textContent = selector + ' {}';
|
|
var _style = style,
|
|
sheet = _style.sheet;
|
|
|
|
if (sheet) {
|
|
var cssRules = sheet.cssRules;
|
|
|
|
if (cssRules) map[cssRules[0].selectorText] = rule.key;
|
|
}
|
|
}
|
|
}
|
|
if (isAttached) {
|
|
getHead().removeChild(style);
|
|
isAttached = false;
|
|
}
|
|
return map;
|
|
};
|
|
}();
|
|
|
|
/**
|
|
* Find attached sheet with an index higher than the passed one.
|
|
*/
|
|
function findHigherSheet(registry, options) {
|
|
for (var i = 0; i < registry.length; i++) {
|
|
var sheet = registry[i];
|
|
if (sheet.attached && sheet.options.index > options.index && sheet.options.insertionPoint === options.insertionPoint) {
|
|
return sheet;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Find attached sheet with the highest index.
|
|
*/
|
|
function findHighestSheet(registry, options) {
|
|
for (var i = registry.length - 1; i >= 0; i--) {
|
|
var sheet = registry[i];
|
|
if (sheet.attached && sheet.options.insertionPoint === options.insertionPoint) {
|
|
return sheet;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Find a comment with "jss" inside.
|
|
*/
|
|
function findCommentNode(text) {
|
|
var head = getHead();
|
|
for (var i = 0; i < head.childNodes.length; i++) {
|
|
var node = head.childNodes[i];
|
|
if (node.nodeType === 8 && node.nodeValue.trim() === text) {
|
|
return node;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Find a node before which we can insert the sheet.
|
|
*/
|
|
function findPrevNode(options) {
|
|
var registry = sheets.registry;
|
|
|
|
|
|
if (registry.length > 0) {
|
|
// Try to insert before the next higher sheet.
|
|
var sheet = findHigherSheet(registry, options);
|
|
if (sheet) return sheet.renderer.element;
|
|
|
|
// Otherwise insert after the last attached.
|
|
sheet = findHighestSheet(registry, options);
|
|
if (sheet) return sheet.renderer.element.nextElementSibling;
|
|
}
|
|
|
|
// Try to find a comment placeholder if registry is empty.
|
|
var insertionPoint = options.insertionPoint;
|
|
|
|
if (insertionPoint && typeof insertionPoint === 'string') {
|
|
var comment = findCommentNode(insertionPoint);
|
|
if (comment) return comment.nextSibling;
|
|
// If user specifies an insertion point and it can't be found in the document -
|
|
// bad specificity issues may appear.
|
|
warning_1(insertionPoint === 'jss', '[JSS] Insertion point "%s" not found.', insertionPoint);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Insert style element into the DOM.
|
|
*/
|
|
function insertStyle(style, options) {
|
|
var insertionPoint = options.insertionPoint;
|
|
|
|
var prevNode = findPrevNode(options);
|
|
|
|
if (prevNode) {
|
|
var parentNode = prevNode.parentNode;
|
|
|
|
if (parentNode) parentNode.insertBefore(style, prevNode);
|
|
return;
|
|
}
|
|
|
|
// Works with iframes and any node types.
|
|
if (insertionPoint && typeof insertionPoint.nodeType === 'number') {
|
|
// https://stackoverflow.com/questions/41328728/force-casting-in-flow
|
|
var insertionPointElement = insertionPoint;
|
|
var _parentNode = insertionPointElement.parentNode;
|
|
|
|
if (_parentNode) _parentNode.insertBefore(style, insertionPointElement.nextSibling);else warning_1(false, '[JSS] Insertion point is not in the DOM.');
|
|
return;
|
|
}
|
|
|
|
getHead().insertBefore(style, prevNode);
|
|
}
|
|
|
|
/**
|
|
* Read jss nonce setting from the page if the user has set it.
|
|
*/
|
|
var getNonce = memoize(function () {
|
|
var node = document.querySelector('meta[property="csp-nonce"]');
|
|
return node ? node.getAttribute('content') : null;
|
|
});
|
|
|
|
var DomRenderer = function () {
|
|
function DomRenderer(sheet) {
|
|
classCallCheck(this, DomRenderer);
|
|
this.getPropertyValue = getPropertyValue;
|
|
this.setProperty = setProperty;
|
|
this.removeProperty = removeProperty;
|
|
this.setSelector = setSelector;
|
|
this.getKey = getKey;
|
|
this.getUnescapedKeysMap = getUnescapedKeysMap;
|
|
this.hasInsertedRules = false;
|
|
|
|
// There is no sheet when the renderer is used from a standalone StyleRule.
|
|
if (sheet) sheets.add(sheet);
|
|
|
|
this.sheet = sheet;
|
|
|
|
var _ref = this.sheet ? this.sheet.options : {},
|
|
media = _ref.media,
|
|
meta = _ref.meta,
|
|
element = _ref.element;
|
|
|
|
this.element = element || document.createElement('style');
|
|
this.element.setAttribute('data-jss', '');
|
|
if (media) this.element.setAttribute('media', media);
|
|
if (meta) this.element.setAttribute('data-meta', meta);
|
|
var nonce = getNonce();
|
|
if (nonce) this.element.setAttribute('nonce', nonce);
|
|
}
|
|
|
|
/**
|
|
* Insert style element into render tree.
|
|
*/
|
|
|
|
|
|
// HTMLStyleElement needs fixing https://github.com/facebook/flow/issues/2696
|
|
|
|
|
|
createClass(DomRenderer, [{
|
|
key: 'attach',
|
|
value: function attach() {
|
|
// In the case the element node is external and it is already in the DOM.
|
|
if (this.element.parentNode || !this.sheet) return;
|
|
|
|
// When rules are inserted using `insertRule` API, after `sheet.detach().attach()`
|
|
// browsers remove those rules.
|
|
// TODO figure out if its a bug and if it is known.
|
|
// Workaround is to redeploy the sheet before attaching as a string.
|
|
if (this.hasInsertedRules) {
|
|
this.deploy();
|
|
this.hasInsertedRules = false;
|
|
}
|
|
|
|
insertStyle(this.element, this.sheet.options);
|
|
}
|
|
|
|
/**
|
|
* Remove style element from render tree.
|
|
*/
|
|
|
|
}, {
|
|
key: 'detach',
|
|
value: function detach() {
|
|
this.element.parentNode.removeChild(this.element);
|
|
}
|
|
|
|
/**
|
|
* Inject CSS string into element.
|
|
*/
|
|
|
|
}, {
|
|
key: 'deploy',
|
|
value: function deploy() {
|
|
if (!this.sheet) return;
|
|
this.element.textContent = '\n' + this.sheet.toString() + '\n';
|
|
}
|
|
|
|
/**
|
|
* Insert a rule into element.
|
|
*/
|
|
|
|
}, {
|
|
key: 'insertRule',
|
|
value: function insertRule(rule, index) {
|
|
var sheet = this.element.sheet;
|
|
var cssRules = sheet.cssRules;
|
|
|
|
var str = rule.toString();
|
|
if (!index) index = cssRules.length;
|
|
|
|
if (!str) return false;
|
|
|
|
try {
|
|
sheet.insertRule(str, index);
|
|
} catch (err) {
|
|
warning_1(false, '[JSS] Can not insert an unsupported rule \n\r%s', rule);
|
|
return false;
|
|
}
|
|
this.hasInsertedRules = true;
|
|
|
|
return cssRules[index];
|
|
}
|
|
|
|
/**
|
|
* Delete a rule.
|
|
*/
|
|
|
|
}, {
|
|
key: 'deleteRule',
|
|
value: function deleteRule(cssRule) {
|
|
var sheet = this.element.sheet;
|
|
|
|
var index = this.indexOf(cssRule);
|
|
if (index === -1) return false;
|
|
sheet.deleteRule(index);
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Get index of a CSS Rule.
|
|
*/
|
|
|
|
}, {
|
|
key: 'indexOf',
|
|
value: function indexOf(cssRule) {
|
|
var cssRules = this.element.sheet.cssRules;
|
|
|
|
for (var _index = 0; _index < cssRules.length; _index++) {
|
|
if (cssRule === cssRules[_index]) return _index;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
/**
|
|
* Generate a new CSS rule and replace the existing one.
|
|
*/
|
|
|
|
}, {
|
|
key: 'replaceRule',
|
|
value: function replaceRule(cssRule, rule) {
|
|
var index = this.indexOf(cssRule);
|
|
var newCssRule = this.insertRule(rule, index);
|
|
this.element.sheet.deleteRule(index);
|
|
return newCssRule;
|
|
}
|
|
|
|
/**
|
|
* Get all rules elements.
|
|
*/
|
|
|
|
}, {
|
|
key: 'getRules',
|
|
value: function getRules() {
|
|
return this.element.sheet.cssRules;
|
|
}
|
|
}]);
|
|
return DomRenderer;
|
|
}();
|
|
|
|
/* eslint-disable class-methods-use-this */
|
|
|
|
/**
|
|
* Rendering backend to do nothing in nodejs.
|
|
*/
|
|
var VirtualRenderer = function () {
|
|
function VirtualRenderer() {
|
|
classCallCheck(this, VirtualRenderer);
|
|
}
|
|
|
|
createClass(VirtualRenderer, [{
|
|
key: 'setProperty',
|
|
value: function setProperty() {
|
|
return true;
|
|
}
|
|
}, {
|
|
key: 'getPropertyValue',
|
|
value: function getPropertyValue() {
|
|
return '';
|
|
}
|
|
}, {
|
|
key: 'removeProperty',
|
|
value: function removeProperty() {}
|
|
}, {
|
|
key: 'setSelector',
|
|
value: function setSelector() {
|
|
return true;
|
|
}
|
|
}, {
|
|
key: 'getKey',
|
|
value: function getKey() {
|
|
return '';
|
|
}
|
|
}, {
|
|
key: 'attach',
|
|
value: function attach() {}
|
|
}, {
|
|
key: 'detach',
|
|
value: function detach() {}
|
|
}, {
|
|
key: 'deploy',
|
|
value: function deploy() {}
|
|
}, {
|
|
key: 'insertRule',
|
|
value: function insertRule() {
|
|
return false;
|
|
}
|
|
}, {
|
|
key: 'deleteRule',
|
|
value: function deleteRule() {
|
|
return true;
|
|
}
|
|
}, {
|
|
key: 'replaceRule',
|
|
value: function replaceRule() {
|
|
return false;
|
|
}
|
|
}, {
|
|
key: 'getRules',
|
|
value: function getRules() {}
|
|
}, {
|
|
key: 'indexOf',
|
|
value: function indexOf() {
|
|
return -1;
|
|
}
|
|
}]);
|
|
return VirtualRenderer;
|
|
}();
|
|
|
|
var defaultPlugins = plugins.concat([observablesPlugin, functionsPlugin]);
|
|
|
|
var instanceCounter = 0;
|
|
|
|
var Jss = function () {
|
|
function Jss(options) {
|
|
classCallCheck(this, Jss);
|
|
this.id = instanceCounter++;
|
|
this.version = "9.8.7";
|
|
this.plugins = new PluginsRegistry();
|
|
this.options = {
|
|
createGenerateClassName: createGenerateClassNameDefault,
|
|
Renderer: isBrowser ? DomRenderer : VirtualRenderer,
|
|
plugins: []
|
|
};
|
|
this.generateClassName = createGenerateClassNameDefault();
|
|
|
|
// eslint-disable-next-line prefer-spread
|
|
this.use.apply(this, defaultPlugins);
|
|
this.setup(options);
|
|
}
|
|
|
|
createClass(Jss, [{
|
|
key: 'setup',
|
|
value: function setup() {
|
|
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
|
|
if (options.createGenerateClassName) {
|
|
this.options.createGenerateClassName = options.createGenerateClassName;
|
|
// $FlowFixMe
|
|
this.generateClassName = options.createGenerateClassName();
|
|
}
|
|
|
|
if (options.insertionPoint != null) this.options.insertionPoint = options.insertionPoint;
|
|
if (options.virtual || options.Renderer) {
|
|
this.options.Renderer = options.Renderer || (options.virtual ? VirtualRenderer : DomRenderer);
|
|
}
|
|
|
|
// eslint-disable-next-line prefer-spread
|
|
if (options.plugins) this.use.apply(this, options.plugins);
|
|
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Create a Style Sheet.
|
|
*/
|
|
|
|
}, {
|
|
key: 'createStyleSheet',
|
|
value: function createStyleSheet(styles) {
|
|
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
|
|
var index = options.index;
|
|
if (typeof index !== 'number') {
|
|
index = sheets.index === 0 ? 0 : sheets.index + 1;
|
|
}
|
|
var sheet = new StyleSheet(styles, _extends({}, options, {
|
|
jss: this,
|
|
generateClassName: options.generateClassName || this.generateClassName,
|
|
insertionPoint: this.options.insertionPoint,
|
|
Renderer: this.options.Renderer,
|
|
index: index
|
|
}));
|
|
this.plugins.onProcessSheet(sheet);
|
|
|
|
return sheet;
|
|
}
|
|
|
|
/**
|
|
* Detach the Style Sheet and remove it from the registry.
|
|
*/
|
|
|
|
}, {
|
|
key: 'removeStyleSheet',
|
|
value: function removeStyleSheet(sheet) {
|
|
sheet.detach();
|
|
sheets.remove(sheet);
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Create a rule without a Style Sheet.
|
|
*/
|
|
|
|
}, {
|
|
key: 'createRule',
|
|
value: function createRule$$1(name) {
|
|
var style = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
|
|
// Enable rule without name for inline styles.
|
|
if ((typeof name === 'undefined' ? 'undefined' : _typeof$1(name)) === 'object') {
|
|
options = style;
|
|
style = name;
|
|
name = undefined;
|
|
}
|
|
|
|
// Cast from RuleFactoryOptions to RuleOptions
|
|
// https://stackoverflow.com/questions/41328728/force-casting-in-flow
|
|
var ruleOptions = options;
|
|
|
|
ruleOptions.jss = this;
|
|
ruleOptions.Renderer = this.options.Renderer;
|
|
if (!ruleOptions.generateClassName) ruleOptions.generateClassName = this.generateClassName;
|
|
if (!ruleOptions.classes) ruleOptions.classes = {};
|
|
var rule = createRule(name, style, ruleOptions);
|
|
|
|
if (!ruleOptions.selector && rule instanceof StyleRule) {
|
|
rule.selector = '.' + ruleOptions.generateClassName(rule);
|
|
}
|
|
|
|
this.plugins.onProcessRule(rule);
|
|
|
|
return rule;
|
|
}
|
|
|
|
/**
|
|
* Register plugin. Passed function will be invoked with a rule instance.
|
|
*/
|
|
|
|
}, {
|
|
key: 'use',
|
|
value: function use() {
|
|
var _this = this;
|
|
|
|
for (var _len = arguments.length, plugins$$1 = Array(_len), _key = 0; _key < _len; _key++) {
|
|
plugins$$1[_key] = arguments[_key];
|
|
}
|
|
|
|
plugins$$1.forEach(function (plugin) {
|
|
// Avoids applying same plugin twice, at least based on ref.
|
|
if (_this.options.plugins.indexOf(plugin) === -1) {
|
|
_this.options.plugins.push(plugin);
|
|
_this.plugins.use(plugin);
|
|
}
|
|
});
|
|
|
|
return this;
|
|
}
|
|
}]);
|
|
return Jss;
|
|
}();
|
|
|
|
/**
|
|
* Extracts a styles object with only props that contain function values.
|
|
*/
|
|
function getDynamicStyles(styles) {
|
|
var to = null;
|
|
|
|
for (var key in styles) {
|
|
var value = styles[key];
|
|
var type = typeof value === 'undefined' ? 'undefined' : _typeof$1(value);
|
|
|
|
if (type === 'function') {
|
|
if (!to) to = {};
|
|
to[key] = value;
|
|
} else if (type === 'object' && value !== null && !Array.isArray(value)) {
|
|
var extracted = getDynamicStyles(value);
|
|
if (extracted) {
|
|
if (!to) to = {};
|
|
to[key] = extracted;
|
|
}
|
|
}
|
|
}
|
|
|
|
return to;
|
|
}
|
|
|
|
/**
|
|
* SheetsManager is like a WeakMap which is designed to count StyleSheet
|
|
* instances and attach/detach automatically.
|
|
*/
|
|
var SheetsManager = function () {
|
|
function SheetsManager() {
|
|
classCallCheck(this, SheetsManager);
|
|
this.sheets = [];
|
|
this.refs = [];
|
|
this.keys = [];
|
|
}
|
|
|
|
createClass(SheetsManager, [{
|
|
key: 'get',
|
|
value: function get$$1(key) {
|
|
var index = this.keys.indexOf(key);
|
|
return this.sheets[index];
|
|
}
|
|
}, {
|
|
key: 'add',
|
|
value: function add(key, sheet) {
|
|
var sheets = this.sheets,
|
|
refs = this.refs,
|
|
keys = this.keys;
|
|
|
|
var index = sheets.indexOf(sheet);
|
|
|
|
if (index !== -1) return index;
|
|
|
|
sheets.push(sheet);
|
|
refs.push(0);
|
|
keys.push(key);
|
|
|
|
return sheets.length - 1;
|
|
}
|
|
}, {
|
|
key: 'manage',
|
|
value: function manage(key) {
|
|
var index = this.keys.indexOf(key);
|
|
var sheet = this.sheets[index];
|
|
if (this.refs[index] === 0) sheet.attach();
|
|
this.refs[index]++;
|
|
if (!this.keys[index]) this.keys.splice(index, 0, key);
|
|
return sheet;
|
|
}
|
|
}, {
|
|
key: 'unmanage',
|
|
value: function unmanage(key) {
|
|
var index = this.keys.indexOf(key);
|
|
if (index === -1) {
|
|
// eslint-ignore-next-line no-console
|
|
warning_1(false, "SheetsManager: can't find sheet to unmanage");
|
|
return;
|
|
}
|
|
if (this.refs[index] > 0) {
|
|
this.refs[index]--;
|
|
if (this.refs[index] === 0) this.sheets[index].detach();
|
|
}
|
|
}
|
|
}, {
|
|
key: 'size',
|
|
get: function get$$1() {
|
|
return this.keys.length;
|
|
}
|
|
}]);
|
|
return SheetsManager;
|
|
}();
|
|
|
|
/**
|
|
* Creates a new instance of Jss.
|
|
*/
|
|
var create = function create(options) {
|
|
return new Jss(options);
|
|
};
|
|
|
|
/**
|
|
* A global Jss instance.
|
|
*/
|
|
var index$1 = create();
|
|
|
|
exports.create = create;
|
|
exports.default = index$1;
|
|
exports.getDynamicStyles = getDynamicStyles;
|
|
exports.toCssValue = toCssValue;
|
|
exports.SheetsRegistry = SheetsRegistry;
|
|
exports.SheetsManager = SheetsManager;
|
|
exports.RuleList = RuleList;
|
|
exports.sheets = sheets;
|
|
exports.createGenerateClassName = createGenerateClassNameDefault;
|
|
|
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
|
})));
|
|
//# sourceMappingURL=jss.js.map
|