|
10 | 10 | * https://github.com/angular/angular/blob/master/packages/compiler/src/shadow_css.ts
|
11 | 11 | */
|
12 | 12 |
|
| 13 | +import { escapeRegExpSpecialCharacters } from './regular-expression'; |
| 14 | + |
13 | 15 | const safeSelector = (selector: string) => {
|
14 | 16 | const placeholders: string[] = [];
|
15 | 17 | let index = 0;
|
@@ -279,9 +281,9 @@ const convertColonSlotted = (cssText: string, slotScopeId: string) => {
|
279 | 281 | prefixSelector = char + prefixSelector;
|
280 | 282 | }
|
281 | 283 |
|
282 |
| - const orgSelector = prefixSelector + slottedSelector; |
283 |
| - const addedSelector = `${prefixSelector.trimRight()}${slottedSelector.trim()}`; |
284 |
| - if (orgSelector.trim() !== addedSelector.trim()) { |
| 284 | + const orgSelector = (prefixSelector + slottedSelector).trim(); |
| 285 | + const addedSelector = `${prefixSelector.trimEnd()}${slottedSelector.trim()}`.trim(); |
| 286 | + if (orgSelector !== addedSelector) { |
285 | 287 | const updatedSelector = `${addedSelector}, ${orgSelector}`;
|
286 | 288 | selectors.push({
|
287 | 289 | orgSelector,
|
@@ -471,15 +473,32 @@ const scopeCssText = (
|
471 | 473 | cssText = scopeSelectors(cssText, scopeId, hostScopeId, slotScopeId, commentOriginalSelector);
|
472 | 474 | }
|
473 | 475 |
|
474 |
| - cssText = cssText.replace(/-shadowcsshost-no-combinator/g, `.${hostScopeId}`); |
| 476 | + cssText = replaceShadowCssHost(cssText, hostScopeId); |
475 | 477 | cssText = cssText.replace(/>\s*\*\s+([^{, ]+)/gm, ' $1 ');
|
476 | 478 |
|
477 | 479 | return {
|
478 | 480 | cssText: cssText.trim(),
|
479 |
| - slottedSelectors: slotted.selectors, |
| 481 | + // We need to replace the shadow CSS host string in each of these selectors since we created |
| 482 | + // them prior to the replacement happening in the components CSS text. |
| 483 | + slottedSelectors: slotted.selectors.map((ref) => ({ |
| 484 | + orgSelector: replaceShadowCssHost(ref.orgSelector, hostScopeId), |
| 485 | + updatedSelector: replaceShadowCssHost(ref.updatedSelector, hostScopeId), |
| 486 | + })), |
480 | 487 | };
|
481 | 488 | };
|
482 | 489 |
|
| 490 | +/** |
| 491 | + * Helper function that replaces the interim string representing a `:host` selector with |
| 492 | + * the host scope selector class for the element. |
| 493 | + * |
| 494 | + * @param cssText The CSS string to make the replacement in |
| 495 | + * @param hostScopeId The scope ID that will be used as the class representing the host element |
| 496 | + * @returns CSS with the selector replaced |
| 497 | + */ |
| 498 | +const replaceShadowCssHost = (cssText: string, hostScopeId: string) => { |
| 499 | + return cssText.replace(/-shadowcsshost-no-combinator/g, `.${hostScopeId}`); |
| 500 | +}; |
| 501 | + |
483 | 502 | export const scopeCss = (cssText: string, scopeId: string, commentOriginalSelector: boolean) => {
|
484 | 503 | const hostScopeId = scopeId + '-h';
|
485 | 504 | const slotScopeId = scopeId + '-s';
|
@@ -528,7 +547,8 @@ export const scopeCss = (cssText: string, scopeId: string, commentOriginalSelect
|
528 | 547 | }
|
529 | 548 |
|
530 | 549 | scoped.slottedSelectors.forEach((slottedSelector) => {
|
531 |
| - cssText = cssText.replace(slottedSelector.orgSelector, slottedSelector.updatedSelector); |
| 550 | + const regex = new RegExp(escapeRegExpSpecialCharacters(slottedSelector.orgSelector), 'g'); |
| 551 | + cssText = cssText.replace(regex, slottedSelector.updatedSelector); |
532 | 552 | });
|
533 | 553 |
|
534 | 554 | return cssText;
|
|
0 commit comments