UNPKG

ionicons

Version:

Premium icons for Ionic.

432 lines (431 loc) 18.7 kB
/** * @license * Copyright Google Inc. All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license * * This file is a port of shadowCSS from webcomponents.js to TypeScript. * https://github.com/webcomponents/webcomponentsjs/blob/4efecd7e0e/src/ShadowCSS/ShadowCSS.js * https://github.com/angular/angular/blob/master/packages/compiler/src/shadow_css.ts */ function scopeCss(cssText, scopeId, commentOriginalSelector) { var sc = new ShadowCss(); return sc.shimCssText(cssText, scopeId, scopeId + '-h', scopeId + '-s', commentOriginalSelector); } var ShadowCss = /** @class */ (function () { function ShadowCss() { this.strictStyling = true; } ShadowCss.prototype.shimCssText = function (cssText, scopeId, hostScopeId, slotScopeId, commentOriginalSelector) { if (hostScopeId === void 0) { hostScopeId = ''; } if (slotScopeId === void 0) { slotScopeId = ''; } if (commentOriginalSelector === void 0) { commentOriginalSelector = false; } var commentsWithHash = extractCommentsWithHash(cssText); cssText = stripComments(cssText); var orgSelectors = []; if (commentOriginalSelector) { var processCommentedSelector_1 = function (rule) { var placeholder = "/*!@___" + orgSelectors.length + "___*/"; var comment = "/*!@" + rule.selector + "*/"; orgSelectors.push({ placeholder: placeholder, comment: comment }); rule.selector = placeholder + rule.selector; return rule; }; cssText = processRules(cssText, function (rule) { if (rule.selector[0] !== '@') { return processCommentedSelector_1(rule); } else if (rule.selector.startsWith('@media') || rule.selector.startsWith('@supports') || rule.selector.startsWith('@page') || rule.selector.startsWith('@document')) { rule.content = processRules(rule.content, processCommentedSelector_1); return rule; } return rule; }); } var scopedCssText = this._scopeCssText(cssText, scopeId, hostScopeId, slotScopeId, commentOriginalSelector); cssText = [scopedCssText].concat(commentsWithHash).join('\n'); if (commentOriginalSelector) { orgSelectors.forEach(function (_a) { var placeholder = _a.placeholder, comment = _a.comment; cssText = cssText.replace(placeholder, comment); }); } return cssText; }; ShadowCss.prototype._scopeCssText = function (cssText, scopeId, hostScopeId, slotScopeId, commentOriginalSelector) { // replace :host and :host-context -shadowcsshost and -shadowcsshost respectively cssText = this._insertPolyfillHostInCssText(cssText); cssText = this._convertColonHost(cssText); cssText = this._convertColonHostContext(cssText); cssText = this._convertColonSlotted(cssText, slotScopeId); cssText = this._convertShadowDOMSelectors(cssText); if (scopeId) { cssText = this._scopeSelectors(cssText, scopeId, hostScopeId, slotScopeId, commentOriginalSelector); } cssText = cssText.replace(/-shadowcsshost-no-combinator/g, "." + hostScopeId); cssText = cssText.replace(/>\s*\*\s+([^{, ]+)/gm, ' $1 '); return cssText.trim(); }; /* * convert a rule like :host(.foo) > .bar { } * * to * * .foo<scopeName> > .bar */ ShadowCss.prototype._convertColonHost = function (cssText) { return this._convertColonRule(cssText, _cssColonHostRe, this._colonHostPartReplacer); }; /* * convert a rule like ::slotted(.foo) { } */ ShadowCss.prototype._convertColonSlotted = function (cssText, slotAttr) { var regExp = _cssColonSlottedRe; return cssText.replace(regExp, function () { var m = []; for (var _i = 0; _i < arguments.length; _i++) { m[_i] = arguments[_i]; } if (m[2]) { var compound = m[2].trim(); var suffix = m[3]; var sel = '.' + slotAttr + ' > ' + compound + suffix; return sel; } else { return _polyfillHostNoCombinator + m[3]; } }); }; /* * convert a rule like :host-context(.foo) > .bar { } * * to * * .foo<scopeName> > .bar, .foo scopeName > .bar { } * * and * * :host-context(.foo:host) .bar { ... } * * to * * .foo<scopeName> .bar { ... } */ ShadowCss.prototype._convertColonHostContext = function (cssText) { return this._convertColonRule(cssText, _cssColonHostContextRe, this._colonHostContextPartReplacer); }; ShadowCss.prototype._convertColonRule = function (cssText, regExp, partReplacer) { // m[1] = :host(-context), m[2] = contents of (), m[3] rest of rule return cssText.replace(regExp, function () { var m = []; for (var _i = 0; _i < arguments.length; _i++) { m[_i] = arguments[_i]; } if (m[2]) { var parts = m[2].split(','); var r = []; for (var i = 0; i < parts.length; i++) { var p = parts[i].trim(); if (!p) break; r.push(partReplacer(_polyfillHostNoCombinator, p, m[3])); } return r.join(','); } else { return _polyfillHostNoCombinator + m[3]; } }); }; ShadowCss.prototype._colonHostContextPartReplacer = function (host, part, suffix) { if (part.indexOf(_polyfillHost) > -1) { return this._colonHostPartReplacer(host, part, suffix); } else { return host + part + suffix + ', ' + part + ' ' + host + suffix; } }; ShadowCss.prototype._colonHostPartReplacer = function (host, part, suffix) { return host + part.replace(_polyfillHost, '') + suffix; }; /* * Convert combinators like ::shadow and pseudo-elements like ::content * by replacing with space. */ ShadowCss.prototype._convertShadowDOMSelectors = function (cssText) { return _shadowDOMSelectorsRe.reduce(function (result, pattern) { return result.replace(pattern, ' '); }, cssText); }; // change a selector like 'div' to 'name div' ShadowCss.prototype._scopeSelectors = function (cssText, scopeSelector, hostSelector, slotSelector, commentOriginalSelector) { var _this = this; return processRules(cssText, function (rule) { var selector = rule.selector; var content = rule.content; if (rule.selector[0] !== '@') { selector = _this._scopeSelector(rule.selector, scopeSelector, hostSelector, slotSelector, _this.strictStyling); } else if (rule.selector.startsWith('@media') || rule.selector.startsWith('@supports') || rule.selector.startsWith('@page') || rule.selector.startsWith('@document')) { content = _this._scopeSelectors(rule.content, scopeSelector, hostSelector, slotSelector, commentOriginalSelector); } selector = selector.replace(/\s{2,}/g, ' ').trim(); return new CssRule(selector, content); }); }; ShadowCss.prototype._scopeSelector = function (selector, scopeSelector, hostSelector, slotSelector, strict) { var _this = this; return selector.split(',') .map(function (shallowPart) { if (slotSelector && shallowPart.indexOf('.' + slotSelector) > -1) { return shallowPart.trim(); } if (_this._selectorNeedsScoping(shallowPart, scopeSelector)) { return strict ? _this._applyStrictSelectorScope(shallowPart, scopeSelector, hostSelector).trim() : _this._applySelectorScope(shallowPart, scopeSelector, hostSelector).trim(); } else { return shallowPart.trim(); } }) .join(', '); }; ShadowCss.prototype._selectorNeedsScoping = function (selector, scopeSelector) { var re = this._makeScopeMatcher(scopeSelector); return !re.test(selector); }; ShadowCss.prototype._makeScopeMatcher = function (scopeSelector) { var lre = /\[/g; var rre = /\]/g; scopeSelector = scopeSelector.replace(lre, '\\[').replace(rre, '\\]'); return new RegExp('^(' + scopeSelector + ')' + _selectorReSuffix, 'm'); }; ShadowCss.prototype._applySelectorScope = function (selector, scopeSelector, hostSelector) { // Difference from webcomponents.js: scopeSelector could not be an array return this._applySimpleSelectorScope(selector, scopeSelector, hostSelector); }; // scope via name and [is=name] ShadowCss.prototype._applySimpleSelectorScope = function (selector, scopeSelector, hostSelector) { // In Android browser, the lastIndex is not reset when the regex is used in String.replace() _polyfillHostRe.lastIndex = 0; if (_polyfillHostRe.test(selector)) { var replaceBy_1 = this.strictStyling ? "." + hostSelector : scopeSelector; return selector .replace(_polyfillHostNoCombinatorRe, function (_, selector) { return selector.replace(/([^:]*)(:*)(.*)/, function (_, before, colon, after) { return before + replaceBy_1 + colon + after; }); }) .replace(_polyfillHostRe, replaceBy_1 + ' '); } return scopeSelector + ' ' + selector; }; ShadowCss.prototype._applyStrictSelectorScope = function (selector, scopeSelector, hostSelector) { var _this = this; var isRe = /\[is=([^\]]*)\]/g; scopeSelector = scopeSelector.replace(isRe, function (_) { var parts = []; for (var _i = 1; _i < arguments.length; _i++) { parts[_i - 1] = arguments[_i]; } return parts[0]; }); var className = '.' + scopeSelector; var _scopeSelectorPart = function (p) { var scopedP = p.trim(); if (!scopedP) { return ''; } if (p.indexOf(_polyfillHostNoCombinator) > -1) { scopedP = _this._applySimpleSelectorScope(p, scopeSelector, hostSelector); } else { // remove :host since it should be unnecessary var t = p.replace(_polyfillHostRe, ''); if (t.length > 0) { var matches = t.match(/([^:]*)(:*)(.*)/); if (matches) { scopedP = matches[1] + className + matches[2] + matches[3]; } } } return scopedP; }; var safeContent = new SafeSelector(selector); selector = safeContent.content(); var scopedSelector = ''; var startIndex = 0; var res; var sep = /( |>|\+|~(?!=))\s*/g; // If a selector appears before :host it should not be shimmed as it // matches on ancestor elements and not on elements in the host's shadow // `:host-context(div)` is transformed to // `-shadowcsshost-no-combinatordiv, div -shadowcsshost-no-combinator` // the `div` is not part of the component in the 2nd selectors and should not be scoped. // Historically `component-tag:host` was matching the component so we also want to preserve // this behavior to avoid breaking legacy apps (it should not match). // The behavior should be: // - `tag:host` -> `tag[h]` (this is to avoid breaking legacy apps, should not match anything) // - `tag :host` -> `tag [h]` (`tag` is not scoped because it's considered part of a // `:host-context(tag)`) var hasHost = selector.indexOf(_polyfillHostNoCombinator) > -1; // Only scope parts after the first `-shadowcsshost-no-combinator` when it is present var shouldScope = !hasHost; while ((res = sep.exec(selector)) !== null) { var separator = res[1]; var part_1 = selector.slice(startIndex, res.index).trim(); shouldScope = shouldScope || part_1.indexOf(_polyfillHostNoCombinator) > -1; var scopedPart = shouldScope ? _scopeSelectorPart(part_1) : part_1; scopedSelector += scopedPart + " " + separator + " "; startIndex = sep.lastIndex; } var part = selector.substring(startIndex); shouldScope = shouldScope || part.indexOf(_polyfillHostNoCombinator) > -1; scopedSelector += shouldScope ? _scopeSelectorPart(part) : part; // replace the placeholders with their original values return safeContent.restore(scopedSelector); }; ShadowCss.prototype._insertPolyfillHostInCssText = function (selector) { selector = selector .replace(_colonHostContextRe, _polyfillHostContext) .replace(_colonHostRe, _polyfillHost) .replace(_colonSlottedRe, _polyfillSlotted); return selector; }; return ShadowCss; }()); var SafeSelector = /** @class */ (function () { function SafeSelector(selector) { var _this = this; this.placeholders = []; this.index = 0; // Replaces attribute selectors with placeholders. // The WS in [attr="va lue"] would otherwise be interpreted as a selector separator. selector = selector.replace(/(\[[^\]]*\])/g, function (_, keep) { var replaceBy = "__ph-" + _this.index + "__"; _this.placeholders.push(keep); _this.index++; return replaceBy; }); // Replaces the expression in `:nth-child(2n + 1)` with a placeholder. // WS and "+" would otherwise be interpreted as selector separators. this._content = selector.replace(/(:nth-[-\w]+)(\([^)]+\))/g, function (_, pseudo, exp) { var replaceBy = "__ph-" + _this.index + "__"; _this.placeholders.push(exp); _this.index++; return pseudo + replaceBy; }); } SafeSelector.prototype.restore = function (content) { var _this = this; return content.replace(/__ph-(\d+)__/g, function (_, index) { return _this.placeholders[+index]; }); }; SafeSelector.prototype.content = function () { return this._content; }; return SafeSelector; }()); var _polyfillHost = '-shadowcsshost'; var _polyfillSlotted = '-shadowcssslotted'; // note: :host-context pre-processed to -shadowcsshostcontext. var _polyfillHostContext = '-shadowcsscontext'; var _parenSuffix = ')(?:\\((' + '(?:\\([^)(]*\\)|[^)(]*)+?' + ')\\))?([^,{]*)'; var _cssColonHostRe = new RegExp('(' + _polyfillHost + _parenSuffix, 'gim'); var _cssColonHostContextRe = new RegExp('(' + _polyfillHostContext + _parenSuffix, 'gim'); var _cssColonSlottedRe = new RegExp('(' + _polyfillSlotted + _parenSuffix, 'gim'); var _polyfillHostNoCombinator = _polyfillHost + '-no-combinator'; var _polyfillHostNoCombinatorRe = /-shadowcsshost-no-combinator([^\s]*)/; var _shadowDOMSelectorsRe = [ /::shadow/g, /::content/g ]; var _selectorReSuffix = '([>\\s~+\[.,{:][\\s\\S]*)?$'; var _polyfillHostRe = /-shadowcsshost/gim; var _colonHostRe = /:host/gim; var _colonSlottedRe = /::slotted/gim; var _colonHostContextRe = /:host-context/gim; var _commentRe = /\/\*\s*[\s\S]*?\*\//g; function stripComments(input) { return input.replace(_commentRe, ''); } var _commentWithHashRe = /\/\*\s*#\s*source(Mapping)?URL=[\s\S]+?\*\//g; function extractCommentsWithHash(input) { return input.match(_commentWithHashRe) || []; } var _ruleRe = /(\s*)([^;\{\}]+?)(\s*)((?:{%BLOCK%}?\s*;?)|(?:\s*;))/g; var _curlyRe = /([{}])/g; var OPEN_CURLY = '{'; var CLOSE_CURLY = '}'; var BLOCK_PLACEHOLDER = '%BLOCK%'; var CssRule = /** @class */ (function () { function CssRule(selector, content) { this.selector = selector; this.content = content; } return CssRule; }()); function processRules(input, ruleCallback) { var inputWithEscapedBlocks = escapeBlocks(input); var nextBlockIndex = 0; return inputWithEscapedBlocks.escapedString.replace(_ruleRe, function () { var m = []; for (var _i = 0; _i < arguments.length; _i++) { m[_i] = arguments[_i]; } var selector = m[2]; var content = ''; var suffix = m[4]; var contentPrefix = ''; if (suffix && suffix.startsWith('{' + BLOCK_PLACEHOLDER)) { content = inputWithEscapedBlocks.blocks[nextBlockIndex++]; suffix = suffix.substring(BLOCK_PLACEHOLDER.length + 1); contentPrefix = '{'; } var rule = ruleCallback(new CssRule(selector, content)); return "" + m[1] + rule.selector + m[3] + contentPrefix + rule.content + suffix; }); } var StringWithEscapedBlocks = /** @class */ (function () { function StringWithEscapedBlocks(escapedString, blocks) { this.escapedString = escapedString; this.blocks = blocks; } return StringWithEscapedBlocks; }()); function escapeBlocks(input) { var inputParts = input.split(_curlyRe); var resultParts = []; var escapedBlocks = []; var bracketCount = 0; var currentBlockParts = []; for (var partIndex = 0; partIndex < inputParts.length; partIndex++) { var part = inputParts[partIndex]; if (part === CLOSE_CURLY) { bracketCount--; } if (bracketCount > 0) { currentBlockParts.push(part); } else { if (currentBlockParts.length > 0) { escapedBlocks.push(currentBlockParts.join('')); resultParts.push(BLOCK_PLACEHOLDER); currentBlockParts = []; } resultParts.push(part); } if (part === OPEN_CURLY) { bracketCount++; } } if (currentBlockParts.length > 0) { escapedBlocks.push(currentBlockParts.join('')); resultParts.push(BLOCK_PLACEHOLDER); } return new StringWithEscapedBlocks(resultParts.join(''), escapedBlocks); } export { ShadowCss, scopeCss };