UNPKG

6.89 kBJavaScriptView Raw
1define(["require", "exports", "@uifabric/merge-styles", "./rtl", "./dom"], function (require, exports, merge_styles_1, rtl_1, dom_1) {
2 "use strict";
3 Object.defineProperty(exports, "__esModule", { value: true });
4 var MAX_CACHE_COUNT = 50;
5 var DEFAULT_SPECIFICITY_MULTIPLIER = 5;
6 var _memoizedClassNames = 0;
7 var stylesheet = merge_styles_1.Stylesheet.getInstance();
8 if (stylesheet && stylesheet.onReset) {
9 stylesheet.onReset(function () { return _memoizedClassNames++; });
10 }
11 // Note that because of the caching nature within the classNames memoization,
12 // I've disabled this rule to simply be able to work with any types.
13 /* eslint-disable @typescript-eslint/no-explicit-any */
14 // This represents a prop we attach to each Map to indicate the cached return value
15 // associated with the graph node.
16 var retVal = '__retval__';
17 /**
18 * Creates a getClassNames function which calls getStyles given the props, and injects them
19 * into mergeStyleSets.
20 *
21 * Note that the props you pass in on every render should be in the same order and
22 * immutable (numbers, strings, and booleans). This will allow the results to be memoized. Violating
23 * these will cause extra recalcs to occur.
24 */
25 function classNamesFunction(options) {
26 // We build a trie where each node is a Map. The map entry key represents an argument
27 // value, and the entry value is another node (Map). Each node has a `__retval__`
28 // property which is used to hold the cached response.
29 if (options === void 0) { options = {}; }
30 // To derive the response, we can simply ensure the arguments are added or already
31 // exist in the trie. At the last node, if there is a `__retval__` we return that. Otherwise
32 // we call the `getStyles` api to evaluate, cache on the property, and return that.
33 var map = new Map();
34 var styleCalcCount = 0;
35 var getClassNamesCount = 0;
36 var currentMemoizedClassNames = _memoizedClassNames;
37 var getClassNames = function (styleFunctionOrObject, styleProps) {
38 if (styleProps === void 0) { styleProps = {}; }
39 var _a, _b;
40 // If useStaticStyles is true, styleFunctionOrObject returns slot to classname mappings.
41 // If there is also no style overrides, we can skip merge styles completely and
42 // simply return the result from the style funcion.
43 if (options.useStaticStyles &&
44 typeof styleFunctionOrObject === 'function' &&
45 styleFunctionOrObject.__noStyleOverride__) {
46 return styleFunctionOrObject(styleProps);
47 }
48 getClassNamesCount++;
49 var current = map;
50 var theme = styleProps.theme;
51 var rtl = theme && theme.rtl !== undefined ? theme.rtl : rtl_1.getRTL();
52 var disableCaching = options.disableCaching;
53 // On reset of our stylesheet, reset memoized cache.
54 if (currentMemoizedClassNames !== _memoizedClassNames) {
55 currentMemoizedClassNames = _memoizedClassNames;
56 map = new Map();
57 styleCalcCount = 0;
58 }
59 if (!options.disableCaching) {
60 current = _traverseMap(map, styleFunctionOrObject);
61 current = _traverseMap(current, styleProps);
62 }
63 if (disableCaching || !current[retVal]) {
64 if (styleFunctionOrObject === undefined) {
65 current[retVal] = {};
66 }
67 else {
68 current[retVal] = merge_styles_1.mergeCssSets([
69 (typeof styleFunctionOrObject === 'function'
70 ? styleFunctionOrObject(styleProps)
71 : styleFunctionOrObject),
72 ], { rtl: !!rtl, specificityMultiplier: options.useStaticStyles ? DEFAULT_SPECIFICITY_MULTIPLIER : undefined });
73 }
74 if (!disableCaching) {
75 styleCalcCount++;
76 }
77 }
78 if (styleCalcCount > (options.cacheSize || MAX_CACHE_COUNT)) {
79 var win = dom_1.getWindow();
80 if ((_b = (_a = win) === null || _a === void 0 ? void 0 : _a.FabricConfig) === null || _b === void 0 ? void 0 : _b.enableClassNameCacheFullWarning) {
81 // eslint-disable-next-line no-console
82 console.warn("Styles are being recalculated too frequently. Cache miss rate is " + styleCalcCount + "/" + getClassNamesCount + ".");
83 // eslint-disable-next-line no-console
84 console.trace();
85 }
86 map.clear();
87 styleCalcCount = 0;
88 // Mutate the options passed in, that's all we can do.
89 options.disableCaching = true;
90 }
91 // Note: the retVal is an attached property on the Map; not a key in the Map. We use this attached property to
92 // cache the return value for this branch of the graph.
93 return current[retVal];
94 };
95 return getClassNames;
96 }
97 exports.classNamesFunction = classNamesFunction;
98 function _traverseEdge(current, value) {
99 value = _normalizeValue(value);
100 if (!current.has(value)) {
101 current.set(value, new Map());
102 }
103 return current.get(value);
104 }
105 function _traverseMap(current, inputs) {
106 if (typeof inputs === 'function') {
107 var cachedInputsFromStyled = inputs.__cachedInputs__;
108 if (cachedInputsFromStyled) {
109 // The styled helper will generate the styles function and will attach the cached
110 // inputs (consisting of the default styles, customzied styles, and user provided styles.)
111 // These should be used as cache keys for deriving the memoized value.
112 for (var _i = 0, _a = inputs.__cachedInputs__; _i < _a.length; _i++) {
113 var input = _a[_i];
114 current = _traverseEdge(current, input);
115 }
116 }
117 else {
118 current = _traverseEdge(current, inputs);
119 }
120 }
121 else if (typeof inputs === 'object') {
122 for (var propName in inputs) {
123 if (inputs.hasOwnProperty(propName)) {
124 current = _traverseEdge(current, inputs[propName]);
125 }
126 }
127 }
128 return current;
129 }
130 function _normalizeValue(value) {
131 switch (value) {
132 case undefined:
133 return '__undefined__';
134 case null:
135 return '__null__';
136 default:
137 return value;
138 }
139 }
140});
141//# sourceMappingURL=classNamesFunction.js.map
\No newline at end of file