1<!doctype html> 2<!-- 3@license 4Copyright (c) 2014 The Polymer Project Authors. All rights reserved. 5This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt 6The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt 7The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt 8Code distributed by Google as part of the polymer project is also 9subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt 10--> 11<html> 12<head> 13 14 <meta charset="utf-8"> 15 <script> 16 WCT = {waitFor: function (cb) {HTMLImports.whenReady(cb)}} 17 </script> 18 <script src="../../node_modules/wct-browser-legacy/browser.js"></script> 19 <script src="../../node_modules/@webcomponents/webcomponents-platform/webcomponents-platform.js"></script> 20 <script src="../../node_modules/es6-promise/dist/es6-promise.auto.min.js"></script> 21 <script src="../../node_modules/@webcomponents/template/template.js"></script> 22 <script src="../../node_modules/@webcomponents/html-imports/html-imports.min.js"></script> 23 <script src="../../node_modules/@webcomponents/shadydom/shadydom.min.js"></script> 24 <script src="../../node_modules/@webcomponents/custom-elements/custom-elements.min.js"></script> 25 <script src="../../apply-shim.min.js"></script> 26 <script src="../../custom-style-interface.min.js"></script> 27 <script src="../module/generated/make-element.js"></script> 28 <script src="../module/generated/custom-style-element.js"></script> 29 <script src="../module/generated/style-util.js"></script> 30 <title>Apply Shim</title> 31 32</head> 33<body> 34 <template id="basic"> 35 <style> 36 :host { 37 --mixin: { 38 border: 2px solid black; 39 }; 40 } 41 div { 42 @apply --mixin; 43 } 44 </style> 45 </template> 46 47 <template id="defaults"> 48 <style> 49 :host { 50 --mixin: { 51 border: 2px solid black; 52 } 53 } 54 div { 55 border: 1px dotted orange; 56 @apply --mixin; 57 } 58 span { 59 border: inherit; 60 @apply --mixin; 61 } 62 span { 63 border: initial; 64 @apply --mixin; 65 } 66 </style> 67 </template> 68 69 <template id="override"> 70 <style> 71 :host { 72 --override: { 73 padding: 2px; 74 }; 75 } 76 :host([override]) { 77 --override: { 78 border: 2px solid black; 79 }; 80 } 81 div { 82 @apply --override; 83 } 84 </style> 85 </template> 86 87 <template id="override-with-property"> 88 <style> 89 :root { 90 --prop-mixin: { 91 border: 2px solid black; 92 }; 93 } 94 x-foo { 95 --prop-mixin: blue; 96 color: var(--prop-mixin); 97 } 98 div { 99 @apply --prop-mixin; 100 } 101 </style> 102 </template> 103 104 <template id="define-with-var"> 105 <style> 106 :root { 107 --mixin-var: { 108 border: 2px solid black; 109 }; 110 } 111 div { 112 --mixin-var2: var(--mixin-var); 113 } 114 span { 115 --mixin-var: 20px; 116 --variable: var(--mixin-var); 117 } 118 </style> 119 </template> 120 121 <template id="x-element"> 122 <style> 123 :host { 124 @apply --my-mixin; 125 } 126 </style> 127 </template> 128 129 <template id="x-element2"> 130 <custom-style> 131 <style> 132 html { 133 --my-mixin: { 134 border: 2px solid black; 135 }; 136 } 137 </style> 138 </custom-style> 139 </template> 140 141 <template id="css-build" css-build="shadow"> 142 <style>:host{@apply --fake;}</style> 143 </template> 144 145 <template id="css-build-comment"><!--css-build:shadow--> 146 <style>:host{@apply --fake;}</style> 147 </template> 148 149 <script> 150 suite('Apply Shim', function() { 151 function copy(name) { 152 var template = document.querySelector('template#' + name); 153 return template.content.cloneNode(true); 154 } 155 156 function prep(templateName, elementName) { 157 var style = copy(templateName).querySelector('style'); 158 var ast = window.ShadyCSS.ApplyShim.transformStyle(style, elementName); 159 return {style: style, ast: ast}; 160 } 161 162 suite('Basic', function() { 163 var style, ast; 164 suiteSetup(function() { 165 var info = prep('basic'); 166 style = info.style; 167 ast = info.ast; 168 style.textContent = window.StyleUtil.toCssText(ast); 169 }); 170 171 test('style is transformed', function() { 172 var orig = copy('basic').querySelector('style'); 173 assert.notEqual(style.textContent, orig.textContent); 174 }); 175 176 test('mixin became custom properties', function() { 177 var definition = ast.rules[0]; 178 var application = ast.rules[1]; 179 assert.match(definition.cssText, /--mixin_-_border:\s*2px solid black/); 180 assert.match(application.cssText, /border:\s*var\(--mixin_-_border\)/); 181 }); 182 }); 183 suite('Defaults', function() { 184 var style, ast; // eslint-disable-line no-unused-vars 185 suiteSetup(function() { 186 var info = prep('defaults'); 187 style = info.style; 188 ast = info.ast; 189 }); 190 191 test('properties defined before mixin are used as defaults', function() { 192 var application = ast.rules[1]; 193 assert.match(application.cssText, /border:\s*var\(--mixin_-_border,\s*1px dotted orange\)/); 194 }); 195 196 test('inherit and initial default values are preserved', function () { 197 var application = ast.rules[2]; 198 assert.match(application.cssText, /border:\s*var\(--mixin_-_border,\s*inherit\)/); 199 application = ast.rules[3]; 200 assert.match(application.cssText, /border:\s*var\(--mixin_-_border,\s*initial\)/); 201 }); 202 }); 203 204 suite('override', function() { 205 var style, ast; // eslint-disable-line no-unused-vars 206 suiteSetup(function() { 207 var info = prep('override'); 208 style = info.style; 209 ast = info.ast; 210 }); 211 212 test('mixin redefinition sets unused properties to initial', function() { 213 var def1 = ast.rules[0]; 214 assert.match(def1.cssText, /--override_-_padding:\s*2px/); 215 var def2 = ast.rules[1]; 216 assert.match(def2.cssText, /--override_-_padding:\s*initial/); 217 assert.match(def2.cssText, /--override_-_border:\s*2px solid black/); 218 }); 219 220 test('mixin application includes all values', function() { 221 var application = ast.rules[2]; 222 assert.match(application.cssText, /padding:\s*var\(--override_-_padding\)/); 223 assert.match(application.cssText, /border:\s*var\(--override_-_border\)/); 224 }); 225 }); 226 227 suite('override with property', function() { 228 var style, ast; // eslint-disable-line no-unused-vars 229 suiteSetup(function() { 230 var info = prep('override-with-property'); 231 style = info.style; 232 ast = info.ast; 233 }); 234 235 test('mixin definition defers to property definition', function() { 236 var def = ast.rules[1]; 237 assert.notMatch(def.cssText, /border:\s*var\(--prop-mixin_-_border\)/); 238 }); 239 240 test('mixin can still be used by other parts of the page', function() { 241 var def = ast.rules[2]; 242 assert.match(def.cssText, /border:\s*var\(--prop-mixin_-_border\)/); 243 }); 244 }); 245 246 suite('define with var()', function() { 247 var style, ast; // eslint-disable-line no-unused-vars 248 suiteSetup(function() { 249 var info = prep('define-with-var'); 250 style = info.style; 251 ast = info.ast; 252 }); 253 254 test('mixin-var2 is defined with mixin-var\'s values', function() { 255 var def = ast.rules[1]; 256 assert.match(def.cssText, /--mixin-var2_-_border:\s*var\(--mixin-var_-_border\)/); 257 }); 258 259 test('var usage of mixin is not removed, preserving override functionality', function() { 260 var def = ast.rules[2]; 261 assert.match(def.cssText, /--variable:\s*var\(--mixin-var\)/); 262 }); 263 }); 264 265 suite('invalidation on new definitions', function() { 266 var style, ast, element; 267 suiteSetup(function() { 268 makeElement('x-element'); 269 element = document.createElement('x-element'); 270 document.body.appendChild(element); 271 style = element.shadowRoot ? element.shadowRoot.querySelector('style') : document.head.querySelector('style[scope=x-element]'); 272 }); 273 274 test('element initially has no definition', function() { 275 var ast = window.StyleUtil.rulesForStyle(style); 276 assert.equal(ast.rules[0].cssText, ';'); 277 }); 278 279 test('Revalidating Apply Shim on element template fills in properties', function() { 280 var nodes = copy('x-element2'); 281 document.body.appendChild(nodes); 282 window.ShadyCSS.styleDocument(); 283 var ast = window.StyleUtil.rulesForStyle(style); 284 assert.match(ast.rules[0].cssText, /border:\s*var\(--my-mixin_-_border\)/); 285 }); 286 }); 287 288 test('templates with "css-build" will not be processed by ApplyShim', function() { 289 makeElement('css-build'); 290 const template = document.querySelector('template#css-build'); 291 assert.equal(template._styleAst, undefined); 292 const style = template.content.querySelector('style'); 293 assert.match(style.textContent.trim(), /:host\s*{\s*@apply --fake;\s*}/); 294 }); 295 296 test('templates with "css-build" comment will not be processed by ApplyShim', function () { 297 const template = document.querySelector('template#css-build-comment'); 298 const buildComment = template.content.firstChild; 299 assert.instanceOf(buildComment, Comment, 'first node in template content should be a Comment'); 300 makeElement('css-build-comment'); 301 assert.equal(template._styleAst, undefined); 302 const style = template.content.querySelector('style'); 303 assert.match(style.textContent.trim(), /:host\s*{\s*@apply --fake;\s*}/); 304 assert.equal(buildComment.parentNode, null, 'build comment should be removed'); 305 }); 306 }); 307 </script> 308</body> 309</html> 310