diff options
author | Eevee (Alex Munroe) <eevee.git@veekun.com> | 2013-08-21 19:03:41 -0700 |
---|---|---|
committer | Eevee (Alex Munroe) <eevee.git@veekun.com> | 2013-08-21 19:03:41 -0700 |
commit | e6e920ac90368f0044536505a408f8809860aece (patch) | |
tree | 7a36a133c9f2d7263391860776af89db2400c07b | |
parent | 5594328337f4078db708d6d14411f435deec6ad1 (diff) | |
download | pyscss-e6e920ac90368f0044536505a408f8809860aece.tar.gz |
Gradient cleanup, now with tests! Also unbreaks radial-gradient.
-rw-r--r-- | scss/functions/compass/gradients.py | 44 | ||||
-rw-r--r-- | scss/tests/files/compass/gradients.css | 58 | ||||
-rw-r--r-- | scss/tests/files/compass/gradients.scss | 83 | ||||
-rw-r--r-- | scss/tests/files/kronuz/linear-gradient.css | 3 | ||||
-rw-r--r-- | scss/tests/functions/compass/test_gradients.py | 57 |
5 files changed, 222 insertions, 23 deletions
diff --git a/scss/functions/compass/gradients.py b/scss/functions/compass/gradients.py index 2a5cd32..37fd5fe 100644 --- a/scss/functions/compass/gradients.py +++ b/scss/functions/compass/gradients.py @@ -62,10 +62,11 @@ def __color_stops(percentages, *args): if stops[-1] is None: stops[-1] = Number(100, '%') - if percentages: - max_stops = max(s and (s.value if s.unit != '%' else None) or None for s in stops) + maxable_stops = [s for s in stops if s and s.unit != '%'] + if maxable_stops: + max_stops = max(maxable_stops) else: - max_stops = max(s if s and s.unit != '%' else None for s in stops) + max_stops = None stops = [_s / max_stops if _s and _s.unit != '%' else _s for _s in stops] @@ -88,10 +89,23 @@ def __color_stops(percentages, *args): if not max_stops or percentages: pass else: - stops = [s * max_stops for s in stops] + stops = [s if s.unit == '%' else s * max_stops for s in stops] + return zip(stops, colors) +def _render_standard_color_stops(color_stops): + pairs = [] + for i, (stop, color) in enumerate(color_stops): + if ((i == 0 and stop == Number(0, '%')) or + (i == len(color_stops) - 1 and stop == Number(100, '%'))): + pairs.append(color) + else: + pairs.append(List([color, stop], use_comma=False)) + + return List(pairs, use_comma=True) + + @register('grad-color-stops') def grad_color_stops(*args): args = List.from_maybe_starargs(args) @@ -155,15 +169,9 @@ def color_stops_in_percentages(*args): def _get_gradient_position_and_angle(args): for arg in args: - if isinstance(arg, (String, Number, six.string_types)): - _arg = [arg] - elif isinstance(arg, (list, tuple, List)): - _arg = arg - else: - continue ret = None skip = False - for a in _arg: + for a in arg: if isinstance(a, Color): skip = True break @@ -178,26 +186,20 @@ def _get_gradient_position_and_angle(args): 'top', 'bottom', 'left', 'right', ): - if String(seek) in _arg: + if String(seek) in arg: return arg return None def _get_gradient_shape_and_size(args): for arg in args: - if isinstance(arg, (String, Number, six.string_types)): - _arg = [arg] - elif isinstance(arg, (list, tuple, List)): - _arg = arg - else: - continue for seek in ( 'circle', 'ellipse', 'closest-side', 'closest-corner', 'farthest-side', 'farthest-corner', 'contain', 'cover', ): - if seek in _arg: + if String(seek) in arg: return arg return None @@ -227,7 +229,7 @@ def radial_gradient(*args): position(position_and_angle) if position_and_angle is not None else None, shape_and_size if shape_and_size is not None else None, ] - args.extend('%s %s' % (c, to_str(s)) for s, c in color_stops) + args.extend(_render_standard_color_stops(color_stops)) to__s = 'radial-gradient(' + ', '.join(to_str(a) for a in args or [] if a is not None) + ')' ret = String.unquoted(to__s) @@ -282,7 +284,7 @@ def linear_gradient(*args): args = [ position(position_and_angle) if position_and_angle is not None else None, ] - args.extend('%s %s' % (c.render(), s.render()) for s, c in color_stops) + args.extend(_render_standard_color_stops(color_stops)) to__s = 'linear-gradient(' + ', '.join(to_str(a) for a in args or [] if a is not None) + ')' ret = String.unquoted(to__s) diff --git a/scss/tests/files/compass/gradients.css b/scss/tests/files/compass/gradients.css new file mode 100644 index 0000000..9a99ca1 --- /dev/null +++ b/scss/tests/files/compass/gradients.css @@ -0,0 +1,58 @@ +.bg-shortcut-linear-gradient { + background: #fff linear-gradient(top left, #ddd, #aaa); +} +.bg-shortcut-radial-gradient { + background: #fff radial-gradient(center center, #ddd, #aaa 100px); +} +.bg-linear-gradient-angle-svg { + background-image: linear-gradient(-45deg, blue, black); +} +.bg-linear-gradient-angle2-svg { + background-image: linear-gradient(top left, blue, black); +} +.bg-linear-gradient { + background-image: linear-gradient(top left, #ddd, #aaa); +} +.bg-linear-gradient-pixel-stop-from-top { + background-image: linear-gradient(top, #ddd 10px, #aaa 40px); +} +.bg-linear-gradient-pixel-stop-from-left { + background-image: linear-gradient(left, #ddd 10px, #aaa 40px); +} +.transparent-in-linear-gradient { + background-image: #fff linear-gradient(top left, transparent, #aaa); +} +.bg-radial-gradient { + background-image: radial-gradient(center center, #ddd, transparent 100px); +} +.bg-linear-gradient-with-angle { + background-image: linear-gradient(-45deg, #ddd, #aaa); +} +.bg-radial-gradient-with-angle-and-shape { + background-image: radial-gradient(ellipse cover, #ddd, #aaa 100px); +} +.bg-all-gradient-types { + background-image: linear-gradient(top left, #ddd, #aaa); + background-image: radial-gradient(center center, #ddd, #aaa 100px); +} +.border-image-gradient { + border-image: radial-gradient(#0f0, #f00 100px) 100 stretch; +} +.direct-list-image-with-gradient { + list-style-image: radial-gradient(lime, red 10px); +} +.shorthand-list-image-with-gradient { + list-style: outside radial-gradient(lime, red 10px); +} +.content-with-gradient { + content: radial-gradient(lime, red 10px); +} +.bg-linear-gradient-no-position { + background-image: linear-gradient(#ddd, #aaa); +} +.bg-radial-gradient-no-position { + background-image: radial-gradient(#ddd, #aaa 100px); +} +.cross-fade { + background-image: cross-fade(radial-gradient(#ddd, #aaa 100px), url("4x6.png")); +} diff --git a/scss/tests/files/compass/gradients.scss b/scss/tests/files/compass/gradients.scss new file mode 100644 index 0000000..9f7d726 --- /dev/null +++ b/scss/tests/files/compass/gradients.scss @@ -0,0 +1,83 @@ +// Borrowed from Compass's actual test suite, but cut down to just the gradient +// calls, and with some editing to e.g. preserve color formatting: +// https://github.com/chriseppstein/compass/blob/stable/test/fixtures/stylesheets/compass/sass/gradients.sass +// Similarly, the expected results have been trimmed to just the standard +// syntax, since this file doesn't use any of Compass's background() calls etc. +// TODO maybe it should, since we try to support all that + +.bg-shortcut-linear-gradient { + background: #fff linear-gradient(top left, #ddd, #aaa); +} + +.bg-shortcut-radial-gradient { + background: #fff radial-gradient(center center, #ddd, #aaa 100px); +} + +.bg-linear-gradient-angle-svg { + background-image: linear-gradient(-45deg, blue, black); +} + +.bg-linear-gradient-angle2-svg { + background-image: linear-gradient(top left, blue, black); +} + +.bg-linear-gradient { + background-image: linear-gradient(top left, #ddd, #aaa); +} + +.bg-linear-gradient-pixel-stop-from-top { + background-image: linear-gradient(top, #ddd 10px, #aaa 40px); +} + +.bg-linear-gradient-pixel-stop-from-left { + background-image: linear-gradient(left, #ddd 10px, #aaa 40px); +} + +.transparent-in-linear-gradient { + background-image: #fff linear-gradient(top left, transparent, #aaa); +} + +.bg-radial-gradient { + background-image: radial-gradient(center center, #ddd, transparent 100px); +} + +.bg-linear-gradient-with-angle { + background-image: linear-gradient(-45deg, #ddd, #aaa); +} + +.bg-radial-gradient-with-angle-and-shape { + background-image: radial-gradient(ellipse cover, #ddd, #aaa 100px); +} + +.bg-all-gradient-types { + background-image: linear-gradient(top left, #ddd, #aaa); + background-image: radial-gradient(center center, #ddd, #aaa 100px); +} + +.border-image-gradient { + border-image: radial-gradient(#0f0,#f00 100px) 100 stretch; +} + +.direct-list-image-with-gradient { + list-style-image: radial-gradient(lime, red 10px); +} + +.shorthand-list-image-with-gradient { + list-style: outside radial-gradient(lime, red 10px); +} + +.content-with-gradient { + content: radial-gradient(lime, red 10px); +} + +.bg-linear-gradient-no-position { + background-image: linear-gradient(#ddd, #aaa); +} + +.bg-radial-gradient-no-position { + background-image: radial-gradient(#ddd, #aaa 100px); +} + +.cross-fade { + background-image: cross-fade(radial-gradient(#ddd, #aaa 100px), url("4x6.png")); +} diff --git a/scss/tests/files/kronuz/linear-gradient.css b/scss/tests/files/kronuz/linear-gradient.css index bfed43f..3af528b 100644 --- a/scss/tests/files/kronuz/linear-gradient.css +++ b/scss/tests/files/kronuz/linear-gradient.css @@ -1,4 +1,3 @@ div { - background: linear-gradient(top, #4d4d4d 0%, #3f3f3f 50%, #333333 50%, #252525 - 100%); + background: linear-gradient(top, #4d4d4d, #3f3f3f 50%, #333333 50%, #252525); } diff --git a/scss/tests/functions/compass/test_gradients.py b/scss/tests/functions/compass/test_gradients.py new file mode 100644 index 0000000..e555b4b --- /dev/null +++ b/scss/tests/functions/compass/test_gradients.py @@ -0,0 +1,57 @@ +"""Tests for Compass gradient generation.""" + +from scss.expression import Calculator +from scss.functions.compass.gradients import COMPASS_GRADIENTS_LIBRARY, linear_gradient +from scss.rule import Namespace +from scss.types import String, List, Number, Color + +import pytest + + +@pytest.fixture +def calc(): + ns = Namespace(functions=COMPASS_GRADIENTS_LIBRARY) + return Calculator(ns).evaluate_expression + + +def test_linear_gradient(): + # Set up some values + to = String.unquoted('to') + bottom = String.unquoted('bottom') + left = String.unquoted('left') + angle = Number(45, 'deg') + + red = Color.from_name('red') + blue = Color.from_name('blue') + + start = Number(0, "%") + middle = Number(50, "%") + end = Number(100, "%") + + assert ( + linear_gradient(left, List((red, start)), List((blue, middle))) + == String('linear-gradient(left, red, blue 50%)') + ) + + assert ( + linear_gradient(List((to, bottom)), blue, List((red, end))) + == String('linear-gradient(to bottom, blue, red)') + ) + + +@pytest.mark.xfail("rainbow still has intermediate values added") +def test_linear_gradient_idempotent(calc): + # linear-gradient should leave valid syntax alone. + # Examples graciously stolen from MDN: + # https://developer.mozilla.org/en-US/docs/Web/CSS/linear-gradient + trials = [ + 'linear-gradient(45deg, blue, red)', + 'linear-gradient(to left top, blue, red)', + 'linear-gradient(0deg, blue, green 40%, red)', + 'linear-gradient(to right, red, orange, yellow, green, blue, indigo, violet)', + 'linear-gradient(to bottom right, red, rgba(255,0,0,0))', + 'linear-gradient(to bottom, hsl(0, 80%, 70%), #bada55)', + ] + + for trial in trials: + assert calc(trial) == String(trial) |