All files / dom/src bind-attrs-to-cssom.js

82.14% Statements 23/28
66.67% Branches 4/6
100% Functions 5/5
82.14% Lines 23/28
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60      1x 1x 1x                   1x 1x 1x 1x 1x 1x                                     1x 1x 1x 1x 1x 1x 1x 1x   1x 1x 1x 1x 1x     1x        
import onDOMLoad from './on-dom-load';
 
function getFirstStyleSheet() {
  const [firstStyleSheet] = document.styleSheets;
  Eif (firstStyleSheet) {
    return firstStyleSheet;
  } else {
    const styleElement = document.createElement('style');
    styleElement.setAttribute('type', 'text/css');
    document.head.appendChild(styleElement);
    return styleElement.sheet;
  }
}
 
function insertCSSRule(selector, rule) {
  for (const cssStylesheet of document.styleSheets) {
    for (let i = 0; i < cssStylesheet.cssRules.length; i++) {
      const cssRule = cssStylesheet.cssRules[i];
      Eif (cssRule.selectorText && cssRule.selectorText.includes(selector)) {
        cssStylesheet.insertRule(rule, i + 1);
        return cssStylesheet.cssRules[i + 1];
      }
    }
  }
  throw new Error(
    'A CSS rule used by a Stylesheet component was not found. Make sure you imported the source CSS correctly'
  );
}
 
/**
 * @typedef {Attr} BoundAttr Attr bound to a CSSOM rule
 * @property {CSSRule} cssRule will be used to apply the result of the attr declaration
 * @property {string} className cssRule's class name
 */
 
/**
 * @param {Attr[]} attrs
 * @returns {BoundAttr[]}
 */
const bindAttrsToCSSOM = attrs => {
  const firstStyleSheet = getFirstStyleSheet();
  const boundAttrs = attrs.map(attr => {
    const className = 'a' + Math.random().toString(32).slice(6);
    const cssRuleIndex = firstStyleSheet.cssRules.length;
    firstStyleSheet.insertRule(`${ attr.selector }.${ className } {}`, cssRuleIndex);
    const cssRule = firstStyleSheet.cssRules[cssRuleIndex];
    return { ...attr, className, cssRule };
  });
  onDOMLoad(() => {
    for (const attr of boundAttrs) {
      const cssRuleIndex = [...firstStyleSheet.cssRules].indexOf(attr.cssRule);
      firstStyleSheet.deleteRule(cssRuleIndex);
      attr.cssRule = insertCSSRule(attr.selector, attr.cssRule.cssText);
    }
  });
  return boundAttrs;
};
 
export default bindAttrsToCSSOM;