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="./test-flags.js"></script> 19 <script src="../node_modules/wct-browser-legacy/browser.js"></script> 20 <script src="../node_modules/@webcomponents/webcomponents-platform/webcomponents-platform.js"></script> 21 <script src="../node_modules/es6-promise/dist/es6-promise.auto.min.js"></script> 22 <script src="../node_modules/@webcomponents/template/template.js"></script> 23 <script src="../node_modules/@webcomponents/html-imports/html-imports.min.js"></script> 24 <script src="../node_modules/@webcomponents/shadydom/shadydom.min.js"></script> 25 <script src="../node_modules/@webcomponents/custom-elements/custom-elements.min.js"></script> 26 <script src="../scoping-shim.min.js"></script> 27 <script src="../apply-shim.min.js"></script> 28 <script> 29 if (customElements.polyfillWrapFlushCallback) { 30 // delay definition of custom-style until after template polyfill loads 31 customElements.polyfillWrapFlushCallback(function(cb) { 32 HTMLImports.whenReady(cb); 33 }); 34 } 35 </script> 36 <script src="../custom-style-interface.min.js"></script> 37 <script src="module/generated/custom-style-element.js"></script> 38 <script src="module/generated/make-element.js"></script> 39 <title>Apply Shim</title> 40 41</head> 42<body> 43 <template id="basic"> 44 <style> 45 :host { 46 --mixin: { 47 border: 2px solid black; 48 }; 49 } 50 div { 51 @apply --mixin; 52 } 53 </style> 54 </template> 55 56 <template id="defaults"> 57 <style> 58 :host { 59 --mixin: { 60 border: 2px solid black; 61 } 62 } 63 div { 64 border: 1px dotted orange; 65 @apply --mixin; 66 } 67 span { 68 border: inherit; 69 @apply --mixin; 70 } 71 span { 72 border: initial; 73 @apply --mixin; 74 } 75 </style> 76 </template> 77 78 <template id="override"> 79 <style> 80 :host { 81 --override: { 82 padding: 2px; 83 }; 84 } 85 :host([override]) { 86 --override: { 87 border: 2px solid black; 88 }; 89 } 90 div { 91 @apply --override; 92 } 93 </style> 94 </template> 95 96 <template id="override-with-property"> 97 <style> 98 :root { 99 --prop-mixin: { 100 border: 2px solid black; 101 }; 102 } 103 x-foo { 104 --prop-mixin: blue; 105 color: var(--prop-mixin); 106 } 107 div { 108 @apply --prop-mixin; 109 } 110 </style> 111 </template> 112 113 <template id="define-with-var"> 114 <style> 115 :root { 116 --mixin-var: { 117 border: 2px solid black; 118 }; 119 } 120 div { 121 --mixin-var2: var(--mixin-var); 122 } 123 span { 124 --mixin-var: 20px; 125 --variable: var(--mixin-var); 126 } 127 </style> 128 </template> 129 130 <template id="x-element"> 131 <style> 132 :host { 133 @apply --my-mixin; 134 } 135 </style> 136 </template> 137 138 <template id="x-element2"> 139 <custom-style> 140 <style> 141 html { 142 --my-mixin: { 143 border: 2px solid black; 144 }; 145 } 146 </style> 147 </custom-style> 148 </template> 149 <template id="important"> 150 <style> 151 :host { 152 --mixin-important: { 153 background-color: white; 154 border: 2px solid black !important; 155 color: white !important; 156 }; 157 --mixin: { 158 background-color: red; 159 border: 1px dotted orange; 160 color: black !important; 161 }; 162 } 163 div { 164 @apply --mixin-important; 165 @apply --mixin; 166 } 167 </style> 168 </template> 169 <script> 170 suite('Apply Shim', function() { 171 function copy(name) { 172 var template = document.querySelector('template#' + name); 173 return template.content.cloneNode(true); 174 } 175 176 function prep(templateName, elementName) { 177 var style = copy(templateName).querySelector('style'); 178 var ast = window.ShadyCSS.ApplyShim.transformStyle(style, elementName); 179 return {style: style, ast: ast}; 180 } 181 182 suite('Basic', function() { 183 var style, ast; 184 suiteSetup(function() { 185 var info = prep('basic'); 186 style = info.style; 187 ast = info.ast; 188 style.textContent = window.ShadyCSS.ScopingShim.styleAstToString(ast); 189 }); 190 191 test('style is transformed', function() { 192 var orig = copy('basic').querySelector('style'); 193 assert.notEqual(style.textContent, orig.textContent); 194 }); 195 196 test('mixin became custom properties', function() { 197 var definition = ast.rules[0]; 198 var application = ast.rules[1]; 199 assert.match(definition.cssText, /--mixin_-_border:\s*2px solid black/); 200 assert.match(application.cssText, /border:\s*var\(--mixin_-_border\)/); 201 }); 202 }); 203 suite('Defaults', function() { 204 var style, ast; // eslint-disable-line no-unused-vars 205 suiteSetup(function() { 206 var info = prep('defaults'); 207 style = info.style; 208 ast = info.ast; 209 }); 210 211 test('properties defined before mixin are used as defaults', function() { 212 var application = ast.rules[1]; 213 assert.match(application.cssText, /border:\s*var\(--mixin_-_border,\s*1px dotted orange\)/); 214 }); 215 216 test('inherit and initial default values are preserved', function() { 217 var application = ast.rules[2]; 218 assert.match(application.cssText, /border:\s*var\(--mixin_-_border,\s*inherit\)/); 219 application = ast.rules[3]; 220 assert.match(application.cssText, /border:\s*var\(--mixin_-_border,\s*initial\)/); 221 }); 222 }); 223 224 suite('override', function() { 225 var style, ast; // eslint-disable-line no-unused-vars 226 suiteSetup(function() { 227 var info = prep('override'); 228 style = info.style; 229 ast = info.ast; 230 }); 231 232 test('mixin redefinition sets unused properties to initial', function() { 233 var def1 = ast.rules[0]; 234 assert.match(def1.cssText, /--override_-_padding:\s*2px/); 235 var def2 = ast.rules[1]; 236 assert.match(def2.cssText, /--override_-_padding:\s*initial/); 237 assert.match(def2.cssText, /--override_-_border:\s*2px solid black/); 238 }); 239 240 test('mixin application includes all values', function() { 241 var application = ast.rules[2]; 242 assert.match(application.cssText, /padding:\s*var\(--override_-_padding\)/); 243 assert.match(application.cssText, /border:\s*var\(--override_-_border\)/); 244 }); 245 }); 246 247 suite('override with property', function() { 248 var style, ast; // eslint-disable-line no-unused-vars 249 suiteSetup(function() { 250 var info = prep('override-with-property'); 251 style = info.style; 252 ast = info.ast; 253 }); 254 255 test('mixin definition defers to property definition', function() { 256 var def = ast.rules[1]; 257 assert.notMatch(def.cssText, /border:\s*var\(--prop-mixin_-_border\)/); 258 }); 259 260 test('mixin can still be used by other parts of the page', function() { 261 var def = ast.rules[2]; 262 assert.match(def.cssText, /border:\s*var\(--prop-mixin_-_border\)/); 263 }); 264 }); 265 266 suite('define with var()', function() { 267 var style, ast; // eslint-disable-line no-unused-vars 268 suiteSetup(function() { 269 var info = prep('define-with-var'); 270 style = info.style; 271 ast = info.ast; 272 }); 273 274 test('mixin-var2 is defined with mixin-var\'s values', function() { 275 var def = ast.rules[1]; 276 assert.match(def.cssText, /--mixin-var2_-_border:\s*var\(--mixin-var_-_border\)/); 277 }); 278 279 test('var usage of mixin is not removed, preserving override functionality', function() { 280 var def = ast.rules[2]; 281 assert.match(def.cssText, /--variable:\s*var\(--mixin-var\)/); 282 }); 283 }); 284 285 suite('invalidation on new definitions', function() { 286 var style, ast, element; 287 suiteSetup(function() { 288 makeElement('x-element'); 289 element = document.createElement('x-element'); 290 document.body.appendChild(element); 291 style = element.shadowRoot ? element.shadowRoot.querySelector('style') : document.head.querySelector('style[scope=x-element]'); 292 }); 293 294 test('element initially has no definition', function() { 295 var ast = window.ShadyCSS.ScopingShim._styleInfoForNode(element)._getStyleRules(); 296 assert.equal(ast.rules[0].cssText, ';'); 297 }); 298 299 test('Revalidating Apply Shim on element template fills in properties', function() { 300 var nodes = copy('x-element2'); 301 document.body.appendChild(nodes); 302 window.ShadyCSS.styleDocument(); 303 var ast = window.ShadyCSS.ScopingShim._styleInfoForNode(element)._getStyleRules(); 304 if (window.ShadyCSS.nativeCss) { 305 assert.match(ast.rules[0].cssText, /border:\s*var\(--my-mixin_-_border\)/); 306 } else { 307 assert.match(ast.rules[0].cssText, /border:\s*2px solid black/); 308 } 309 }); 310 }); 311 suite('!important', function() { 312 var ast; 313 suiteSetup(function() { 314 var info = prep('important'); 315 ast = info.ast; 316 }); 317 318 test('!important in mixin correctly translates to !important in resulting custom property', function() { 319 var application = ast.rules[1]; 320 assert.match(application.cssText, /border:\s*var\(--mixin-important_-_border\)\s*!important/); 321 }); 322 test("Fallback of related property without !important is kept without !important in resulting custom property", function() { 323 var application = ast.rules[1]; 324 assert.match(application.cssText, /border:\s*var\(--mixin_-_border,\s*var\(--mixin-important_-_border\)\)/); 325 }); 326 test('Two mixins with both !important are treated in correct order while also preserving !important in resulting custom property', function () { 327 var application = ast.rules[1]; 328 assert.match(application.cssText, /color:\s*var\(--mixin-important_-_color\)\s*!important/); 329 assert.match(application.cssText, /color:\s*var\(--mixin_-_color,\s*var\(--mixin-important_-_color\)\)\s*!important/); 330 }) 331 test('Properties without !important in a mixin with !important are treated independently', function() { 332 var application = ast.rules[1]; 333 assert.match(application.cssText, /background-color:\s*var\(--mixin_-_background-color,\s*var\(--mixin-important_-_background-color\)\)/); 334 assert.notMatch(application.cssText, /background-color:\s*var\(--mixin_-_background-color,\s*var\(--mixin-important_-_background-color\)\)\s*!important/); 335 336 assert.match(application.cssText, /background-color:\s*var\(--mixin-important_-_background-color\)/); 337 assert.notMatch(application.cssText, /background-color:\s*var\(--mixin-important_-_background-color\)\s*!important/); 338 }); 339 }); 340 }); 341 </script> 342</body> 343</html> 344