UNPKG

@uifabric/merge-styles

Version:
236 lines 8.81 kB
import { __assign } from "tslib"; export var InjectionMode = { /** * Avoids style injection, use getRules() to read the styles. */ none: 0, /** * Inserts rules using the insertRule api. */ insertNode: 1, /** * Appends rules using appendChild. */ appendChild: 2, }; var STYLESHEET_SETTING = '__stylesheet__'; /** * MSIE 11 doesn't cascade styles based on DOM ordering, but rather on the order that each style node * is created. As such, to maintain consistent priority, IE11 should reuse a single style node. */ var REUSE_STYLE_NODE = typeof navigator !== 'undefined' && /rv:11.0/.test(navigator.userAgent); var _global = {}; // Grab window. try { _global = window; } catch (_a) { /* leave as blank object */ } var _stylesheet; /** * Represents the state of styles registered in the page. Abstracts * the surface for adding styles to the stylesheet, exposes helpers * for reading the styles registered in server rendered scenarios. * * @public */ var Stylesheet = /** @class */ (function () { function Stylesheet(config) { this._rules = []; this._preservedRules = []; this._rulesToInsert = []; this._counter = 0; this._keyToClassName = {}; this._onResetCallbacks = []; this._classNameToArgs = {}; this._config = __assign({ injectionMode: InjectionMode.insertNode, defaultPrefix: 'css', namespace: undefined, cspSettings: undefined }, config); this._keyToClassName = this._config.classNameCache || {}; } /** * Gets the singleton instance. */ Stylesheet.getInstance = function () { var _a; _stylesheet = _global[STYLESHEET_SETTING]; if (!_stylesheet || (_stylesheet._lastStyleElement && _stylesheet._lastStyleElement.ownerDocument !== document)) { var fabricConfig = ((_a = _global) === null || _a === void 0 ? void 0 : _a.FabricConfig) || {}; _stylesheet = _global[STYLESHEET_SETTING] = new Stylesheet(fabricConfig.mergeStyles); } return _stylesheet; }; /** * Configures the stylesheet. */ Stylesheet.prototype.setConfig = function (config) { this._config = __assign(__assign({}, this._config), config); }; /** * Configures a reset callback. * * @param callback - A callback which will be called when the Stylesheet is reset. */ Stylesheet.prototype.onReset = function (callback) { this._onResetCallbacks.push(callback); }; /** * Generates a unique classname. * * @param displayName - Optional value to use as a prefix. */ Stylesheet.prototype.getClassName = function (displayName) { var namespace = this._config.namespace; var prefix = displayName || this._config.defaultPrefix; return "" + (namespace ? namespace + '-' : '') + prefix + "-" + this._counter++; }; /** * Used internally to cache information about a class which was * registered with the stylesheet. */ Stylesheet.prototype.cacheClassName = function (className, key, args, rules) { this._keyToClassName[key] = className; this._classNameToArgs[className] = { args: args, rules: rules, }; }; /** * Gets the appropriate classname given a key which was previously * registered using cacheClassName. */ Stylesheet.prototype.classNameFromKey = function (key) { return this._keyToClassName[key]; }; /** * Gets all classnames cache with the stylesheet. */ Stylesheet.prototype.getClassNameCache = function () { return this._keyToClassName; }; /** * Gets the arguments associated with a given classname which was * previously registered using cacheClassName. */ Stylesheet.prototype.argsFromClassName = function (className) { var entry = this._classNameToArgs[className]; return entry && entry.args; }; /** * Gets the arguments associated with a given classname which was * previously registered using cacheClassName. */ Stylesheet.prototype.insertedRulesFromClassName = function (className) { var entry = this._classNameToArgs[className]; return entry && entry.rules; }; /** * Inserts a css rule into the stylesheet. * @param preserve - Preserves the rule beyond a reset boundary. */ Stylesheet.prototype.insertRule = function (rule, preserve) { var injectionMode = this._config.injectionMode; var element = injectionMode !== InjectionMode.none ? this._getStyleElement() : undefined; if (preserve) { this._preservedRules.push(rule); } if (element) { switch (this._config.injectionMode) { case InjectionMode.insertNode: var sheet = element.sheet; try { sheet.insertRule(rule, sheet.cssRules.length); } catch (e) { // The browser will throw exceptions on unsupported rules (such as a moz prefix in webkit.) // We need to swallow the exceptions for this scenario, otherwise we'd need to filter // which could be slower and bulkier. } break; case InjectionMode.appendChild: element.appendChild(document.createTextNode(rule)); break; } } else { this._rules.push(rule); } if (this._config.onInsertRule) { this._config.onInsertRule(rule); } }; /** * Gets all rules registered with the stylesheet; only valid when * using InsertionMode.none. */ Stylesheet.prototype.getRules = function (includePreservedRules) { return ((includePreservedRules ? this._preservedRules.join('') : '') + this._rules.join('') + this._rulesToInsert.join('')); }; /** * Resets the internal state of the stylesheet. Only used in server * rendered scenarios where we're using InsertionMode.none. */ Stylesheet.prototype.reset = function () { this._rules = []; this._rulesToInsert = []; this._counter = 0; this._classNameToArgs = {}; this._keyToClassName = {}; this._onResetCallbacks.forEach(function (callback) { return callback(); }); }; // Forces the regeneration of incoming styles without totally resetting the stylesheet. Stylesheet.prototype.resetKeys = function () { this._keyToClassName = {}; }; Stylesheet.prototype._getStyleElement = function () { var _this = this; if (!this._styleElement && typeof document !== 'undefined') { this._styleElement = this._createStyleElement(); if (!REUSE_STYLE_NODE) { // Reset the style element on the next frame. window.requestAnimationFrame(function () { _this._styleElement = undefined; }); } } return this._styleElement; }; Stylesheet.prototype._createStyleElement = function () { var head = document.head; var styleElement = document.createElement('style'); var nodeToInsertBefore = null; styleElement.setAttribute('data-merge-styles', 'true'); var cspSettings = this._config.cspSettings; if (cspSettings) { if (cspSettings.nonce) { styleElement.setAttribute('nonce', cspSettings.nonce); } } if (this._lastStyleElement) { // If the `nextElementSibling` is null, then the insertBefore will act as a regular append. // https://developer.mozilla.org/en-US/docs/Web/API/Node/insertBefore#Syntax nodeToInsertBefore = this._lastStyleElement.nextElementSibling; } else { var placeholderStyleTag = this._findPlaceholderStyleTag(); if (placeholderStyleTag) { nodeToInsertBefore = placeholderStyleTag.nextElementSibling; } else { nodeToInsertBefore = head.childNodes[0]; } } head.insertBefore(styleElement, head.contains(nodeToInsertBefore) ? nodeToInsertBefore : null); this._lastStyleElement = styleElement; return styleElement; }; Stylesheet.prototype._findPlaceholderStyleTag = function () { var head = document.head; if (head) { return head.querySelector('style[data-merge-styles]'); } return null; }; return Stylesheet; }()); export { Stylesheet }; //# sourceMappingURL=Stylesheet.js.map