UNPKG

@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

681 lines (600 loc) 17.1 kB
<!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="../../../webcomponentsjs/webcomponents-lite.js"></script> <script src="../../../web-component-tester/browser.js"></script> <link rel="import" href="../../polymer.html"> </head> <body> <x-scope></x-scope> <dom-module id="story-card"> <template> <style> :host { display: block; } #story-card .story-content { font-family: 'Roboto', sans-serif; font-size: 1.2em; @apply --story-content; } </style> <div id="story-card"> <div class="story-content" id="content">Content</div> </div> </template> <script> HTMLImports.whenReady(function() { Polymer({is: 'story-card'}); }); </script> </dom-module> <dom-module id="x-child-scope"> <template> <style> :host { display: block; --mixin2: { border: 3px solid seagreen; background: url(http://www.google.com/icon.png); }; } #mixin1 { @apply --mixin1; } #mixin2 { @apply --mixin2; } #mixin3 { padding: 3px; @apply --mixin3; } #mixin4 { @apply --mixin4; } #mixin6 { @apply --mixin6 } #mixin7 {@apply --mixin7} #mixin8 { @apply --mixin8 } #mixin9 { @apply --mixin9 } </style> <div id="mixin1">mixin1</div> <div id="mixin2">mixin2</div> <div id="mixin3">mixin3</div> <div id="mixin4">mixin4</div> <div id="mixin6">mixin6</div> <div id="mixin7">mixin7</div> <div id="mixin8">mixin8</div> <div id="mixin9">mixin9</div> </template> <script> HTMLImports.whenReady(function() { Polymer({is: 'x-child-scope'}); }); </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(--c1); } 100% { left: var(--c2); @apply --keyframe-finish; } } @keyframes x-keyframes-animation { 0% { left: var(--c1); } 100% { left: var(--c2); @apply --keyframe-finish; } } </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 { display: block; padding: 8px; --override-me: { border: 11px solid black; }; --mixin1: { border: 1px solid black; }; --b: 2px solid orange; --m1: 1px; --m2: 2px; --c1: 5px; --c2: 10px; --mixin2: { border: var(--b); }; --mixin3: { @apply --mixin2; }; --mixin4: { padding: 2px; @apply --mixin3; margin: var(--m2); }; --mixin5: { border: calc(var(--c1) + var(--c2)) solid orange; }; --mixin6: { border: 16px solid orange; }; --mixin7: { border: 17px solid navy; }; --mixin8: { border: 17px dotted navy; }; --mixin9: var(--mixin8); } #mixin1 { @apply --mixin1; } #mixin2 { @apply --mixin2; } #mixin3 { padding: 1px; margin: var(--m1); @apply --mixin3; } #mixin4 { @apply --mixin4; } #mixin5 { @apply --mixin5; } #keyframes2 { --keyframe-finish: { left: 20px; }; } x-child-scope { padding: 10px; } #card { --story-content: { border: 11px solid orange; }; } #override { @apply --override-me; border: 19px solid steelblue; } </style> <div id="mixin1">mixin1</div> <div id="mixin2">mixin2</div> <div id="mixin3">mixin3</div> <div id="mixin4">mixin4</div> <div id="mixin5">mixin5</div> <hr> <x-keyframes id="keyframes1"></x-keyframes> <x-keyframes id="keyframes2"></x-keyframes> <x-child-scope id="child"></x-child-scope> <story-card id="card"></story-card> <div id="override">override</div> </template> <script> HTMLImports.whenReady(function() { Polymer({is: 'x-scope'}); }); </script> </dom-module> <dom-module id="x-var-produce-via-consume"> <template> <style> :host { display: block; border: 10px solid orange; --foo: { color: var(--bar); } } </style> </template> <script> HTMLImports.whenReady(function() { Polymer({ is: 'x-var-produce-via-consume' }); }); </script> </dom-module> <dom-module id="x-cache-child"> <template> <style> :host { display: block; color: var(--foo); @apply --bar; } </style> X </template> <script> HTMLImports.whenReady(function() { Polymer({ is: 'x-cache-child' }); }); </script> </dom-module> <dom-module id="x-cache-host-1"> <template> <style> :host { display: block; --foo: blue; --bar: { border: 10px solid black; }; } </style> <x-cache-child id="child"></x-bad-child> </template> <script> HTMLImports.whenReady(function() { Polymer({ is: 'x-cache-host-1' }); }); </script> </dom-module> <dom-module id="x-cache-host-2"> <template> <style> :host { display: block; --foo: blue; --bar: { border: 1px dotted green; }; } </style> <x-cache-child id="child"></x-bad-child> </template> <script> HTMLImports.whenReady(function() { Polymer({ is: 'x-cache-host-2' }); }); </script> </dom-module> <dom-module id="x-no-paren-apply-only"> <template> <style> :host { --bar: { border: 2px solid green; } } #child { @apply --bar; } </style> <div id="child">X</div> </template> <script> HTMLImports.whenReady(function() { Polymer({ is: 'x-no-paren-apply-only' }); }); </script> </dom-module> <dom-module id="x-redefine-three"> <template> <style> div { @apply --redefine; } </style> <div id="div"></div> </template> <script> HTMLImports.whenReady(function() { Polymer({is: 'x-redefine-three'}); }); </script> </dom-module> <dom-module id="x-redefine-two"> <template> <style> x-redefine-three { --redefine: { border: 2px solid gray; }; } </style> <x-redefine-three id="three"></x-redefine-three> </template> <script> HTMLImports.whenReady(function() { Polymer({is: 'x-redefine-two'}); }); </script> </dom-module> <dom-module id="x-redefine-one"> <template> <style> x-redefine-two { --redefine: { height: 100px; width: 100px; }; } </style> <x-redefine-two id="two"></x-redefine-two> </template> <script> HTMLImports.whenReady(function() { Polymer({is: 'x-redefine-one'}); }); </script> </dom-module> <dom-module id="order-child"> <template> <style> div { @apply --order-mixin; } </style> <div id="target"></div> </template> </dom-module> <dom-module id="order-parent"> <template> <style> order-child { --order-mixin: { border: 10px solid black; }; } </style> <order-child id="child"></order-child> </template> </dom-module> <dom-module id="order-gp"> <template> <style> order-child { --order-mixin: { }; } </style> <order-child id="child"></order-child> <order-parent id="parent"></order-parent> </template> </dom-module> <script> HTMLImports.whenReady(function() { Polymer({is: 'order-child'}); Polymer({is: 'order-parent'}); Polymer({is: 'order-gp'}); }); </script> <script> suite('scoped-styling-apply', function() { function assertComputed(element, value, property) { var computed = getComputedStyle(element); property = property || 'border-top-width'; assert.equal(computed[property], value, 'computed style incorrect for ' + property); } var styled = document.querySelector('x-scope'); test('variable mixins calculated correctly and inherit', function() { if (!window.ShadyCSS || ShadyCSS.nativeCss) { this.skip(); } var suffix = window.ShadyCSS.ApplyShim._separator + 'border'; var e = styled; let mixin1 = ShadyCSS.ScopingShim.getComputedStyleValue(e, '--mixin1' + suffix); let mixin2 = ShadyCSS.ScopingShim.getComputedStyleValue(e, '--mixin2' + suffix); let mixin3 = ShadyCSS.ScopingShim.getComputedStyleValue(e, '--mixin3' + suffix); let mixin4 = ShadyCSS.ScopingShim.getComputedStyleValue(e, '--mixin4' + suffix); e = styled.$.child; let cmixin1 = ShadyCSS.ScopingShim.getComputedStyleValue(e, '--mixin1' + suffix); let cmixin2 = ShadyCSS.ScopingShim.getComputedStyleValue(e, '--mixin2' + suffix); let cmixin3 = ShadyCSS.ScopingShim.getComputedStyleValue(e, '--mixin3' + suffix); let cmixin4 = ShadyCSS.ScopingShim.getComputedStyleValue(e, '--mixin4' + suffix); assert.equal(mixin1, cmixin1); assert.equal(mixin2, cmixin2); assert.equal(mixin3, cmixin3); assert.equal(mixin4, cmixin4); }); test('variable mixins apply', function() { assertComputed(styled.$.mixin1, '1px'); assertComputed(styled.$.mixin2, '2px'); assertComputed(styled.$.mixin3, '2px'); assertComputed(styled.$.mixin3, '1px', 'padding-top'); assertComputed(styled.$.mixin3, '1px', 'margin-top'); assertComputed(styled.$.mixin4, '2px'); assertComputed(styled.$.mixin4, '2px', 'padding-top'); assertComputed(styled.$.mixin4, '2px', 'margin-top'); }); test('mixins apply with url values', function() { var url = 'http://www.google.com/icon.png'; var e = styled.$.child; var actual, unescaped, propertyName; if (window.ShadyCSS && ShadyCSS.nativeCssApply) { actual = getComputedStyle(e).getPropertyValue('--mixin2'); // if strings aren't used in the url, getPropertyValue will escape the string, which breaks assert.include unescaped = actual.replace(/\\/g, ''); assert.include(unescaped, url); } else if (!window.ShadyCSS || ShadyCSS.nativeCss) { propertyName = '--mixin2' + window.ShadyCSS.ApplyShim._separator + 'background'; actual = getComputedStyle(e).getPropertyValue(propertyName); // if strings aren't used in the url, getPropertyValue will escape the string, which breaks assert.include unescaped = actual.replace(/\\/g, ''); assert.include(unescaped, url); } else { propertyName = '--mixin2'; actual = ShadyCSS.ScopingShim.getComputedStyleValue(e, propertyName); unescaped = actual.replace(/\\/g, ''); assert.include(unescaped, url); } }); test('variable mixins inherit and override', function() { var e = styled.$.child; assertComputed(e.$.mixin1, '1px'); assertComputed(e.$.mixin2, '3px'); assertComputed(e.$.mixin3, '2px'); assertComputed(e.$.mixin3, '3px', 'padding-top'); assertComputed(e.$.mixin4, '2px'); assertComputed(e.$.mixin4, '2px', 'padding-top'); assertComputed(e.$.mixin4, '2px', 'margin-top'); }); test('calc can be used in mixins', function() { assertComputed(styled.$.mixin5, '15px'); }); test('mixins work with selectors that contain element name', function() { assertComputed(styled.$.card.$.content, '11px'); }); test('mixins with trailing new line or } apply', function() { assertComputed(styled.$.child.$.mixin6, '16px'); assertComputed(styled.$.child.$.mixin7, '17px'); }); test('mixins with new `@apply --foo` syntax', function() { assertComputed(styled.$.child.$.mixin8, '17px'); }); test('mixins can be realiased with var()', function() { assertComputed(styled.$.child.$.mixin9, '17px'); }); test('mixins apply to @keyframe rules', function(done) { if (navigator.userAgent.match('Edge') && (!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 xKeyframes1 = styled.$.keyframes1; var xKeyframes2 = styled.$.keyframes2; var completed = 0; [xKeyframes1, xKeyframes2].forEach(function(xKeyframes, index) { var target = index === 0 ? '10px' : '20px'; var onAnimationEnd = function() { assert.include(xKeyframes.getComputedStyleValue('left'), target, xKeyframes.id); xKeyframes.removeEventListener('animationend', onAnimationEnd); xKeyframes.removeEventListener('webkitAnimationEnd', onAnimationEnd); xKeyframes.animated = false; if (++completed > 1) { done(); } }; xKeyframes.addEventListener('animationend', onAnimationEnd); xKeyframes.addEventListener('webkitAnimationEnd', onAnimationEnd); xKeyframes.animated = true; }); }); 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() { var d = document.createElement('x-var-produce-via-consume'); document.body.appendChild(d); var styleRoot = (!window.ShadyDOM || !ShadyDOM.isShadyRoot(d.shadowRoot)) ? d.shadowRoot : document.head; var selector = window.ShadyDOM ? 'style[scope~=x-var-produce-via-consume]' : 'style'; var staticStyle = styleRoot.querySelector(selector); assert.ok(staticStyle); assert.match(staticStyle.textContent, /display/, 'static style does not contain style content'); assert.equal(styleRoot.querySelectorAll(selector).length, 1); }); test('mixin values can be overridden by subsequent concrete properties', function() { assertComputed(styled.$.override, '19px'); }); test('@apply without parens is included in style cache behavior', function() { var e1 = document.createElement('x-cache-host-1'); var e2 = document.createElement('x-cache-host-2'); document.body.appendChild(e1); document.body.appendChild(e2); Polymer.flush(); assertComputed(e1.$.child, '10px'); assertComputed(e2.$.child, '1px'); }); test('@apply without parens triggers property shim', function() { var e = document.createElement('x-no-paren-apply-only'); document.body.appendChild(e); Polymer.flush(); assertComputed(e.$.child, '2px'); }); test('mixin redefinition resets old properties', function() { var e = document.createElement('x-redefine-one'); document.body.appendChild(e); Polymer.flush(); var div = e.$.two.$.three.$.div; assertComputed(div, '2px'); assertComputed(div, '0px', 'height'); }); test('mixin redefinition applies to complicated hierarchies', function() { var e = document.createElement('order-gp'); document.body.appendChild(e); Polymer.flush(); var childDiv = e.$.child.$.target; var parentDiv = e.$.parent.$.child.$.target; assertComputed(childDiv, '0px'); assertComputed(parentDiv, '10px'); }); }); </script> </body> </html>