mirror of
https://github.com/Polymer/polymer.git
synced 2025-02-25 18:55:30 -06:00
1187 lines
32 KiB
HTML
1187 lines
32 KiB
HTML
<!doctype 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="../../node_modules/@webcomponents/webcomponentsjs/webcomponents-lite.js"></script>
|
|
<script type="module">
|
|
let define = window.customElements.define;
|
|
let order = [];
|
|
window.customElements.define = function(name, fn, options) {
|
|
order.push(name);
|
|
return define.call(window.customElements, name, fn, options);
|
|
};
|
|
customElements.defineOrder = order;
|
|
</script>
|
|
<script src="wct-browser-config.js"></script>
|
|
<script src="../../node_modules/wct-browser-legacy/browser.js"></script>
|
|
<script type="module" src="../../polymer-legacy.js"></script>
|
|
<style>
|
|
#priority[style-scope=x-styled], #priority.style-scope.x-styled {
|
|
border: 1px solid black;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
|
|
<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(--keyframes0, 0px);
|
|
}
|
|
|
|
100% {
|
|
left: var(--keyframes100, 10px);
|
|
}
|
|
}
|
|
@keyframes x-keyframes-animation {
|
|
0% {
|
|
left: var(--keyframes0, 0px);
|
|
}
|
|
|
|
100% {
|
|
left: var(--keyframes100, 10px);
|
|
}
|
|
}
|
|
</style>
|
|
x-keyframes
|
|
</template>
|
|
<script type="module">
|
|
import { Polymer } from '../../polymer-legacy.js';
|
|
Polymer({
|
|
is: 'x-keyframes',
|
|
properties: {
|
|
animated: {
|
|
type: Boolean,
|
|
value: false,
|
|
reflectToAttribute: true
|
|
}
|
|
}
|
|
});
|
|
</script>
|
|
</dom-module>
|
|
<dom-module id="x-gchild">
|
|
<template>
|
|
<style>
|
|
</style>
|
|
<div id="target">x-gchild</div>
|
|
</template>
|
|
</dom-module>
|
|
<script type="module">
|
|
import { Polymer } from '../../polymer-legacy.js';
|
|
Polymer({
|
|
is: 'x-gchild'
|
|
});
|
|
</script>
|
|
|
|
<dom-module id="x-child">
|
|
<template>
|
|
<div id="simple">simple</div>
|
|
<div id="complex1" class="scoped">complex1</div>
|
|
<div id="complex2" selected>complex2</div>
|
|
<div id="media">media</div>
|
|
<div id="shadow" class="shadowTarget">shadowTarget</div>
|
|
<div id="deep" class="deepTarget">deepTarget</div>
|
|
<x-gchild id="gchild1"></x-gchild>
|
|
<x-gchild id="gchild2" class="wide"></x-gchild>
|
|
</template>
|
|
</dom-module>
|
|
<script type="module">
|
|
import { Polymer } from '../../polymer-legacy.js';
|
|
Polymer({
|
|
is: 'x-child',
|
|
hostAttributes: {
|
|
class: 'nug'
|
|
}
|
|
});
|
|
</script>
|
|
|
|
<dom-module id="x-child2">
|
|
<template>
|
|
<style>
|
|
:host(.wide) #target{
|
|
border: none;
|
|
}
|
|
</style>
|
|
<div id="target">x-child2</div>
|
|
</template>
|
|
</dom-module>
|
|
<script type="module">
|
|
import { Polymer } from '../../polymer-legacy.js';
|
|
Polymer({
|
|
is: 'x-child2'
|
|
});
|
|
</script>
|
|
|
|
<dom-module id="x-scope-class">
|
|
<template>
|
|
<div id="scope">Trivial</div>
|
|
</template>
|
|
<script type="module">
|
|
import { Polymer } from '../../polymer-legacy.js';
|
|
Polymer({
|
|
is: 'x-scope-class'
|
|
});
|
|
</script>
|
|
</dom-module>
|
|
|
|
|
|
|
|
<dom-module id="x-styled">
|
|
<template>
|
|
<style>
|
|
:host {
|
|
display: block;
|
|
border: 1px solid orange;
|
|
--keyframes100: 100px;
|
|
}
|
|
|
|
:host(.wide) {
|
|
border-width: 2px;
|
|
}
|
|
|
|
:host(.wide)::after {
|
|
content: '-content-';
|
|
};
|
|
|
|
#keyframes2.special {
|
|
--keyframes100: 200px;
|
|
}
|
|
|
|
#simple {
|
|
border: 3px solid orange;
|
|
}
|
|
|
|
.scoped, [selected] {
|
|
border: 4px solid pink;
|
|
}
|
|
|
|
@media(max-width: 10000px) {
|
|
.media {
|
|
border: 5px solid brown;
|
|
}
|
|
}
|
|
|
|
.container ::slotted(*) {
|
|
border: 6px solid navy;
|
|
}
|
|
|
|
#priority {
|
|
border: 9px solid orange;
|
|
}
|
|
|
|
.container1 > ::slotted([slot=content1]) {
|
|
border: 13px solid navy;
|
|
}
|
|
|
|
.container2 > ::slotted([slot=content2]) {
|
|
border: 14px solid navy;
|
|
}
|
|
|
|
.computed {
|
|
border: 15px solid orange;
|
|
}
|
|
|
|
.computeda {
|
|
border: 20px solid orange;
|
|
}
|
|
|
|
.a.computedb {
|
|
border: 16px solid gray;
|
|
}
|
|
|
|
#child {
|
|
border: 16px solid tomato;
|
|
display: block;
|
|
}
|
|
|
|
svg {
|
|
margin-top: 20px;
|
|
}
|
|
|
|
#circle {
|
|
fill: seagreen;
|
|
stroke-width: 1px;
|
|
stroke: tomato;
|
|
}
|
|
</style>
|
|
<slot name="blank"></slot>
|
|
<div id="simple">simple</div>
|
|
<div id="complex1" class="scoped">complex1</div>
|
|
<div id="complex2" selected>complex2</div>
|
|
<div id="media" class="media">media</div>
|
|
<div class="container1">
|
|
<slot name="content1"></slot>
|
|
</div>
|
|
<div class="container2">
|
|
<slot name="content2"></slot>
|
|
</div>
|
|
<div class="container">
|
|
<slot></slot>
|
|
</div>
|
|
<x-child id="child"></x-child>
|
|
<div id="priority">priority</div>
|
|
<x-child2 class="wide" id="child2"></x-child2>
|
|
<div id="computed" class$="{{computeClass(aClass)}}">Computed</div>
|
|
<div>
|
|
<div id="computed2" class$="a {{computeClass('computedb')}}">Computed</div>
|
|
</div>
|
|
<div id="repeatContainer">
|
|
<template id="repeat" is="dom-repeat" items="{{items}}">
|
|
<a class$="{{aaClass}}">A Computed</a>
|
|
</template>
|
|
</div>
|
|
<svg height="25" width="25">
|
|
<circle id="circle" cx="12" cy="12" r="10"></circle>
|
|
</svg>
|
|
<x-scope-class id="scopeClass"></x-scope-class>
|
|
<x-keyframes id="keyframes"></x-keyframes>
|
|
<x-keyframes id="keyframes2"></x-keyframes>
|
|
</template>
|
|
</dom-module>
|
|
<script type="module">
|
|
import { Polymer } from '../../polymer-legacy.js';
|
|
Polymer({
|
|
is: 'x-styled',
|
|
|
|
properties: {
|
|
items: {value: [{}]}
|
|
},
|
|
|
|
computeClass: function(className) {
|
|
return className;
|
|
}
|
|
|
|
});
|
|
</script>
|
|
|
|
<template id="dynamic">
|
|
<div class="added">
|
|
Added
|
|
<div class="sub-added">
|
|
Sub-added
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<dom-module id="x-dynamic-scope">
|
|
<template>
|
|
<style>
|
|
.added {
|
|
border: 17px solid beige;
|
|
}
|
|
|
|
.sub-added {
|
|
border: 18px solid #fafafa;
|
|
}
|
|
</style>
|
|
<div id="container"></div>
|
|
</template>
|
|
</dom-module>
|
|
<script type="module">
|
|
import { Polymer } from '../../polymer-legacy.js';
|
|
var doc = window.document;
|
|
var dynamic = doc.querySelector('template#dynamic');
|
|
|
|
HTMLImports.whenReady(function() {
|
|
Polymer({
|
|
is: 'x-dynamic-scope',
|
|
ready: function() {
|
|
// simulate 3rd party action by using normal dom to add to element.
|
|
var dom = document.importNode(dynamic.content, true);
|
|
this.$.container.appendChild(dom);
|
|
}
|
|
});
|
|
});
|
|
</script>
|
|
|
|
<template id="dynamic-style-template">
|
|
<style>
|
|
:host {
|
|
border: 40px solid tomato;
|
|
}
|
|
</style>
|
|
<div>big border</div>
|
|
</template>
|
|
|
|
<script type="module">
|
|
import { Polymer } from '../../polymer-legacy.js';
|
|
var doc = window.document;
|
|
var template = doc.querySelector('template#dynamic-style-template');
|
|
|
|
HTMLImports.whenReady(function() {
|
|
Polymer({
|
|
is: 'x-dynamic-template',
|
|
registered: function() {
|
|
this._template = template;
|
|
}
|
|
});
|
|
});
|
|
</script>
|
|
|
|
<template id="svg">
|
|
<svg class="svg" viewBox="0 0 24 24">
|
|
<circle id="circle" r="12" cx="12" cy="12" />
|
|
</svg>
|
|
</template>
|
|
|
|
<dom-module id="x-dynamic-svg">
|
|
<template>
|
|
<style>
|
|
.svg {
|
|
height: 24px;
|
|
width: 24px;
|
|
}
|
|
#circle {
|
|
fill: red;
|
|
fill-opacity: 0.5;
|
|
}
|
|
</style>
|
|
<div id="container"></div>
|
|
</template>
|
|
<script type="module">
|
|
import { Polymer } from '../../polymer-legacy.js';
|
|
var doc = window.document;
|
|
var template = doc.querySelector('template#svg');
|
|
|
|
HTMLImports.whenReady(function() {
|
|
Polymer({
|
|
is: 'x-dynamic-svg',
|
|
ready: function() {
|
|
this.scopeSubtree(this.$.container, true);
|
|
var dom = document.importNode(template.content, true);
|
|
this.$.container.appendChild(dom);
|
|
}
|
|
});
|
|
});
|
|
</script>
|
|
</dom-module>
|
|
|
|
<dom-module id="x-specificity">
|
|
<template>
|
|
<style>
|
|
:host {
|
|
border-top: 1px solid red;
|
|
}
|
|
:host(.bar) {
|
|
border-top: 2px solid red;
|
|
}
|
|
</style>
|
|
<slot></slot>
|
|
</template>
|
|
<script type="module">
|
|
import { Polymer } from '../../polymer-legacy.js';
|
|
Polymer({is: 'x-specificity'});
|
|
</script>
|
|
</dom-module>
|
|
|
|
<custom-style>
|
|
<style>
|
|
html {
|
|
--x-specificity-parent : {
|
|
border: 10px solid blue;
|
|
};
|
|
--x-specificity-nested : {
|
|
border: 3px solid red;
|
|
};
|
|
}
|
|
</style>
|
|
</custom-style>
|
|
|
|
<dom-module id="x-specificity-parent">
|
|
<template>
|
|
<style>
|
|
::slotted(:not(template)) {
|
|
@apply(--x-specificity-parent);
|
|
}
|
|
</style>
|
|
<slot></slot>
|
|
</template>
|
|
<script type="module">
|
|
import { Polymer } from '../../polymer-legacy.js';
|
|
Polymer({is: 'x-specificity-parent'});
|
|
</script>
|
|
</dom-module>
|
|
|
|
<dom-module id="x-specificity-nested">
|
|
<template>
|
|
<style>
|
|
:host {
|
|
@apply(--x-specificity-nested);
|
|
}
|
|
</style>
|
|
</template>
|
|
<script type="module">
|
|
import { Polymer } from '../../polymer-legacy.js';
|
|
Polymer({is: 'x-specificity-nested'});
|
|
</script>
|
|
</dom-module>
|
|
|
|
<custom-style>
|
|
<style>
|
|
html {
|
|
--x-overriding : {
|
|
border-top: 1px solid red;
|
|
}
|
|
}
|
|
</style>
|
|
</custom-style>
|
|
|
|
<dom-module id="x-overriding">
|
|
<template>
|
|
<style>
|
|
.red {
|
|
@apply(--x-overriding);
|
|
}
|
|
.green {
|
|
@apply(--x-overriding);
|
|
border-top: 2px solid green;
|
|
}
|
|
.red-2 {
|
|
border-top: 2px solid green;
|
|
@apply(--x-overriding);
|
|
}
|
|
.blue {
|
|
@apply(--x-overriding);
|
|
border-top: 3px solid blue;
|
|
}
|
|
</style>
|
|
|
|
<div class="red">red</div>
|
|
<div class="green">green</div>
|
|
<div class="red-2">green-2</div>
|
|
<div class="blue">blue</div>
|
|
</template>
|
|
</dom-module>
|
|
|
|
<script type="module">
|
|
import { Polymer } from '../../polymer-legacy.js';
|
|
Polymer({
|
|
is: 'x-overriding'
|
|
});
|
|
</script>
|
|
|
|
<dom-module id="x-attr-selector">
|
|
<template>
|
|
<style>
|
|
#foo1 ~ #bar1 {
|
|
border: 2px solid red;
|
|
}
|
|
|
|
#foo1 ~ #bar1 ~ #foo2[attr~=foo2] ~ #bar2[attr~=bar2] {
|
|
border: 4px solid red;
|
|
}
|
|
|
|
#foo1 ~ #bar1 ~ #foo2[attr~=foo2] ~ #bar2[attr~=bar2] ~ #foo3[attr~=foo3][a~=a] ~ #bar3[attr~=bar3][a~=a] {
|
|
border: 6px solid red;
|
|
}
|
|
</style>
|
|
<div id="foo1"></div>
|
|
<div id="bar1">bar1</div>
|
|
<div id="foo2" attr="foo2"></div>
|
|
<div id="bar2" attr="bar2">bar2</div>
|
|
<div id="foo3" attr="foo3" a="a"></div>
|
|
<div id="bar3" attr="bar3" a="a">bar3</div>
|
|
|
|
</template>
|
|
<script type="module">
|
|
import { Polymer } from '../../polymer-legacy.js';
|
|
Polymer({is: 'x-attr-selector'});
|
|
</script>
|
|
</dom-module>
|
|
|
|
<dom-module id="shared-style">
|
|
<template>
|
|
<style>
|
|
:host(x-shared1) {
|
|
display: block;
|
|
border: 2px solid orange;
|
|
}
|
|
|
|
:host(x-shared2) {
|
|
display: block;
|
|
border: 4px solid orange;
|
|
}
|
|
|
|
:host(.x-shared1) {
|
|
top: 10px;
|
|
};
|
|
</style>
|
|
</template>
|
|
</dom-module>
|
|
|
|
<dom-module id="x-shared1">
|
|
<template>
|
|
<style include="shared-style"></style>
|
|
x-shared1
|
|
</template>
|
|
<script type="module">
|
|
import { Polymer } from '../../polymer-legacy.js';
|
|
Polymer({is: 'x-shared1'});
|
|
</script>
|
|
</dom-module>
|
|
|
|
<dom-module id="x-shared2">
|
|
<template>
|
|
<style include="shared-style"></style>
|
|
x-shared2
|
|
</template>
|
|
<script type="module">
|
|
import { Polymer } from '../../polymer-legacy.js';
|
|
Polymer({is: 'x-shared2'});
|
|
</script>
|
|
</dom-module>
|
|
|
|
<dom-module id="x-slotted">
|
|
<template>
|
|
<style>
|
|
::slotted(.auto-content) {
|
|
border: 2px solid orange;
|
|
}
|
|
.bar, ::slotted(.complex-child) {
|
|
border: 6px solid navy;
|
|
}
|
|
#container ::slotted(*) {
|
|
border: 8px solid green;
|
|
}
|
|
</style>
|
|
<slot></slot>
|
|
<div id="container">
|
|
<slot name="container"></slot>
|
|
</div>
|
|
</template>
|
|
<script type="module">
|
|
import { Polymer } from '../../polymer-legacy.js';
|
|
Polymer({is: 'x-slotted'});
|
|
</script>
|
|
</dom-module>
|
|
|
|
<template id="xClass">
|
|
<style>
|
|
:host {
|
|
display: block;
|
|
border: 1px solid orange;
|
|
}
|
|
</style>
|
|
</template>
|
|
<script type="module">
|
|
import { PolymerElement } from '../../polymer-element.js';
|
|
customElements.define('x-class-no-is', class extends PolymerElement {
|
|
static get template() {
|
|
return window.xClass;
|
|
}
|
|
});
|
|
|
|
customElements.define('x-template-string', class extends PolymerElement {
|
|
static get template() {
|
|
return `<style>
|
|
:host {
|
|
display: block;
|
|
border: 1px solid orange;
|
|
}
|
|
</style>;`;
|
|
}
|
|
});
|
|
</script>
|
|
|
|
|
|
<div class="scoped">no margin</div>
|
|
|
|
<x-styled>
|
|
<div slot="content1">Foo</div>
|
|
<div slot="content2">Bar</div>
|
|
<div class="content">Content</div>
|
|
</x-styled>
|
|
|
|
<x-styled class="wide"></x-styled>
|
|
|
|
<x-dynamic-scope></x-dynamic-scope>
|
|
|
|
<dom-bind id="bind">
|
|
<template>
|
|
<div id="dom-bind-static" class="static">static</div>
|
|
<span id="dom-bind-dynamic" class$="[[dynamic]]">[[dynamic]]</span>
|
|
</template>
|
|
</dom-bind>
|
|
|
|
<x-dynamic-svg></x-dynamic-svg>
|
|
<x-specificity></x-specificity>
|
|
<x-specificity class="bar"></x-specificity>
|
|
<x-specificity-parent>
|
|
<x-specificity-nested></x-specificity-nested>
|
|
</x-specificity-parent>
|
|
<x-overriding></x-overriding>
|
|
|
|
<dom-module id="nested-shared-style">
|
|
<template>
|
|
<style>
|
|
:host {
|
|
padding-top: 10px;
|
|
}
|
|
</style>
|
|
</template>
|
|
</dom-module>
|
|
|
|
<dom-module id="x-nested-style">
|
|
<template>
|
|
<div id="container">
|
|
<style include="nested-shared-style">
|
|
:host {
|
|
display: block;
|
|
border: 10px solid black;
|
|
}
|
|
</style>
|
|
</div>
|
|
</template>
|
|
<script type="module">
|
|
import { PolymerElement } from '../../polymer-element.js';
|
|
class XNestedStyle extends PolymerElement {
|
|
static get is() {return 'x-nested-style';}
|
|
}
|
|
customElements.define(XNestedStyle.is, XNestedStyle);
|
|
</script>
|
|
</dom-module>
|
|
|
|
<dom-module id="x-interleaved-styles">
|
|
<template>
|
|
<style include="x-nested-style"></style>
|
|
<style>
|
|
:host {
|
|
padding-top: 5px;
|
|
}
|
|
</style>
|
|
<style>
|
|
:host {
|
|
color: blue;
|
|
}
|
|
</style>
|
|
</template>
|
|
<script type="module">
|
|
import { PolymerElement } from '../../polymer-element.js';
|
|
class XInterleaved extends PolymerElement {
|
|
static get is() {return 'x-interleaved-styles';}
|
|
}
|
|
customElements.define(XInterleaved.is, XInterleaved);
|
|
</script>
|
|
</dom-module>
|
|
|
|
<dom-module id="x-only-link-style">
|
|
<link rel="import" type="css" href="styling-import-host.css">
|
|
<link rel="import" type="css" href="styling-import-host2.css">
|
|
<template></template>
|
|
<script type="module">
|
|
import { PolymerElement } from '../../polymer-element.js';
|
|
class XOnlyLink extends PolymerElement {
|
|
static get is() { return 'x-only-link-style'; }
|
|
}
|
|
customElements.define(XOnlyLink.is, XOnlyLink);
|
|
</script>
|
|
</dom-module>
|
|
|
|
<dom-module id="double-shared-style">
|
|
<template>
|
|
<style>
|
|
.double-shared-style {
|
|
color: green;
|
|
}
|
|
</style>
|
|
</template>
|
|
</dom-module>
|
|
|
|
<dom-module id="importing-double-shared-style">
|
|
<template>
|
|
<style include="double-shared-style">
|
|
</style>
|
|
</template>
|
|
</dom-module>
|
|
|
|
<dom-module id="double-shared-styling-element">
|
|
<template>
|
|
<style include="importing-double-shared-style double-shared-style"></style>
|
|
</template>
|
|
<script type="module">
|
|
import { PolymerElement } from '../../polymer-element.js';
|
|
class DoubleSharedStylingElement extends PolymerElement {
|
|
static get is() { return 'double-shared-styling-element'; }
|
|
}
|
|
customElements.define(DoubleSharedStylingElement.is, DoubleSharedStylingElement);
|
|
</script>
|
|
</dom-module>
|
|
|
|
<script type="module">
|
|
import { dom } from '../../lib/legacy/polymer.dom.js';
|
|
import { flush } from '../../lib/utils/flush.js';
|
|
function assertComputed(element, value, property, pseudo) {
|
|
var computed = getComputedStyle(element, pseudo);
|
|
property = property || 'border-top-width';
|
|
if (Array.isArray(value)) {
|
|
assert.oneOf(computed[property], value, 'computed style incorrect for ' + property);
|
|
} else {
|
|
assert.equal(computed[property], value, 'computed style incorrect for ' + property);
|
|
}
|
|
}
|
|
|
|
var styled = document.querySelector('x-styled');
|
|
var styledWide = document.querySelector('x-styled.wide');
|
|
var unscoped = document.querySelector('.scoped');
|
|
|
|
suite('scoped-styling', function() {
|
|
|
|
test(':host, :host(...)', function() {
|
|
assertComputed(styled, '1px');
|
|
assertComputed(styledWide, '2px');
|
|
assertComputed(styled, ['', 'none'], 'content', '::after');
|
|
assertComputed(styledWide, ['"-content-"', '-content-'], 'content', '::after');
|
|
});
|
|
|
|
test('scoped selectors, simple and complex', function() {
|
|
assertComputed(styled.$.simple, '3px');
|
|
assertComputed(styled.$.complex1, '4px');
|
|
assertComputed(styled.$.complex2, '4px');
|
|
});
|
|
|
|
test('media query scoped selectors', function() {
|
|
assertComputed(styled.$.media, '5px');
|
|
});
|
|
|
|
test('upper bound encapsulation', function() {
|
|
assertComputed(unscoped, '0px');
|
|
});
|
|
|
|
test('lower bound encapsulation', function() {
|
|
assertComputed(styled.$.child.$.simple, '0px');
|
|
assertComputed(styled.$.child.$.complex1, '0px');
|
|
assertComputed(styled.$.child.$.complex2, '0px');
|
|
assertComputed(styled.$.child.$.media, '0px');
|
|
});
|
|
|
|
test('::slotted selectors', function() {
|
|
var content = document.querySelector('.content');
|
|
var content1 = document.querySelector('[slot=content1]');
|
|
var content2 = document.querySelector('[slot=content2]');
|
|
assertComputed(content, '6px');
|
|
assertComputed(content1, '13px');
|
|
assertComputed(content2, '14px');
|
|
});
|
|
|
|
test('auto ::slotted selector', function() {
|
|
var x = document.createElement('x-slotted');
|
|
var d1 = document.createElement('div');
|
|
d1.classList.add('auto-content');
|
|
d1.textContent = 'auto-content';
|
|
document.body.appendChild(x);
|
|
dom(x).appendChild(d1);
|
|
flush();
|
|
assertComputed(d1, '2px');
|
|
});
|
|
|
|
test('::slotted + child in complex selector', function() {
|
|
var x = document.createElement('x-slotted');
|
|
var d1 = document.createElement('div');
|
|
d1.classList.add('complex-child');
|
|
d1.textContent = 'complex-child';
|
|
document.body.appendChild(x);
|
|
dom(x).appendChild(d1);
|
|
flush();
|
|
assertComputed(d1, '6px');
|
|
});
|
|
|
|
test('::slotted + named slot', function() {
|
|
var x = document.createElement('x-slotted');
|
|
var d1 = document.createElement('div');
|
|
d1.setAttribute('slot', 'container');
|
|
d1.textContent = 'named slot child';
|
|
document.body.appendChild(x);
|
|
dom(x).appendChild(d1);
|
|
flush();
|
|
assertComputed(d1, '8px');
|
|
});
|
|
|
|
test('elements dynamically added/removed from root', function() {
|
|
var d = document.createElement('div');
|
|
d.classList.add('scoped');
|
|
d.textContent = 'Dynamically... Scoped!';
|
|
dom(styled.root).appendChild(d);
|
|
flush();
|
|
assertComputed(d, '4px');
|
|
dom(document.body).appendChild(d);
|
|
flush();
|
|
assert.notInclude(d.getAttribute('style-scoped') || '', styled.is, 'scoping attribute not removed when added to other root');
|
|
assert.notInclude(d.className, styled.is, 'scoping class not removed when added to other root');
|
|
assertComputed(d, '0px');
|
|
dom(styled.root).appendChild(d);
|
|
flush();
|
|
assertComputed(d, '4px');
|
|
});
|
|
|
|
test('elements dynamically added/removed from host', function() {
|
|
var d = document.createElement('div');
|
|
d.classList.add('scoped');
|
|
d.slot = 'blank';
|
|
d.textContent = 'Dynamically... unScoped!';
|
|
dom(styled).appendChild(d);
|
|
flush();
|
|
assertComputed(d, '0px');
|
|
dom(document.body).appendChild(d);
|
|
flush();
|
|
assert.notInclude(d.getAttribute('style-scoped') || '', styled.is, 'scoping attribute not removed when added to other root');
|
|
assert.notInclude(d.className, styled.is, 'scoping class not removed when added to other root');
|
|
dom(styled).appendChild(d);
|
|
flush();
|
|
assertComputed(d, '0px');
|
|
dom(styled).removeChild(d);
|
|
flush();
|
|
assert.notInclude(d.getAttribute('style-scoped') || '', styled.is, 'scoping attribute not removed when removed from root');
|
|
assert.notInclude(d.className, styled.is, 'scoping class not removed when removed from root');
|
|
dom(styled).appendChild(d);
|
|
flush();
|
|
assertComputed(d, '0px');
|
|
});
|
|
|
|
test('keyframes change scope', function(done) {
|
|
if (navigator.userAgent.match('Edge/16') && (!window.ShadyCSS || window.ShadyCSS.nativeCss)) {
|
|
// skip test due to missing variable support in keyframes
|
|
// https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/12084341/
|
|
this.skip();
|
|
}
|
|
var xKeyframes = styled.$.keyframes;
|
|
|
|
var onAnimationEnd = function() {
|
|
xKeyframes.removeEventListener('animationend', onAnimationEnd);
|
|
xKeyframes.removeEventListener('webkitAnimationEnd', onAnimationEnd);
|
|
assertComputed(xKeyframes, '100px', 'left');
|
|
|
|
xKeyframes = styled.$.keyframes2;
|
|
|
|
onAnimationEnd = function() {
|
|
xKeyframes.removeEventListener('animationend', onAnimationEnd);
|
|
xKeyframes.removeEventListener('webkitAnimationEnd', onAnimationEnd);
|
|
assertComputed(xKeyframes, '200px', 'left');
|
|
done();
|
|
};
|
|
|
|
xKeyframes.addEventListener('animationend', onAnimationEnd);
|
|
xKeyframes.addEventListener('webkitAnimationEnd', onAnimationEnd);
|
|
|
|
dom(xKeyframes).classList.add('special');
|
|
xKeyframes.updateStyles();
|
|
xKeyframes.animated = true;
|
|
};
|
|
|
|
xKeyframes.addEventListener('animationend', onAnimationEnd);
|
|
xKeyframes.addEventListener('webkitAnimationEnd', onAnimationEnd);
|
|
|
|
xKeyframes.animated = true;
|
|
assertComputed(xKeyframes, '0px', 'left');
|
|
});
|
|
|
|
test('elements with computed classes', function() {
|
|
assertComputed(styled.$.computed, '0px');
|
|
styled.aClass = 'computed';
|
|
assertComputed(styled.$.computed, '15px');
|
|
assertComputed(styled.$.computed2, '16px');
|
|
});
|
|
|
|
test('<a> with computed classes dynamically added', function() {
|
|
assertComputed(styled.$.repeatContainer.firstElementChild, '0px');
|
|
styled.aaClass = 'computeda';
|
|
assertComputed(styled.$.repeatContainer.firstElementChild, '20px');
|
|
});
|
|
|
|
test('elements with hostAttributes: class', function() {
|
|
assertComputed(styled.$.child, '16px');
|
|
});
|
|
|
|
test('element subtree added via dom api', function() {
|
|
var container = document.querySelector('x-dynamic-scope').$.container;
|
|
var a = container.querySelector('.added');
|
|
assertComputed(a, '17px');
|
|
var b = container.querySelector('.sub-added');
|
|
assertComputed(b, '18px');
|
|
});
|
|
|
|
test('styles in dynamically selected template', function() {
|
|
var el = document.createElement('x-dynamic-template');
|
|
document.body.appendChild(el);
|
|
if (el.shadowRoot) {
|
|
// style properly removed
|
|
assert.notOk(el.querySelector('style'));
|
|
}
|
|
assertComputed(el, '40px');
|
|
document.body.removeChild(el);
|
|
});
|
|
|
|
test('attribute inclusive selector and general sibling selectors', function() {
|
|
var e = document.createElement('x-attr-selector');
|
|
document.body.appendChild(e);
|
|
flush();
|
|
assertComputed(e.$.bar1, '2px');
|
|
assertComputed(e.$.bar2, '4px');
|
|
assertComputed(e.$.bar3, '6px');
|
|
});
|
|
|
|
test('svg classes are dynamically scoped correctly', function() {
|
|
var container = document.querySelector('x-dynamic-svg').$.container;
|
|
var svg = container.querySelector('.svg');
|
|
var computed = getComputedStyle(svg);
|
|
assert.equal(computed.height, '24px');
|
|
assert.equal(computed.width, '24px');
|
|
var circle = container.querySelector('#circle');
|
|
computed = getComputedStyle(circle);
|
|
assert.equal(computed['fill-opacity'], '0.5');
|
|
});
|
|
|
|
test(':host with element tag selector', function() {
|
|
var s1 = document.createElement('x-shared1');
|
|
document.body.appendChild(s1);
|
|
assertComputed(s1, '2px');
|
|
var s2 = document.createElement('x-shared2');
|
|
document.body.appendChild(s2);
|
|
assertComputed(s2, '4px');
|
|
});
|
|
|
|
test(':host with superset of element tag selector does not leak', function() {
|
|
var t = document.createElement('div');
|
|
t.textContent = 'host leak test';
|
|
t.classList.add('x-shared1');
|
|
document.body.appendChild(t);
|
|
assertComputed(t, 'auto', 'top');
|
|
});
|
|
|
|
test(':host(...) with non-matching type selector does not leak', function() {
|
|
var t = document.createElement('x-shared1x-shared2');
|
|
t.textContent = ':host(non-matching-type-selector)';
|
|
document.body.appendChild(t);
|
|
assertComputed(t, '0px');
|
|
t = document.createElement('x-shared2x-shared1');
|
|
t.textContent = ':host(non-matching-type-selector)';
|
|
document.body.appendChild(t);
|
|
assertComputed(t, '0px');
|
|
});
|
|
|
|
test('static is not required for scoping styling', function() {
|
|
var e = document.createElement('x-class-no-is');
|
|
document.body.appendChild(e);
|
|
assertComputed(e, '1px');
|
|
});
|
|
|
|
test('template string has scoped styling', function() {
|
|
var e = document.createElement('x-template-string');
|
|
document.body.appendChild(e);
|
|
assertComputed(e, '1px');
|
|
});
|
|
|
|
test('styles work correctly when not direct children of the template', function() {
|
|
var e = document.createElement('x-nested-style');
|
|
document.body.appendChild(e);
|
|
assertComputed(e, '10px');
|
|
assertComputed(e, '10px', 'padding-top');
|
|
});
|
|
|
|
test('interleaved styles and styles with includes work as expected', function() {
|
|
var e = document.createElement('x-interleaved-styles');
|
|
document.body.appendChild(e);
|
|
assertComputed(e, '5px', 'padding-top');
|
|
});
|
|
|
|
test('elements without styles work', function() {
|
|
var e = document.createElement('x-only-link-style');
|
|
document.body.appendChild(e);
|
|
assertComputed(e, '2px');
|
|
});
|
|
|
|
});
|
|
|
|
suite('double including style sheets', function() {
|
|
let el;
|
|
|
|
setup(function() {
|
|
el = document.createElement('double-shared-styling-element');
|
|
document.body.appendChild(el);
|
|
});
|
|
|
|
teardown(function() {
|
|
document.body.removeChild(el);
|
|
});
|
|
|
|
test('only includes style modules once', function() {
|
|
const style = el.shadowRoot.querySelector('style');
|
|
|
|
// We cant use the regular "does a sub-node have the correct style",
|
|
// because we actually need to assert on the actual style content.
|
|
// In native shadow dom, the style element resides in the shadowRoot,
|
|
// but in shadyDOM it has moved to the head and the selector has been altered.
|
|
if (style) {
|
|
assert.equal(style.textContent, `.double-shared-style {
|
|
color: green;
|
|
}`, 'There should be only one class selector in this style element');
|
|
} else {
|
|
assert.equal(document.head.querySelector('[scope="double-shared-styling-element"]').textContent,
|
|
`.double-shared-style.double-shared-styling-element {
|
|
color: green;
|
|
}`);
|
|
}
|
|
});
|
|
});
|
|
|
|
if (window.ShadyDOM) {
|
|
|
|
suite('scoped-styling-shady-only', function() {
|
|
|
|
test('element style precedence below document styles', function() {
|
|
assertComputed(styledWide.$.priority, '1px');
|
|
});
|
|
|
|
test('styles shimmed in registration order', function() {
|
|
var regList = customElements.defineOrder;
|
|
function regIndex(styleScope) {
|
|
for (var i=0, r; (r=regList[i]); i++) {
|
|
if (styleScope.match(new RegExp(r + '\\-?\\d*$'))) {
|
|
return i;
|
|
}
|
|
}
|
|
}
|
|
var s$ = document.head.querySelectorAll('style[scope]');
|
|
for (var i=0, scope, prevScope, n=0, o=0; i<s$.length; i++) {
|
|
scope = s$[i].getAttribute('scope');
|
|
n = regIndex(scope);
|
|
assert.isTrue(n >= o, 'style not in registration order, expected `' +
|
|
scope + '` to be before `' + prevScope + '`');
|
|
o = n;
|
|
prevScope = scope;
|
|
}
|
|
});
|
|
|
|
test('svg elements properly scoped', function() {
|
|
assert.include(styled.$.circle.getAttribute('class'), 'x-styled');
|
|
assert.include(styled.$.circle.getAttribute('class'), 'style-scope');
|
|
assert.notInclude(styled.$.circle.getAttribute('class'), 'null');
|
|
assertComputed(styled.$.circle, '1px', 'strokeWidth');
|
|
});
|
|
|
|
test('dom-bind content is unscoped', function() {
|
|
var e = document.querySelector('#bind');
|
|
e.dynamic = 'dynamic';
|
|
var staticClassEl = document.querySelector('#dom-bind-static');
|
|
assert.equal(staticClassEl.className, 'static');
|
|
var dynamicClassEl = document.querySelector('#dom-bind-dynamic');
|
|
assert.equal(dynamicClassEl.className, 'dynamic');
|
|
});
|
|
|
|
test('serializeValueToAttribute for class', function() {
|
|
var s = styled.$.scopeClass;
|
|
var scope = s.$.scope;
|
|
assert.isTrue(s.classList.contains('style-scope'));
|
|
assert.isTrue(s.classList.contains('x-styled'));
|
|
s.serializeValueToAttribute('foo', 'class');
|
|
assert.isTrue(s.classList.contains('foo'));
|
|
assert.isTrue(s.classList.contains('style-scope'));
|
|
assert.isTrue(s.classList.contains('x-styled'));
|
|
//
|
|
assert.isTrue(scope.classList.contains('style-scope'));
|
|
assert.isTrue(scope.classList.contains('x-scope-class'));
|
|
s.serializeValueToAttribute('foo', 'class', scope);
|
|
assert.isTrue(scope.classList.contains('foo'));
|
|
assert.isTrue(scope.classList.contains('style-scope'));
|
|
assert.isTrue(scope.classList.contains('x-scope-class'));
|
|
});
|
|
|
|
test('specificity of :host selector with class', function() {
|
|
assertComputed(document.querySelector('x-specificity'), '1px');
|
|
assertComputed(document.querySelector('x-specificity.bar'), '2px');
|
|
});
|
|
|
|
test('specificity of ::slotted :not(template) selector', function() {
|
|
assertComputed(document.querySelector('x-specificity-nested'), '10px');
|
|
});
|
|
|
|
test('overwriting mixin properties', function() {
|
|
var el = document.querySelector('x-overriding');
|
|
assertComputed(el.shadowRoot.querySelector('.red'), '1px');
|
|
assertComputed(el.shadowRoot.querySelector('.green'), '2px');
|
|
assertComputed(el.shadowRoot.querySelector('.red-2'), '1px');
|
|
assertComputed(el.shadowRoot.querySelector('.blue'), '3px');
|
|
});
|
|
|
|
test('dynamically scope element class on add/remove', function () {
|
|
var el = document.createElement('x-scope-class');
|
|
document.body.appendChild(el);
|
|
flush();
|
|
var div = document.createElement('div');
|
|
el.shadowRoot.appendChild(div);
|
|
flush();
|
|
assert.isTrue(div.classList.contains('style-scope'));
|
|
assert.isTrue(div.classList.contains('x-scope-class'));
|
|
el.shadowRoot.appendChild(div);
|
|
flush();
|
|
document.body.removeChild(el);
|
|
});
|
|
|
|
test('dynamically scope element class on setAttribute class', function () {
|
|
var el = document.createElement('x-scope-class');
|
|
document.body.appendChild(el);
|
|
flush();
|
|
var div = document.createElement('div');
|
|
el.shadowRoot.appendChild(div);
|
|
flush();
|
|
div.setAttribute('class', 'foo');
|
|
assert.isTrue(div.classList.contains('foo'));
|
|
assert.isTrue(div.classList.contains('style-scope'));
|
|
assert.isTrue(div.classList.contains('x-scope-class'));
|
|
el.shadowRoot.appendChild(div);
|
|
flush();
|
|
document.body.removeChild(el);
|
|
});
|
|
|
|
test('dynamically scope element class on set className', function () {
|
|
var el = document.createElement('x-scope-class');
|
|
document.body.appendChild(el);
|
|
flush();
|
|
var div = document.createElement('div');
|
|
el.shadowRoot.appendChild(div);
|
|
flush();
|
|
div.className = 'foo';
|
|
assert.isTrue(div.classList.contains('foo'));
|
|
assert.isTrue(div.classList.contains('style-scope'));
|
|
assert.isTrue(div.classList.contains('x-scope-class'));
|
|
el.shadowRoot.appendChild(div);
|
|
flush();
|
|
document.body.removeChild(el);
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
</script>
|
|
</body>
|
|
</html>
|