import { CSSScope } from './interfaces' ; import { addGlobalStyle , updateGlobalScopes } from './scope' ; export function loadDocument ( doc , globalScopes ) { loadDocumentStyles ( doc , globalScopes ) ; return loadDocumentLinks ( doc , globalScopes ) . then ( ( ) => { updateGlobalScopes ( globalScopes ) ; } ) ; } export function startWatcher ( doc , globalScopes ) { if ( typeof MutationObserver !== 'undefined' ) { const mutation = new MutationObserver ( ( ) => { if ( loadDocumentStyles ( doc , globalScopes ) ) { updateGlobalScopes ( globalScopes ) ; } } ) ; mutation . observe ( document . head , { childList : true } ) ; } } export function loadDocumentLinks ( doc , globalScopes ) { const promises = [ ] ; const linkElms = doc . querySelectorAll ( 'link[rel="stylesheet"][href]:not([data-no-shim])' ) ; for ( let i = 0 ; i < linkElms . length ; i ++ ) { promises . push ( addGlobalLink ( doc , globalScopes , linkElms [ i ] as HTMLLinkElement ) ) ; } return Promise . all ( promises ) ; } export function loadDocumentStyles ( doc , globalScopes ) { const styleElms = Array . from ( doc . querySelectorAll ( 'style:not([data-styles]):not([data-no-shim])' ) ) as HTMLStyleElement [ ] ; return styleElms . map ( ( style ) => addGlobalStyle ( globalScopes , style ) ) . some ( Boolean ) ; } export function addGlobalLink ( doc , globalScopes , linkElm ) { const url = linkElm . href ; return fetch ( url ) . then ( ( rsp ) => rsp . text ( ) ) . then ( ( text ) => { if ( hasCssVariables ( text ) && linkElm . parentNode ) { if ( hasRelativeUrls ( text ) ) { text = fixRelativeUrls ( text , url ) ; } const styleEl = doc . createElement ( 'style' ) ; styleEl . setAttribute ( 'data-styles' , '' ) ; styleEl . textContent = text ; addGlobalStyle ( globalScopes , styleEl ) ; linkElm . parentNode . insertBefore ( styleEl , linkElm ) ; linkElm . remove ( ) ; } } ) . catch ( ( err ) => { console . error ( err ) ; } ) ; } const CSS_VARIABLE_REGEXP = /[\s;{]--[-a-zA-Z0-9]+\s*:/m ; export function hasCssVariables ( css ) { return css . indexOf ( 'var(' ) > - 1 || CSS_VARIABLE_REGEXP . test ( css ) ; } const CSS_URL_REGEXP = /url[\s]*\([\s]*['"]?(?!(?:https?|data)\:|\/)([^\'\"\)]*)[\s]*['"]?\)[\s]*/gim ; export function hasRelativeUrls ( css ) { CSS_URL_REGEXP . lastIndex = 0 ; return CSS_URL_REGEXP . test ( css ) ; } export function fixRelativeUrls ( css , originalUrl ) { const basePath = originalUrl . replace ( /[^/]*$/ , '' ) ; return css . replace ( CSS_URL_REGEXP , ( fullMatch , url ) => { const relativeUrl = basePath + url ; return fullMatch . replace ( url , relativeUrl ) ; } ) ; }