Replaces style-properties with *experimental* x-style element:

* shims ::shadow, /deep/
* avoids applying styles inside roots
* can be used to set root custom property values
This commit is contained in:
Steven Orvell
2015-03-17 06:49:46 -07:00
parent 8862974b3f
commit e0b4575808
9 changed files with 184 additions and 62 deletions

View File

@@ -51,7 +51,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
</script>
<link rel="import" href="src/lib/style-properties.html">
<link rel="import" href="src/lib/x-style.html">
<link rel="import" href="src/lib/template/x-autobind.html">
<link rel="import" href="src/lib/template/x-template.html">
<link rel="import" href="src/lib/template/x-repeat.html">

View File

@@ -1,6 +1,9 @@
<link rel="import" href="../lib/x-style.html">
<script>
(function() {
var transformer = document.createElement('style', 'x-style');
var styleProtector = {
scopeDocumentSheets: function() {
@@ -22,34 +25,17 @@
scopeSheet: function(sheet) {
var owner = sheet.ownerNode;
var css = this.sheetToScopedCss(sheet);
var cssText = transformer.scopeCssText(this.rulesToCss(sheet.cssRules));
if (owner.localName === 'link') {
var style = document.createElement('style');
style.textContent = css;
style.textContent = cssText;
owner.parentNode.insertBefore(style, owner);
owner.parentNode.removeChild(owner);
} else {
owner.textContent = css;
owner.textContent = cssText;
}
},
sheetToScopedCss: function(sheet) {
var css = this.rulesToCss(sheet.cssRules);
var rules = Polymer.CssParse.parse(css);
var self = this;
Polymer.StyleUtil.forEachStyleRule(rules, function(r) {
r.selector = self.scopeSelector(r.selector);
});
return Polymer.CssParse.stringify(rules);
},
scopeSelector: function(selector) {
var parts = selector.split(this.SELECTOR_SEP);
return parts.map(function(p) {
return p.trim() + this.SCOPE_SELECTOR;
}, this).join(this.SELECTOR_SEP);
},
rulesToCss: function(cssRules) {
for (var i=0, css=[]; i < cssRules.length; i++) {
css.push(cssRules[i].cssText);
@@ -57,9 +43,7 @@
return css.join('\n\n');
},
SCOPE_SELECTOR: ':not([style-scope])',
SCOPE_ATTR: 'needs-scoping',
SELECTOR_SEP: ','
SCOPE_ATTR: 'needs-scoping'
};
addEventListener('DOMContentLoaded', styleProtector.scopeDocumentSheets());

View File

@@ -107,7 +107,9 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
for (var i=0, l=styles.length, s; (i<l) && (s=styles[i]); i++) {
// transform style if necessary and place in correct place
if (Polymer.Settings.useNativeShadow) {
this._template.content.appendChild(s);
if (this._template) {
this._template.content.appendChild(s);
}
} else {
var rules = this._rulesForStyle(s);
Polymer.StyleUtil.applyCss(

View File

@@ -20,20 +20,11 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
Polymer.StyleUtil.parser.parse(defaultSheet.textContent);
}
function applyStyle(style) {
if (style.parentNode) {
style.parentNode.removeChild(style);
}
applyCss(style.textContent);
}
applyCss('');
// exports
Polymer.StyleDefaults = {
applyCss: applyCss,
applyStyle: applyStyle,
defaultSheet: defaultSheet
};

View File

@@ -1,22 +0,0 @@
<!--
@license
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
-->
<link rel="import" href="style-defaults.html">
<script>
// allow specification of defaults using <style is="style-properties">
Polymer({
is: 'style-properties',
extends: 'style',
created: function() {
Polymer.StyleDefaults.applyStyle(this);
}
});
</script>

View File

@@ -78,19 +78,22 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
return ext ? '[is=' + scope + ']' : scope;
}
// transforms a css rule to a scoped rule.
function transformRule(rule, scope, hostScope) {
_transformRule(rule, transformComplexSelector,
scope, hostScope);
}
// transforms a css rule to a scoped rule.
function _transformRule(rule, transformer, scope, hostScope) {
var p$ = rule.selector.split(COMPLEX_SELECTOR_SEP);
for (var i=0, l=p$.length, p; (i<l) && (p=p$[i]); i++) {
p$[i] = transformComplexSelector(p, scope, hostScope);
p$[i] = transformer(p, scope, hostScope);
}
rule.selector = p$.join(COMPLEX_SELECTOR_SEP);
}
function transformComplexSelector(selector, scope, hostScope) {
var stop = false;
var o = selector;
selector = selector.replace(SIMPLE_SELECTOR_SEP, function(m, c, s) {
if (!stop) {
var o = transformCompoundSelector(s, c, scope, hostScope);
@@ -117,7 +120,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
selector = selector.replace(HOST, hostScope);
// replace other selectors with scoping class
} else if (jumpIndex !== 0) {
selector = transformSimpleSelector(selector, scope);
selector = scope ? transformSimpleSelector(selector, scope) : selector;
}
// remove left-side combinator when dealing with ::content.
if (selector.indexOf(CONTENT) >= 0) {
@@ -139,7 +142,18 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
return p$.join(PSEUDO_PREFIX);
}
function transformRootRule(rule) {
_transformRule(rule, transformRootSelector);
}
function transformRootSelector(selector) {
return selector.match(SCOPE_JUMP) ?
transformComplexSelector(selector) :
selector.trim() + SCOPE_ROOT_SELECTOR;
}
var SCOPE_ATTR = 'style-scope';
var SCOPE_ROOT_SELECTOR = ':not([' + SCOPE_ATTR + '])';
var SCOPE_SUFFIX = '';
var COMPLEX_SELECTOR_SEP = ',';
var SIMPLE_SELECTOR_SEP = /(^|[\s>+~]+)([^\s>+~]+)/g;
@@ -161,6 +175,8 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
dom: transformDom,
host: transformHost,
css: transformCss,
rule: transformRule,
rootRule: transformRootRule,
SCOPE_SUFFIX: SCOPE_SUFFIX
};

61
src/lib/x-style.html Normal file
View File

@@ -0,0 +1,61 @@
<!--
@license
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
-->
<link rel="import" href="style-util.html">
<link rel="import" href="style-transformer.html">
<link rel="import" href="style-defaults.html">
<script>
(function() {
Polymer({
is: 'x-style',
extends: 'style',
created: function() {
var rules = Polymer.StyleUtil.parser.parse(this.textContent);
this.applyProperties(rules);
// TODO(sorvell): since custom rules must match directly, they tend to be
// made with selectors like `*`.
// We *remove them here* so they don't apply too widely and nerf recalc.
// This means that normal properties mixe in rules with custom
// properties will *not* apply.
var cssText = Polymer.StyleUtil.parser.stringify(rules);
this.textContent = this.scopeCssText(cssText);
},
scopeCssText: function(cssText) {
return Polymer.Settings.useNativeShadow ?
cssText :
Polymer.StyleUtil.toCssText(cssText, function(rule) {
Polymer.StyleTransformer.rootRule(rule);
});
},
applyProperties: function(rules) {
var cssText = '';
Polymer.StyleUtil.forEachStyleRule(rules, function(rule) {
if (rule.cssText.match(CUSTOM_RULE)) {
// TODO(sorvell): use parser.stringify, it needs an option not to
// strip custom properties.
cssText += rule.selector + ' {\n' + rule.cssText + '\n}\n';
}
});
if (cssText) {
Polymer.StyleDefaults.applyCss(cssText);
}
}
});
var CUSTOM_RULE = /--[^;{'"]*\:/;
})();
</script>

View File

@@ -33,7 +33,8 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
'unit/resolveurl.html',
'unit/css-parse.html',
'unit/styling-scoped.html',
'unit/styling-remote.html'
'unit/styling-remote.html',
'unit/x-style.html'
]);
</script>
</body>

89
test/unit/x-style.html Normal file
View File

@@ -0,0 +1,89 @@
<!doctype html>
<!--
@license
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
-->
<html>
<head>
<meta charset="utf-8">
<script src="../../../webcomponentsjs/webcomponents-lite.js"></script>
<script src="../../../web-component-tester/browser.js"></script>
<link rel="import" href="../../polymer.html">
<style is="x-style">
x-bar {
border: 1px solid red;
display: block;
}
x-foo::shadow #bar2 {
border: 2px solid orange;
display: block;
}
</style>
</head>
<body>
<x-bar></x-bar>
<x-foo></x-foo>
<dom-module id="x-foo">
<template>
<div>x-foo</div>
<x-bar id="bar1"></x-bar>
<x-bar id="bar2"></x-bar>
</template>
</dom-module>
<dom-module id="x-bar">
<template>
<div>x-bar</div>
</template>
</dom-module>
<script>
before(function() {
Polymer({
is: 'x-bar'
});
Polymer({
is: 'x-foo'
});
xBar = document.querySelector('x-bar');
xFoo = document.querySelector('x-foo');
});
suite('x-style', function() {
test('root styles applied', function() {
assertComputed(xBar, '1px');
});
test('root styles have lower bound encapsulation', function() {
assertComputed(xFoo.$.bar1, '0px');
});
test('::shadow styles applied', function() {
assertComputed(xFoo.$.bar2, '2px');
});
});
function assertComputed(element, value) {
var computed = getComputedStyle(element);
assert.equal(computed['border-top-width'], value, 'computed style incorrect');
}
</script>
</body>
</html>