Skip to content

Commit

Permalink
Merge styles order (#4664)
Browse files Browse the repository at this point in the history
* Updating how style elements are injected (to preserve the location in head in which they're inserted.)

* adding change file

* Adding nit fixes.
  • Loading branch information
dzearing authored Apr 25, 2018
1 parent 6bfddc1 commit 1d305b5
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 33 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"changes": [
{
"packageName": "@uifabric/merge-styles",
"comment": "merge-styles: `style` elements which are created on the fly now \"bunch\" together, avoiding unpredictability in specificity.",
"type": "patch"
}
],
"packageName": "@uifabric/merge-styles",
"email": "[email protected]"
}
72 changes: 39 additions & 33 deletions packages/merge-styles/src/Stylesheet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ let _stylesheet: Stylesheet;
* @public
*/
export class Stylesheet {
private _lastStyleElement?: HTMLStyleElement;
private _styleElement?: HTMLStyleElement;
private _rules: string[] = [];
private _config: IStyleSheetConfig;
Expand Down Expand Up @@ -158,28 +159,29 @@ export class Stylesheet {
public insertRule(
rule: string
): void {
const element = this._getElement();
const injectionMode = element ? this._config.injectionMode : InjectionMode.none;

switch (injectionMode) {
case InjectionMode.insertNode:
const { sheet } = element!;

try {
// tslint:disable-next-line:no-any
(sheet as any).insertRule(rule, (sheet as any).cssRules.length);
} catch (e) {
/* no-op on errors */
}
break;

case InjectionMode.appendChild:
_createStyleElement(rule);
break;

default:
this._rules.push(rule);
break;
const { injectionMode } = this._config;
const element = injectionMode !== InjectionMode.none ? this._getStyleElement() : undefined;

if (element) {
switch (this._config.injectionMode) {
case InjectionMode.insertNode:
const { sheet } = element!;

try {
(sheet as CSSStyleSheet).insertRule(rule, (sheet as CSSStyleSheet).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) {
Expand Down Expand Up @@ -212,9 +214,9 @@ export class Stylesheet {
this._keyToClassName = {};
}

private _getElement(): HTMLStyleElement | undefined {
private _getStyleElement(): HTMLStyleElement | undefined {
if (!this._styleElement && typeof document !== 'undefined') {
this._styleElement = _createStyleElement();
this._styleElement = this._createStyleElement();

// Reset the style element on the next frame.
window.requestAnimationFrame(() => {
Expand All @@ -223,17 +225,21 @@ export class Stylesheet {
}
return this._styleElement;
}
}

function _createStyleElement(content?: string): HTMLStyleElement {
const styleElement = document.createElement('style');
private _createStyleElement(): HTMLStyleElement {
const styleElement = document.createElement('style');

styleElement.setAttribute('data-merge-styles', 'true');
styleElement.type = 'text/css';

if (this._lastStyleElement && this._lastStyleElement.nextElementSibling) {
document.head.insertBefore(styleElement, this._lastStyleElement.nextElementSibling);
} else {
document.head.appendChild(styleElement);
}
this._lastStyleElement = styleElement;

styleElement.setAttribute('data-merge-styles', 'true');
styleElement.type = 'text/css';
if (content) {
styleElement.appendChild(document.createTextNode(content));
return styleElement;
}
document.head.appendChild(styleElement);

return styleElement;
}

0 comments on commit 1d305b5

Please sign in to comment.