@polymer/polymer
Version:
The Polymer library makes it easy to create your own web components. Give your element some markup and properties, and then use it on a site. Polymer provides features like dynamic templates and data binding to reduce the amount of boilerplate you need to
1,113 lines (984 loc) • 30.8 kB
HTML
<!--
@license
Copyright (c) 2017 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>
.variable-override {
border-top-width: 10px;
}
</style>
</head>
<body>
<simple-element></simple-element>
<simple-element></simple-element>
<x-scope></x-scope>
<dom-module id="x-grand-child-scope">
<template>
<style>
:host {
display: block;
padding: 8px;
}
#scope {
border: var(--scope-var);
}
#child {
border: var(--child-scope-var);
}
#me {
border: var(--grand-child-scope-var);
}
</style>
<div id="me">x-grand-child-scope</div>
<div id="scope">From x-scope</div>
<div id="child">From x-child-scope</div>
</template>
<script>
HTMLImports.whenReady(function() {
Polymer({is: 'x-grand-child-scope'});
});
</script>
</dom-module>
<dom-module id="x-host-property">
<template>
<style>
:host {
display: block;
padding: 8px;
border: var(--scope-var);
}
:host(.foo) {
border: var(--scope-var-foo);
}
</style>
Host property
</template>
<script>
HTMLImports.whenReady(function() {
Polymer({is: 'x-host-property'});
});
</script>
</dom-module>
<dom-module id="x-host-host-property">
<template>
<x-host-property id="hosted"></x-host-property>
</template>
<script>
HTMLImports.whenReady(function() {
Polymer({is: 'x-host-host-property'});
});
</script>
</dom-module>
<dom-module id="x-produce-use-property">
<template>
<style>
:host {
--scope-var: 6px solid steelblue;
--scope-var-foo: 8px solid steelblue;
}
</style>
<x-host-host-property id="hosted"></x-host-host-property>
</template>
<script>
HTMLImports.whenReady(function() {
Polymer({is: 'x-produce-use-property'});
});
</script>
</dom-module>
<dom-module id="x-child-scope">
<template>
<style>
:host {
display: block;
padding: 8px;
}
:host > * {
--gc4-scope: 5px solid green;
}
#me {
border: var(--child-scope-var);
}
#gc2 {
--grand-child-scope-var: 4px solid seagreen;
}
#gc4 {
--grand-child-scope-var:
var(--gc4-scope);
}
</style>
<div id="me">x-child-scope</div>
<x-grand-child-scope id="gc1"></x-grand-child-scope>
<x-grand-child-scope id="gc2"></x-grand-child-scope>
<x-grand-child-scope id="gc3"></x-grand-child-scope>
<x-grand-child-scope id="gc4"></x-grand-child-scope>
</template>
<script>
HTMLImports.whenReady(function() {
Polymer({is: 'x-child-scope'});
});
</script>
</dom-module>
<dom-module id="x-overrides">
<template>
<style>
:host {
border: 1px dashed gray;
margin: 8px;
padding: 8px;
display: block;
--grand-child-scope-var: var(--rename);
}
</style>
overrides:
<x-grand-child-scope id="gc1"></x-grand-child-scope>
</template>
<script>
HTMLImports.whenReady(function() {
Polymer({is: 'x-overrides'});
});
</script>
</dom-module>
<dom-module id="x-overrides2">
<template>
<style>
:host {
border: 1px dashed gray;
margin: 8px;
padding: 8px;
display: block;
}
:host > * {
--grand-child-scope-var: var(--rename);
}
</style>
overrides:
<x-grand-child-scope id="gc1"></x-grand-child-scope>
</template>
<script>
HTMLImports.whenReady(function() {
Polymer({is: 'x-overrides2'});
});
</script>
</dom-module>
<dom-module id="x-late">
<template>
<style>
:host {
border: var(--late);
display: block;
}
</style>
late
</template>
<script>
HTMLImports.whenReady(function() {
Polymer({is: 'x-late'});
});
</script>
</dom-module>
<dom-module id="x-overrides3">
<template>
<style>
:host {
border: 1px dashed gray;
margin: 8px;
padding: 8px;
display: block;
}
:host > * {
--fillin: 16px;
}
</style>
overrides:
<x-late id="late"></x-late>
</template>
<script>
HTMLImports.whenReady(function() {
Polymer({is: 'x-overrides3'});
});
</script>
</dom-module>
<dom-module id="x-has-def">
<template>
<style>
:host {
border: var(--border, var(--defaultBorder));
margin: 8px;
padding: 8px;
display: block;
}
</style>
Element with default variable.
</template>
<script>
HTMLImports.whenReady(function() {
Polymer({is: 'x-has-def'});
});
</script>
</dom-module>
<dom-module id="x-has-if">
<template>
<style>
.iffy {
border: var(--scope-var);
}
</style>
<template is="dom-if" if="{{gogo}}">
<div class="iffy">iffy</div>
</template>
</template>
<script>
HTMLImports.whenReady(function() {
Polymer({
is: 'x-has-if',
properties: {
gogo: {value: true}
}
});
});
</script>
</dom-module>
<dom-module id="x-button">
<template>
<style>
:host {
display: block;
border: var(--button-border);
}
</style>
Button!
</template>
<script>
HTMLImports.whenReady(function() {
Polymer({
is: 'x-button',
extends: 'button'
});
});
</script>
</dom-module>
<dom-module id="x-dynamic">
<template>
<style>
:host {
display: block;
margin: 20px;
border: var(--dynamic);
}
</style>
Dynamic
</template>
<script>
HTMLImports.whenReady(function() {
Polymer({
is: 'x-dynamic'
});
});
</script>
</dom-module>
<dom-module id="x-keyframes">
<template>
<style>
:host {
display: block;
position: relative;
border: 10px solid blue;
left: 0px;
/* Prefix required by Safari <= 8 */
-webkit-animation-duration: 0.3s;
animation-duration: 0.3s;
-webkit-animation-fill-mode: forwards;
animation-fill-mode: forwards;
}
:host([animated]) {
/* Prefix required by Safari <= 8 */
-webkit-animation-name: x-keyframes-animation;
animation-name: x-keyframes-animation;
}
/* Prefix required by Safari <= 8 */
@-webkit-keyframes x-keyframes-animation {
0% {
left: var(--a);
}
100% {
left: var(--b);
}
}
@keyframes x-keyframes-animation {
0% {
left: var(--a);
}
100% {
left: var(--b);
}
}
</style>
x-keyframes
</template>
<script>
HTMLImports.whenReady(function() {
Polymer({
is: 'x-keyframes',
properties: {
animated: {
type: Boolean,
value: false,
reflectToAttribute: true
}
}
});
});
</script>
</dom-module>
<dom-module id="x-scope">
<template>
<style>
:host {
x--invalid: 15px solid gray;
display: block;
padding: 8px;
--scope-var: 1px solid black;
--fallback: 7px solid orange;
--default1: var(--undefined, 6px solid yellow);
--default2: var(--undefined, var(--fallback));
--default3: var(--undefined, rgb(128, 200, 250));
--defaultBorder: 22px solid green;
--a: 10px;
--b: 5px;
--primary-color: rgb(128, 128, 128);
--late: var(--fillin);
--button-border: 16px solid tomato;
--after: 17px solid brown;
--end-term: 19px solid blue}
:host > *{--ws-term: 18px solid orange}
#me {
border: var(--scope-var);
}
x-child-scope {
--child-scope-var: 2px solid orange;
--grand-child-scope-var: 3px solid steelblue;
}
x-child-scope.special {
--child-scope-var: 12px solid orange;
}
#applyDefault1 {
border: var(--undefined, 6px solid yellow);
}
#applyDefault2 {
border: var(--undefined, var(--fallback));
}
#default1 {
border: var(--default1);
}
#default2 {
border: var(--default2);
}
#default3 {
padding: 8px;
background-color: var(--default3);
}
#defaultElement2 {
--defaultBorder: 23px solid goldenrod;
}
#overrides1a, #overrides1b, #overrides2 {
--rename: 8px solid navy;
}
#overrides1b, #overrides2 {
--grand-child-scope-var: 9px solid orange;
}
#overridesConcrete {
border: var(--scope-var);
border: 4px solid steelblue;
}
#calc {
border: solid red;
border-width: calc(var(--a) + var(--b));
}
#shadow {
box-shadow: 10px 10px 10px var(--primary-color);
-webkit-box-shadow: 10px 10px 10px var(--primary-color);
}
x-host-property {
border: 10px solid purple;
}
#invalid {
border: var(--invalid);
}
#after::after {
content: 'after';
border: var(--after);
}
#wsTerm {
border: var(--ws-term)
}
x-keyframes:nth-of-type(2) {
--b: -5px;
}
#endTerm {border: var(--end-term)}
#parenthesis {
background-image: var(--foo-background-image, url(http://placehold.it/400x300));
}
#nestedFallback {
border: var(--undefined, var(--undefined, 20px solid blue));
}
#doubleNestedFallback {
border: var(--undefined, var(--undefined, var(--undefined, 20px solid red)));
}
#cornerFallback {
background-image: var(--undefined, var(--undefined, var(--undefined, url(http://placehold.it/400x300))));
}
</style>
<div id="me">x-scope</div>
<x-keyframes id="keyframes"></x-keyframes>
<x-keyframes id="keyframes2"></x-keyframes>
<x-child-scope id="child"></x-child-scope>
<x-child-scope id="child2"></x-child-scope>
<x-overrides id="overrides1a"></x-overrides>
<x-overrides id="overrides1b"></x-overrides>
<x-overrides2 id="overrides2"></x-overrides2>
<x-overrides3 id="overrides3"></x-overrides3>
<div id="overridesConcrete">override concrete</div>
<button id="button" is="x-button"></button>
<div id="default1">default</div>
<div id="default2">var default</div>
<div id="default3">tricky property rgb(...) default</div>
<x-has-def id="defaultElement1"></x-has-def>
<x-has-def id="defaultElement2"></x-has-def>
<div id="applyDefault1">default</div>
<div id="applyDefault2">var default</div>
<div id="calc">Calc</div>
<div id="shadow">Shadow</div>
<div id="invalid">invalid</div>
<x-host-property id="hostProp"></x-host-property>
<x-has-if id="iffy"></x-has-if>
<div id="after"></div>
<x-dynamic id="dynamic"></x-dynamic>
<div id="wsTerm">new line var</div>
<div id="endTerm">end var</div>
<div id="parenthesis">parenthesis</div>
<div id="nestedFallback"></div>
<div id="doubleNestedFallback"></div>
<div id="cornerFallback"></div>
<div id="badFallback"></div>
</template>
<script>
HTMLImports.whenReady(function() {
Polymer({
is: 'x-scope'
});
});
</script>
</dom-module>
<dom-module id="x-inside">
<template>
<style>
:host {
display: inline-block;
border: var(--border) solid orange;
height: 10px;
width: 10px;
background-color: tomato;
}
</style>
</template>
<script>
HTMLImports.whenReady(function() {
Polymer({
is: 'x-inside'
});
});
</script>
</dom-module>
<dom-module id="simple-element">
<template>
<style>
:host {
display: block;
}
x-inside {
color: var(--dne);
--border: 10px;
}
</style>
<x-inside id="inner"></x-inside>
</template>
<script>
HTMLImports.whenReady(function() {
Polymer({
is: 'simple-element'
});
});
</script>
</dom-module>
<dom-module id="x-variable-override">
<template>
<style>
:host {
--b: 2px solid black;
display: block;
border: var(--b);
}
</style>
</template>
<script>
HTMLImports.whenReady(function() {
Polymer({
is: 'x-variable-override'
});
});
</script>
</dom-module>
<dom-module id="x-variable-consumer">
<template>
<style>
:host(.foo) {
border: var(--consumer);
}
</style>
test
</template>
<script>
HTMLImports.whenReady(function() {
Polymer({
is: 'x-variable-consumer'
});
});
</script>
</dom-module>
<dom-module id="x-host-variable-consumer">
<template>
<style>
:host {
--consumer: 2px solid orange;
}
.foo {
display: block;
/* should override */
border: 10px solid black;
}
</style>
<x-variable-consumer id="consumer" class="foo"></x-variable-consumer>
</template>
<script>
HTMLImports.whenReady(function() {
Polymer({
is: 'x-host-variable-consumer'
});
});
</script>
</dom-module>
<dom-module id="x-var-produce-via-consume">
<template>
<style>
:host {
display: block;
border: 10px solid orange;
--foo: var(--bar);
}
</style>
</template>
<script>
HTMLImports.whenReady(function() {
Polymer({
is: 'x-var-produce-via-consume'
});
});
</script>
</dom-module>
<dom-module id="x-non-media-matching">
<template>
<style>
@media (min-width: 100000px) {
#inside {
--consumer: 10px solid red;
}
}
</style>
<x-variable-consumer id="inside" class="foo"></x-variable-consumer>
</template>
<script>
HTMLImports.whenReady(function() {
Polymer({
is: 'x-non-media-matching'
});
});
</script>
</dom-module>
<dom-module id="x-non-media-matching-host">
<template>
<style>
@media (min-width: 100000px) {
:host {
--border: 10px solid red;
}
}
:host {
display: block;
border: var(--border);
}
</style>
</template>
<script>
HTMLImports.whenReady(function() {
Polymer({
is: 'x-non-media-matching-host'
});
});
</script>
</dom-module>
<dom-module id="x-update-styles">
<template>
<style>
:host {
--border: 10px solid red;
}
:host([active]) {
--consumer: 6px solid orange;
}
:host {
display: block;
border: var(--border);
}
</style>
<x-variable-consumer id="child" class="foo"></x-variable-consumer>
</template>
<script>
HTMLImports.whenReady(function() {
Polymer({
is: 'x-update-styles',
properties: {
active: {
reflectToAttribute: true,
observer: '_activeChanged'
}
},
_activeChanged: function() {
this.updateStyles();
}
});
});
</script>
</dom-module>
<script>
suite('scoped-styling-var', function() {
function assertComputed(element, value, pseudo, name) {
// force a style-recalc for Safari missing updated CSS Custom Properties
// https://bugs.webkit.org/show_bug.cgi?id=170708
element.offsetWidth;
name = name || 'border-top-width';
var computed = element.getComputedStyleValue && !pseudo ?
element.getComputedStyleValue(name) :
getComputedStyle(element, pseudo)[name];
assert.equal(computed, value, 'computed style incorrect');
}
function assertStylePropertyValue(element, name, includeValue) {
var value = element.getComputedStyleValue(name);
assert.include(value, includeValue);
}
var styled = document.querySelector('x-scope');
test('variables in @keyframes', function(done) {
var xKeyframes = styled.$.keyframes;
var onAnimationEnd = function() {
assertStylePropertyValue(xKeyframes, 'left', '5px');
xKeyframes.removeEventListener('animationend', onAnimationEnd);
xKeyframes.removeEventListener('webkitAnimationEnd', onAnimationEnd);
xKeyframes.animated = false;
done();
};
assertStylePropertyValue(xKeyframes, '--a', '10px');
assertStylePropertyValue(xKeyframes, '--b', '5px');
xKeyframes.addEventListener('animationend', onAnimationEnd);
xKeyframes.addEventListener('webkitAnimationEnd', onAnimationEnd);
xKeyframes.animated = true;
});
test('instances of scoped @keyframes', function(done) {
if (navigator.userAgent.match(/Safari/) && ShadyCSS.nativeCss && ShadyCSS.nativeShadow) {
// `:nth-of-type` is broken in shadow roots on Safari 10.1
// https://bugs.webkit.org/show_bug.cgi?id=166748
this.skip();
}
var xKeyframes = styled.$.keyframes2;
var onAnimationEnd = function() {
assertStylePropertyValue(xKeyframes, 'left', '5px');
xKeyframes.removeEventListener('animationend', onAnimationEnd);
xKeyframes.removeEventListener('webkitAnimationEnd', onAnimationEnd);
xKeyframes.animated = false;
done();
};
assertStylePropertyValue(xKeyframes, '--a', '10px');
assertStylePropertyValue(xKeyframes, '--b', '-5px');
xKeyframes.addEventListener('animationend', onAnimationEnd);
xKeyframes.addEventListener('webkitAnimationEnd', onAnimationEnd);
xKeyframes.animated = true;
});
test('multiple elements in document', function() {
var e$ = document.querySelectorAll('simple-element');
assertComputed(e$[0].$.inner, '10px');
assertComputed(e$[1].$.inner, '10px');
});
test('simple variables calculated correctly between scopes', function() {
assertStylePropertyValue(styled, '--scope-var', '1px');
//
var child = styled.$.child;
assertStylePropertyValue(child, '--scope-var', '1px');
assertStylePropertyValue(child, '--child-scope-var', '2px');
assertStylePropertyValue(child, '--grand-child-scope-var', '3px');
//
var gc1 = child.$.gc1;
assertStylePropertyValue(gc1, '--scope-var', '1px');
assertStylePropertyValue(gc1, '--child-scope-var', '2px');
assertStylePropertyValue(gc1, '--grand-child-scope-var', '3px');
//
var gc2 = child.$.gc2;
assertStylePropertyValue(gc2, '--scope-var', '1px');
assertStylePropertyValue(gc2, '--child-scope-var', '2px');
assertStylePropertyValue(gc2, '--grand-child-scope-var', '4px');
//
var gc3 = child.$.gc3;
assertStylePropertyValue(gc3, '--scope-var', '1px');
assertStylePropertyValue(gc3, '--child-scope-var', '2px');
assertStylePropertyValue(gc3, '--grand-child-scope-var', '3px');
});
test('invalid variables not parsed', function() {
if (!window.ShadyCSS || ShadyCSS.nativeCss) {
this.skip();
}
assert.notOk(ShadyCSS.ScopingShim.getComputedStyleValue(styled, 'x--invalid'));
assertComputed(styled.$.invalid, '0px');
});
test('simple variables applied correctly between scopes', function() {
assertComputed(styled.$.me, '1px');
assertComputed(styled.$.child.$.me, '2px');
assertComputed(styled.$.child.$.gc1.$.me, '3px');
assertComputed(styled.$.child.$.gc1.$.scope, '1px');
assertComputed(styled.$.child.$.gc1.$.child, '2px');
assertComputed(styled.$.child.$.gc2.$.me, '4px');
assertComputed(styled.$.child.$.gc2.$.scope, '1px');
assertComputed(styled.$.child.$.gc2.$.child, '2px');
});
test('variable can be set to another variable', function() {
var gc4 = styled.$.child.$.gc4;
assertStylePropertyValue(gc4, '--grand-child-scope-var', '5px');
assertComputed(gc4.$.me, '5px');
});
test('variable default values can be assigned to other variables', function() {
assertStylePropertyValue(styled, '--default1', '6px');
assertStylePropertyValue(styled, '--default2', '7px');
assertComputed(styled.$.default1, '6px');
assertComputed(styled.$.default2, '7px');
assertComputed(styled.$.applyDefault1, '6px');
assertComputed(styled.$.applyDefault2, '7px');
});
test('variable literal defaults can contain one (...)', function() {
var b = getComputedStyle(styled.$.default3).backgroundColor;
assert.match(b, /rgb\(128/, 'literal fallback containing (...) not set');
});
test('variable values can be used with calc', function() {
assertComputed(styled.$.calc, '15px');
});
test('variable values can be used with box-shadow', function() {
var b = getComputedStyle(styled.$.shadow).boxShadow;
assert.match(b, /rgb\(128/, 'box shadow not set correctly');
});
test('host properties can be overridden with outer scope styles', function() {
assertComputed(styled.$.hostProp, '10px');
});
test('updateStyles changes property values and using style cache', function() {
styled.$.child.classList.add('special');
var l = document.querySelectorAll('style').length;
styled.updateStyles();
if (styled.shadowRoot && window.ShadyCSS && !ShadyCSS.nativeCss) {
assert.equal(document.querySelectorAll('style').length, l+4);
}
assertComputed(styled.$.child.$.me, '12px');
styled.$.child.classList.remove('special');
styled.updateStyles();
if (styled.shadowRoot && window.ShadyCSS && !ShadyCSS.nativeCss) {
assert.equal(document.querySelectorAll('style').length, l);
}
assertComputed(styled.$.child.$.me, '2px');
});
test('Nested element uses style cache when attached and updateStyles is called', function() {
var l = document.querySelectorAll('style').length;
var e1 = document.createElement('x-produce-use-property');
document.body.appendChild(e1);
var e1t = e1.$.hosted.$.hosted;
var e2 = document.createElement('x-produce-use-property');
document.body.appendChild(e2);
var e2t = e2.$.hosted.$.hosted;
if (styled.shadowRoot && window.ShadyDOM) {
assert.equal(document.querySelectorAll('style').length, l+1);
}
assertComputed(e1t, '6px');
assertComputed(e2t, '6px');
e1.updateStyles({'--scope-var': '8px solid purple'});
e2.updateStyles({'--scope-var': '8px solid purple'});
assertComputed(e1t, '8px');
assertComputed(e2t, '8px');
if (styled.shadowRoot && window.ShadyDOM) {
assert.equal(document.querySelectorAll('style').length, l+1);
}
e1.updateStyles({'--scope-var': null});
e2.updateStyles({'--scope-var': null});
assertComputed(e1t, '6px');
assertComputed(e2t, '6px');
if (styled.shadowRoot && window.ShadyDOM) {
assert.equal(document.querySelectorAll('style').length, l+1);
}
});
test('updateStyles with properties argument changes styles', function() {
styled.$.child.updateStyles({'--child-scope-var': '26px solid seagreen'});
assertComputed(styled.$.child.$.me, '26px');
styled.$.child.updateStyles({'--child-scope-var': null});
assertComputed(styled.$.child.$.me, '2px');
});
test('updateStyles on when element when not attached', function() {
var x = document.createElement('x-update-styles');
document.body.appendChild(x);
assertComputed(x, '10px');
document.body.removeChild(x);
x.updateStyles({'--border': '8px solid orange'});
document.body.appendChild(x);
assertComputed(x, '8px');
});
test('updateStyles called in observer when element not attached', function() {
var x = document.createElement('x-update-styles');
document.body.appendChild(x);
assertComputed(x.$.child, '0px');
x.active = true;
assertComputed(x.$.child, '6px');
x.active = false;
assertComputed(x.$.child, '0px');
document.body.removeChild(x);
x.active = true;
// disable element's updateStyles to show that observer for `active`'s call to updateStyles
// functions correctly.
x.updateStyles = function(){};
document.body.appendChild(x);
assertComputed(x.$.child, '6px');
});
test('styles update based on root customStyle changes', function() {
assertComputed(styled.$.dynamic, '0px');
Polymer.updateStyles({'--dynamic': '4px solid navy'});
assertComputed(styled.$.dynamic, '4px');
Polymer.updateStyles({'--dynamic': '6px solid gray'});
assertComputed(styled.$.dynamic, '6px');
});
test('null customStyles unapply', function() {
styled.$.dynamic.updateStyles({'--dynamic': '8px solid black'});
assertComputed(styled.$.dynamic, '8px');
styled.$.dynamic.updateStyles({'--dynamic': null});
assertComputed(styled.$.dynamic, '6px');
styled.$.dynamic.updateStyles({'--dynamic': '8px solid black'});
assertComputed(styled.$.dynamic, '8px');
styled.$.dynamic.updateStyles({'--dynamic': null});
assertComputed(styled.$.dynamic, '6px');
});
test('style properties with dom-if', function() {
var e = styled.$.iffy;
var c = Polymer.dom(e.root).querySelector('.iffy');
assert.ok(c, 'dom-if did not stamp');
assertComputed(c, '1px');
});
test('variable precedence and overrides', function() {
// renamed property applied
var o1a = styled.$.overrides1a;
assertStylePropertyValue(o1a, '--rename', '8px');
assertStylePropertyValue(o1a, '--grand-child-scope-var', '8px');
assertComputed(o1a.$.gc1.$.me, '8px');
// :host property overridden by outer scope
var o1b = styled.$.overrides1b;
assertStylePropertyValue(o1b, '--rename', '8px');
assertStylePropertyValue(o1b, '--grand-child-scope-var', '9px');
assertComputed(o1b.$.gc1.$.me, '9px');
// own scope property overrides outer scope
var o2 = styled.$.overrides2;
assertStylePropertyValue(o2, '--rename', '8px');
assertStylePropertyValue(o2.$.gc1, '--grand-child-scope-var', '8px');
assertComputed(o2.$.gc1.$.me, '8px');
// late bound property does *not* resolve using inherited value
var o3 = styled.$.overrides3;
if (window.ShadyCSS && !ShadyCSS.nativeCss) {
assert.equal(ShadyCSS.ScopingShim.getComputedStyleValue(o3, '--late'), '', 'property should not be late bound');
}
assertStylePropertyValue(o3.$.late, '--fillin', '16px');
assertComputed(o3.$.late, '0px');
});
test('pseudo-elements can consume custom properties', function() {
assertComputed(styled.$.after, '17px', '::after');
});
test('elements using only variable defaults are styled properly', function() {
assertComputed(styled.$.defaultElement1, '22px');
assertComputed(styled.$.defaultElement2, '23px');
});
test('vars with trailing new line or } apply', function() {
assertComputed(styled.$.wsTerm, '18px');
assertComputed(styled.$.endTerm, '19px');
});
test('variable with parenthesis', function() {
var url = getComputedStyle(styled.$.parenthesis).backgroundImage.replace(/['"]/g, '');
assert.equal('url(http://placehold.it/400x300)', url);
});
test('custom style class overrides css variable', function() {
var d = document.createElement('x-variable-override');
d.classList.add('variable-override');
document.body.appendChild(d);
assertComputed(d, '10px');
});
test('class selector overrides :host(class) property on element with only dynamic styles', function() {
var d = document.createElement('x-host-variable-consumer');
document.body.appendChild(d);
assertComputed(d.$.consumer, '10px');
});
test('var values can be overridden by subsequent concrete properties', function() {
assertComputed(styled.$.overridesConcrete, '4px');
});
test('producing a var that consumes another var preserves static styling', function() {
var d = document.createElement('x-var-produce-via-consume');
document.body.appendChild(d);
assertComputed(d, '10px');
});
test('producing a var that consumes results in static and not dynamic stylesheet', function() {
if (!window.ShadyCSS || ShadyCSS.nativeCss) {
this.skip();
}
var d = document.createElement('x-var-produce-via-consume');
document.body.appendChild(d);
var styleRoot = (!window.ShadyCSS || ShadyCSS.nativeShadow) ? d.shadowRoot : document.head;
var staticStyle = styleRoot.querySelector('style[scope=x-var-produce-via-consume]');
assert.ok(staticStyle);
assert.match(staticStyle.textContent, /display/, 'static style does not contain style content');
assert.equal(styleRoot.querySelectorAll('style[scope~=x-var-produce-via-consume]').length, 1);
});
test('Nested var fallback syntax', function() {
assertComputed(styled.$.nestedFallback, '20px');
assertComputed(styled.$.doubleNestedFallback, '20px');
var url = getComputedStyle(styled.$.cornerFallback).backgroundImage.replace(/['"]/g, '');
assert.equal('url(http://placehold.it/400x300)', url);
});
test('invalid @media rules do not match', function() {
var e = document.createElement('x-non-media-matching');
document.body.appendChild(e);
assertComputed(e.$.inside, '0px');
});
test('invalid @media rules do not match :host rule', function() {
var e = document.createElement('x-non-media-matching-host');
document.body.appendChild(e);
assertComputed(e, '0px');
});
});
</script>
</body>
</html>