Skip to content
This repository has been archived by the owner on Sep 16, 2022. It is now read-only.

Commit

Permalink
Adds ::ng-deep to replace /deep/ and >>>
Browse files Browse the repository at this point in the history
Closes #454.
  • Loading branch information
leonsenft committed Jun 16, 2017
1 parent 2e27883 commit fbe15b5
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 37 deletions.
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
## 3.2.0

### Deprecations

* Support for shadow piercing combinators `/deep/` and `>>>` to prevent style
encapsulation is now deprecated. `/deep/` is already deprecated and will be
[removed in Chrome 60][deep-removal]. Its alias `>>>` is limited to the
[static profile of selectors][static-profile], meaning it's not supported
in style sheets. Continued use of these combinators puts Angular at risk of
incompatibility with common CSS tooling. `::ng-deep` is a drop-in replacement,
intended to provide the same functionality as `/deep/` and `>>>`, without the
need to use deprecated or unsupported CSS syntax.

[deep-removal]: https://www.chromestatus.com/features/4964279606312960
[static-profile]: https://drafts.csswg.org/css-scoping/#deep-combinator

## 3.1.0

### New features
Expand Down
54 changes: 35 additions & 19 deletions lib/src/compiler/shadow_css.dart
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,12 @@ bool matchesElement(SelectorGroup selectorGroup, String name) {
Iterable<SimpleSelectorSequence> clone(Iterable<SimpleSelectorSequence> it) =>
it.map((selector) => selector.clone());

SimpleSelectorSequence createElementSelectorSequence(String name) {
var identifier = new Identifier(name, null);
var selector = new ElementSelector(identifier, null);
return new SimpleSelectorSequence(selector, null);
}

/// Convenience function for terse construction of a class sequence.
SimpleSelectorSequence createClassSelectorSequence(String name) {
var identifier = new Identifier(name, null);
Expand Down Expand Up @@ -301,6 +307,22 @@ class CompoundSelector {
return false;
}

/// Replaces this with an empty type selector if it's `::ng-deep`.
///
/// `::ng-deep` is replaced with an empty tag, rather than removed, to
/// preserve adjacent combinators.
///
/// Returns true if a replacement occurs.
bool removeIfNgDeep() {
if (_sequences.isEmpty) return false;
final selector = _sequences.first.simpleSelector;
if (selector is PseudoElementSelector && selector.name == 'ng-deep') {
_sequences = [createElementSelectorSequence('')..combinator = combinator];
return true;
}
return false;
}

/// Determines the ordering of two selectors in a valid compound selector.
///
/// Returns
Expand Down Expand Up @@ -465,25 +487,17 @@ class ShadowTransformer extends Visitor {
void shimDeepCombinators(ComplexSelector selector, Indices indices) {
for (var i = selector.compoundSelectors.length - 1; i >= 0; i--) {
var compoundSelector = selector.compoundSelectors[i];
switch (compoundSelector.combinator) {
case TokenKind.COMBINATOR_DEEP:
case TokenKind.COMBINATOR_SHADOW_PIERCING_DESCENDANT:
// Replace shadow piercing combinator with descendant combinator.
compoundSelector.combinator = TokenKind.COMBINATOR_DESCENDANT;
indices.deepIndex = i;
break;
case TokenKind.COMBINATOR_PLUS:
case TokenKind.COMBINATOR_TILDE:
if (i > 0) {
var precedingSelector = selector.compoundSelectors[i - 1];
if (precedingSelector.containsHost ||
precedingSelector.containsHostContext) {
// Prevent scoping host siblings.
indices.deepIndex = i;
indices.hostIndex = i - 1;
}
}
break;

// Shim '::ng-deep'
if (compoundSelector.removeIfNgDeep()) indices.deepIndex = i;

// Shim deprecated '>>>' and '/deep/'.
if (compoundSelector.combinator == TokenKind.COMBINATOR_DEEP ||
compoundSelector.combinator ==
TokenKind.COMBINATOR_SHADOW_PIERCING_DESCENDANT) {
// Replace shadow piercing combinator with descendant combinator.
compoundSelector.combinator = TokenKind.COMBINATOR_DESCENDANT;
indices.deepIndex = i;
}
}
}
Expand Down Expand Up @@ -615,6 +629,8 @@ class LegacyShadowTransformer extends ShadowTransformer {
// Don't scope selectors following a shadow host selector.
indices.deepIndex = i;
indices.hostIndex = i;
} else if (compoundSelector.removeIfNgDeep()) {
indices.deepIndex = i;
}
if (compoundSelector.combinator == TokenKind.COMBINATOR_DEEP ||
compoundSelector.combinator ==
Expand Down
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: angular2
version: 3.1.0
version: 3.2.0
author: Dart Team <web@dartlang.org>
description: Framework for modern web applications
homepage: https://webdev.dartlang.org/angular
Expand Down
30 changes: 13 additions & 17 deletions test/compiler/shadow_css_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -114,11 +114,6 @@ void main() {
shimAndExpect(':host.x::before {}', '.$host.x::before {}');
});

test("shouldn't scope siblings", () {
shimAndExpect(':host + .x {}', '.$host + .x {}');
shimAndExpect(':host ~ .x {}', '.$host ~ .x {}');
});

test('should differentiate legacy encapsulation', () {
shimAndExpect(':host p {}', '.$host p.$content {}',
expectedLegacy: '.$host p {}');
Expand Down Expand Up @@ -172,11 +167,6 @@ void main() {
test('should handle multiple selectors', () {
shimAndExpect(':host(.x),:host(a) {}', '.$host.x,a.$host {}');
});

test("shouldn't shim siblings", () {
shimAndExpect(':host(.x) + .y {}', '.$host.x + .y {}');
shimAndExpect(':host(.x) ~ .y {}', '.$host.x ~ .y {}');
});
});

group(':host-context()', () {
Expand Down Expand Up @@ -228,13 +218,6 @@ void main() {
var expected = '.$host.x,.x .$host,.$host.y,.y .$host {}';
shimAndExpect(css, expected);
});

test("shouldn't shim siblings", () {
var css = ':host-context(.x) + .y {}';
shimAndExpect(css, '.$host.x + .y,.x .$host + .y {}');
css = ':host-context(.x) ~ .y {}';
shimAndExpect(css, '.$host.x ~ .y,.x .$host ~ .y {}');
});
});

// Each host selector contributes a host class. For now this duplication is
Expand Down Expand Up @@ -323,6 +306,19 @@ void main() {
shimAndExpect(css, 'x.$content y {}');
});

test('should handle ::ng-deep', () {
var css = '::ng-deep y {}';
shimAndExpect(css, 'y {}');
css = 'x ::ng-deep y {}';
shimAndExpect(css, 'x.$content y {}');
css = ':host > ::ng-deep .x {}';
shimAndExpect(css, '.$host > .x {}');
css = ':host ::ng-deep > .x {}';
shimAndExpect(css, '.$host > .x {}');
css = ':host > ::ng-deep > .x {}';
shimAndExpect(css, '.$host > > .x {}');
});

test('should pass through @import directives', () {
var css = '@import url("https://fonts.googleapis.com/css?family=Roboto");';
shimAndExpect(css, css);
Expand Down

0 comments on commit fbe15b5

Please sign in to comment.