-
Notifications
You must be signed in to change notification settings - Fork 2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Shim CSS Mixins in terms of CSS Custom Properties #3587
Merged
Merged
Changes from all commits
Commits
Show all changes
80 commits
Select commit
Hold shift + click to select a range
17bc75a
check for native css variables
dfreedm ff5658a
keep custom properties, still unpack mixins
dfreedm 5ea78b0
make `updateStyles` (modulo @apply) work with native custom properties.
b2777f9
modifications
dfreedm 0374478
sigh
dfreedm c2b5a82
fix tests in firefox safari and chrome 49
dfreedm bc982c8
add back missing styleutil code in x-styling
dfreedm b4ec339
support all the fallback cases with nested parens
dfreedm 6589a50
fix rules with property and mixin definitions for native
dfreedm 49e0873
First draft of @apply shim
dfreedm 5d700e5
step 3
dfreedm 62dc8b9
Process stylesheets in custom-styles
dfreedm 79afddf
always add semicolon in flattenMixin
dfreedm c120d37
reset order back to master
dfreedm 0e903bc
step 4
dfreedm b351a99
Temporary ordering fixup for native @apply shim.
8f9d308
better step 5
dfreedm e72e974
make custom-style support @apply shim.
45fd0ec
* make @apply regex match globally
626083c
Collect default property values between consumption and application
dfreedm 142c846
stupid stateful regexes
dfreedm e62b322
Handle realiasing mixins (step 6)
dfreedm 4a21057
Add more tests for apply shim
dfreedm 844b9e7
fix :root for apply shim
dfreedm fcf96dd
add StyleTransformer smoke test.
96d341a
Move regexes from style-properties to style-util for easier sharing
dfreedm e287c6f
Move check for CSS Custom Properties to settings lib
dfreedm fb0eaaa
add apply shim to smoke test
dfreedm 39b067f
actually let uses set useNativeCSSProperties false
dfreedm 6eca881
SCOPE_SELECTORS needs to work with built selectors for custom-style a…
dfreedm a96210c
No need to decorate styles for apply shim
dfreedm fc7ea29
apply mixins and gather defaults incrementally
dfreedm 558a3f7
Fix @apply consumption to incrementally process rule text
dfreedm 1dc1ccb
MORE APPLY SHIM TESTING
dfreedm f279858
Make sure @apply without parens works in property shim as expected
dfreedm 49e1c9f
Simpler tracking of mixin properties
dfreedm b4ead5c
Support builds of CSS
dfreedm 8274efc
patch a few spots that custom property shim needs to know about the b…
dfreedm b9c4da2
still need to transform the selectors if a shadow build was the source
dfreedm 788c5e4
support tests with build to choose the right property
dfreedm 7a7fbfa
make `importHref` avoid re-importing already loaded resources.
3f27aeb
One more spot a shady build will break custom property shim
dfreedm 795831f
A few more allowances for the builds
dfreedm 4a3b322
mark elements and custom-styles as built, no globals
dfreedm 4fcf6c2
use propertyDataFromStyles for :host and :root
dfreedm 0f5acbb
make tests pass by hacking `propertyDataFromStyles`, needs refactoring.
7afa3cf
Search for properties in :host and :root rules at the same time
dfreedm 53f8d2e
Don't expect shady built styles to be in head
dfreedm 9d272e0
Fixes #3637. Normalizes attached timing between Shady and Shadow DOM …
00bb79f
Fixes #3638. Avoid spamming document.head with already loaded link el…
b67f413
actually listen for the error event (unclear how to test error withou…
2d37b2b
fix typo
f17685b
Merge branch 'fix-3637,3638' into mixins-as-custom-properties
053bc8a
fix lint errors
dfreedm b4c853c
Merge branch 'master' into mixins-as-custom-properties
dfreedm f16f6ab
fix bad merge conflict
dfreedm 4f92704
Safari 9.1.1 is still busted, drop minor version check for AppleWebKit
dfreedm 0a7cd88
only apply statically shimmed styles if the element has cssText (this…
a33c687
* slight optimization: cache cssBuild info on element.
6e1bff0
revert dom scoping change and add clarifying comment about why this i…
03fd748
formatting
72f194c
custom-style: avoid applying shimmed custom properties when native cu…
c946232
avoid shimming styles under shady dom when there is a shady css build.
7644af2
custom-style: when native custom properties are in use and no build i…
1be473d
avoid work in the presence of a css build.
0d14881
Merge branch 'master' into mixins-as-custom-properties
6cc7774
add test for :host(element-name)
c597fff
correct custom-style under shadow build when using shady and custom p…
4500e4b
fix tests to not rely on order in className
eccaee2
Support custom-style with css-build status in HTMLImports polyfill
dfreedm ce06254
Clean up logic in custom-style _apply
dfreedm a2550bc
Loop over all property names ever used for a mixin
dfreedm acf5f5a
Bail early if rule does not have properties
dfreedm 5626fc7
Comments.
b3d6336
test that invalid @media rules do *not* apply via the custom properti…
4be2598
Use `_-_` as seperator for apply-shim created variables
dfreedm 22af46f
Fix custom-style test with new separator
dfreedm 6383358
fix a few more tests for built styles
dfreedm 0ae2ee7
Revert "Fixes #3637. Normalizes attached timing between Shady and Sha…
dfreedm 1ec23a5
[ci skip] PolymerBuild global has been removed
dfreedm File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,247 @@ | ||
<!-- | ||
@license | ||
Copyright (c) 2014 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 | ||
--> | ||
<link rel="import" href="style-util.html"> | ||
<script> | ||
/** | ||
* The apply shim simulates the behavior of `@apply` proposed at | ||
* https://tabatkins.github.io/specs/css-apply-rule/. | ||
* The approach is to convert a property like this: | ||
* | ||
* --foo: {color: red; background: blue;} | ||
* | ||
* to this: | ||
* | ||
* --foo_-_color: red; | ||
* --foo_-_background: blue; | ||
* | ||
* Then where `@apply --foo` is used, that is converted to: | ||
* | ||
* color: var(--foo_-_color); | ||
* background: var(--foo_-_background); | ||
* | ||
* This approach generally works but there are some issues and limitations. | ||
* Consider, for example, that somewhere *between* where `--foo` is set and used, | ||
* another element sets it to: | ||
* | ||
* --foo: { border: 2px solid red; } | ||
* | ||
* We must now ensure that the color and background from the previous setting | ||
* do not apply. This is accomplished by changing the property set to this: | ||
* | ||
* --foo_-_border: 2px solid red; | ||
* --foo_-_color: initial; | ||
* --foo_-_background: initial; | ||
* | ||
* This works but introduces one new issue. | ||
* Consider this setup at the point where the `@apply` is used: | ||
* | ||
* background: orange; | ||
* @apply --foo; | ||
* | ||
* In this case the background will be unset (initial) rather than the desired | ||
* `orange`. We address this by altering the property set to use a fallback | ||
* value like this: | ||
* | ||
* color: var(--foo_-_color); | ||
* background: var(--foo_-_background, orange); | ||
* border: var(--foo_-_border); | ||
* | ||
* Note that the default is retained in the property set and the `background` is | ||
* the desired `orange`. This leads us to a limitation. | ||
* | ||
* Limitation 1: | ||
|
||
* Only properties in the rule where the `@apply` | ||
* is used are considered as default values. | ||
* If another rule matches the element and sets `background` with | ||
* less specificity than the rule in which `@apply` appears, | ||
* the `background` will not be set. | ||
* | ||
* Limitation 2: | ||
* | ||
* When using Polymer's `updateStyles` api, new properties may not be set for | ||
* `@apply` properties. | ||
|
||
*/ | ||
Polymer.ApplyShim = (function(){ | ||
'use strict'; | ||
|
||
var styleUtil = Polymer.StyleUtil; | ||
|
||
var MIXIN_MATCH = styleUtil.rx.MIXIN_MATCH; | ||
var VAR_ASSIGN = styleUtil.rx.VAR_ASSIGN; | ||
var VAR_MATCH = styleUtil.rx.VAR_MATCH; | ||
var APPLY_NAME_CLEAN = /;\s*/m; | ||
|
||
// separator used between mixin-name and mixin-property-name when producing properties | ||
// NOTE: plain '-' may cause collisions in user styles | ||
var MIXIN_VAR_SEP = '_-_'; | ||
|
||
// map of mixin to property names | ||
// --foo: {border: 2px} -> (--foo, ['border']) | ||
var mixinMap = {}; | ||
|
||
function mapSet(name, prop) { | ||
name = name.trim(); | ||
mixinMap[name] = prop; | ||
} | ||
|
||
function mapGet(name) { | ||
name = name.trim(); | ||
return mixinMap[name]; | ||
} | ||
|
||
// "parse" a mixin definition into a map of properties and values | ||
// cssTextToMap('border: 2px solid black') -> ('border', '2px solid black') | ||
function cssTextToMap(text) { | ||
var props = text.split(';'); | ||
var out = {}; | ||
for (var i = 0, p, sp; i < props.length; i++) { | ||
p = props[i]; | ||
if (p) { | ||
sp = p.split(':'); | ||
// ignore lines that aren't definitions like @media | ||
if (sp.length > 1) { | ||
// some properties may have ':' in the value, like data urls | ||
out[sp[0].trim()] = sp.slice(1).join(':'); | ||
} | ||
} | ||
} | ||
return out; | ||
} | ||
|
||
function produceCssProperties(matchText, propertyName, valueProperty, valueMixin) { | ||
// handle case where property value is a mixin | ||
if (valueProperty) { | ||
VAR_MATCH.lastIndex = 0; | ||
var m = VAR_MATCH.exec(valueProperty); | ||
if (m) { | ||
var value = m[2]; | ||
if (mapGet(value)){ | ||
valueMixin = '@apply ' + value + ';'; | ||
} | ||
} | ||
} | ||
if (!valueMixin) { | ||
return matchText; | ||
} | ||
var mixinAsProperties = consumeCssProperties(valueMixin); | ||
var prefix = matchText.slice(0, matchText.indexOf('--')); | ||
var mixinValues = cssTextToMap(mixinAsProperties); | ||
var oldProperties = mapGet(propertyName); | ||
var combinedProps = mixinValues; | ||
if (oldProperties) { | ||
// NOTE: since we use mixin, the map of properties is updated here | ||
// and this is what we want. | ||
combinedProps = Polymer.Base.mixin(oldProperties, mixinValues); | ||
} else { | ||
mapSet(propertyName, combinedProps); | ||
} | ||
var out = []; | ||
var p, v; | ||
// set variables defined by current mixin | ||
for (p in combinedProps) { | ||
v = mixinValues[p]; | ||
// if property not defined by current mixin, set initial | ||
if (v === undefined) { | ||
v = 'initial'; | ||
} | ||
out.push(propertyName + MIXIN_VAR_SEP + p + ': ' + v); | ||
} | ||
return prefix + out.join('; ') + ';'; | ||
} | ||
|
||
// fix shim'd var syntax | ||
// var(--a, --b) -> var(--a, var(--b)); | ||
function fixVars(matchText, prefix, value, fallback) { | ||
// if fallback doesn't exist, or isn't a broken variable, abort | ||
if (!fallback || fallback.indexOf('--') !== 0) { | ||
return matchText; | ||
} | ||
return [prefix, 'var(', value, ', var(', fallback, '));'].join(''); | ||
} | ||
|
||
// produce variable consumption at the site of mixin consumption | ||
// @apply --foo; -> for all props (${propname}: var(--foo_-_${propname}, ${fallback[propname]}})) | ||
// Example: | ||
// border: var(--foo_-_border); padding: var(--foo_-_padding, 2px) | ||
function atApplyToCssProperties(mixinName, fallbacks) { | ||
mixinName = mixinName.replace(APPLY_NAME_CLEAN, ''); | ||
var vars = []; | ||
var mixinProperties = mapGet(mixinName); | ||
if (mixinProperties) { | ||
var p, parts, f; | ||
for (p in mixinProperties) { | ||
f = fallbacks && fallbacks[p]; | ||
parts = [p, ': var(', mixinName, MIXIN_VAR_SEP, p]; | ||
if (f) { | ||
parts.push(',', f); | ||
} | ||
parts.push(')'); | ||
vars.push(parts.join('')); | ||
} | ||
} | ||
return vars.join('; '); | ||
} | ||
|
||
// replace mixin consumption with variable consumption | ||
function consumeCssProperties(text) { | ||
var m; | ||
// loop over text until all mixins with defintions have been applied | ||
while((m = MIXIN_MATCH.exec(text))) { | ||
var matchText = m[0]; | ||
var mixinName = m[1]; | ||
var idx = m.index; | ||
// collect properties before apply to be "defaults" if mixin might override them | ||
// match includes a "prefix", so find the start and end positions of @apply | ||
var applyPos = idx + matchText.indexOf('@apply'); | ||
var afterApplyPos = idx + matchText.length; | ||
// find props defined before this @apply | ||
var textBeforeApply = text.slice(0, applyPos); | ||
var textAfterApply = text.slice(afterApplyPos); | ||
var defaults = cssTextToMap(textBeforeApply); | ||
var replacement = atApplyToCssProperties(mixinName, defaults); | ||
// use regex match position to replace mixin, keep linear processing time | ||
text = [textBeforeApply, replacement, textAfterApply].join(''); | ||
// move regex search to _after_ replacement | ||
MIXIN_MATCH.lastIndex = idx + replacement.length; | ||
} | ||
return text; | ||
} | ||
|
||
var ApplyShim = { | ||
_map: mixinMap, | ||
_separator: MIXIN_VAR_SEP, | ||
transform: function(styles) { | ||
styleUtil.forRulesInStyles(styles, this._boundTransformRule); | ||
}, | ||
transformRule: function(rule) { | ||
rule.cssText = this.transformCssText(rule.parsedCssText); | ||
// :root was only used for variable assignment in property shim, | ||
// but generates invalid selectors with real properties. | ||
// replace with `:host > *`, which serves the same effect | ||
if (rule.selector === ':root') { | ||
rule.selector = ':host > *'; | ||
} | ||
}, | ||
transformCssText: function(cssText) { | ||
// fix shim variables | ||
cssText = cssText.replace(VAR_MATCH, fixVars); | ||
// produce variables | ||
cssText = cssText.replace(VAR_ASSIGN, produceCssProperties); | ||
// consume mixins | ||
return consumeCssProperties(cssText); | ||
} | ||
}; | ||
|
||
ApplyShim._boundTransformRule = ApplyShim.transformRule.bind(ApplyShim); | ||
return ApplyShim; | ||
})(); | ||
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is the else here? Don't we always want to update the property map with the list of all properties that have been used for that mixin?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since we are using
mixin
, the reference in the map is always the same and we don't need toset
again.