Skip to content

Commit

Permalink
Merge pull request #3 from slang800/gradients
Browse files Browse the repository at this point in the history
Gradients
  • Loading branch information
notslang committed Jul 31, 2013
2 parents ac9913f + ac88469 commit ab02a97
Show file tree
Hide file tree
Showing 13 changed files with 392 additions and 174 deletions.
4 changes: 4 additions & 0 deletions lib/nib.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ try {
// ignore
}

var vendorHelpers = require('./nodes/vendor-helpers')

/**
* Library version.
*/
Expand Down Expand Up @@ -64,5 +66,7 @@ function plugin() {
} else {
style.define('has-canvas', nodes.false);
}

style.define('normalize', vendorHelpers);
}
}
61 changes: 11 additions & 50 deletions lib/nib/gradients.styl
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,6 @@ replace(expr, str, val)
expr[i] = val
expr

/*
* Normalize gradient points.
*/

grad-point(pos)
if length(pos) == 1
return left pos if pos in (top bottom)
return pos top if pos in (left right)
else if pos[0] in (top bottom)
pos[1] pos[0]
else
pos

/*
* Implicit color stop position.
*/
Expand Down Expand Up @@ -76,13 +63,6 @@ join-stops(stops, translate)
str += translate(color, pos)
unquote(str)

/*
* Legacy Webkit color stop.
*/

webkit-stop(color, pos)
'color-stop(%d, %s)' % (pos / 100 color)

/*
* Standard color stop.
*/
Expand All @@ -105,36 +85,17 @@ std-stop(color, pos)

linear-gradient(start, stops...)
error('color stops required') unless length(stops)
prop = current-property[0]
val = current-property[1]

if start is a 'color'
unshift(stops, start)
start = top

stops = normalize-stops(stops)

// gradient image
if start[0] is a 'unit'
if has-canvas
img = linear-gradient-image(start, stops)
add-property(prop, replace(val, '__CALL__', img))
start = start[1]

// legacy webkit
end = grad-point(opposite-position(start))
webkit-legacy = '-webkit-gradient(linear, %s, %s, %s)' % (grad-point(start) end join-stops(stops, webkit-stop))
add-property(prop, replace(val, '__CALL__', webkit-legacy))

// vendor prefixed
stops = join-stops(stops, std-stop)
for prefix in vendor-prefixes
unless prefix == official
gradient = '-%s-linear-gradient(%s, %s)' % (prefix start stops)
add-property(prop, replace(val, '__CALL__', gradient))

// standard
'linear-gradient(%s, %s)' % (start stops)
// if current-property
// if start is a 'color'
// unshift(stops, start)
// start = top
// if start[0] is a 'unit'
// if has-canvas
// img = linear-gradient-image(start, stops)
// add-property(prop, replace(val, '__CALL__', img))
// start = start[1]

unquote('linear-gradient(' + join(', ',arguments) + ')')

/*
* Create a linear gradient image with the given start position
Expand Down
115 changes: 47 additions & 68 deletions lib/nib/vendor.styl
Original file line number Diff line number Diff line change
Expand Up @@ -6,84 +6,29 @@

no-wrap = unquote('nowrap')

/*
* Helper to find out is the list of arguments have commas
*/

is-comma-list()
return match('\), \(', ''+arguments)

/*
* Helper to find out if a given value is a width
*/

is-width(val)
if auto == val
return true
else if val && 'unit' == type(val)
// Stylus does not short circuit so we need to perform this as a distinct
// operation to prevent errors
return '' != unit(val)
return false

/*
* Literal joining
*/

literal-join(string, literals)
result = unquote('')
first = true
for args in literals
subresult = unquote('')
for arg in args
subresult = subresult arg
if first
result = subresult
first = false
else
result = s('%s%s%s', result, unquote(string), subresult)
return result

/*
* Replacing one value with another
*/

replace-args(args,argument,val)
result = ()
// Checking if there are values divided by comma
if is-comma-list(args)
for subargs in args
subresult = ()
for arg in subargs
arg = unquote(val) if arg == argument
push(subresult, arg)
subresult = literal-join(' ', subresult) if length(subresult) > 1
push(result, subresult)
result = literal-join(', ', result)
else
for arg in args
arg = unquote(val) if arg == argument
push(result, arg)
return result

/*
* Vendor support for the given prop / arguments,
* optionally specifying the only prefixes to utilize,
* or those which should be ignored.
*/

vendor(prop, args, only = null, ignore = null)
vendor(prop, args, only = null, ignore = null, vendor-property = true)
need_normalize = !vendor-property or prop in ('transition' 'transition-property' 'border-image' 'border-image-slice')
for prefix in vendor-prefixes
unless (only and !(prefix in only)) or (ignore and prefix in ignore)
if official == prefix
{prop}: args
if need_normalize
{prop}: normalize(prop,('%s' % args))
else
{prop}: args
else
newargs = args
// Adjusting the args if needed
if prop in ('transition' 'transition-property')
newargs = replace-args(args, transform, '-' + prefix + '-transform')
{'-' + prefix + '-' + prop}: newargs
newprop = prop
newprop = '-' + prefix + '-' + prop if vendor-property

if need_normalize
{newprop}: normalize(prop,('%s' % args),prefix)
else
{newprop}: args
/*
* Vendorize the given value.
*/
Expand Down Expand Up @@ -578,4 +523,38 @@ placeholder()
pair()
else if pair is not null && pair[0] is not null
{pair[0]}: type(pair[1]) == 'string' ? s(pair[1]) : pair[1]
input-placeholder = placeholder
input-placeholder = placeholder

/*
* Vendor background support (gradients).
*/

background()
if match('-gradient\(', ''+arguments)
vendor('background', arguments, vendor-property: false)
else
background arguments

background-image()
if match('-gradient\(', ''+arguments)
vendor('background-image', arguments, vendor-property: false)
else
background-image arguments

cursor()
if match('-gradient\(', ''+arguments)
vendor('cursor', arguments, vendor-property: false)
else
cursor arguments

list-style()
if match('-gradient\(', ''+arguments)
vendor('list-style', arguments, vendor-property: false)
else
list-style arguments

list-style-image()
if match('-gradient\(', ''+arguments)
vendor('list-style-image', arguments, vendor-property: false)
else
list-style-image arguments
75 changes: 75 additions & 0 deletions lib/nodes/vendor-helpers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@

/**
* Module dependencies.
*/

var stylus = require('stylus')
, nodes = stylus.nodes;

var RE_GRADIENT_STOPS = /([\(\,]\s*)(-?(?:\d*\.)?\d+(?:%|px|em))(\s+)((hsl|rgb)a?\([^\)]+\)|#[^\)\,]+)/g
, RE_GRADIENT_VAL = /(\(\s*)(?:(-?(\d*\.)?\d+)deg|((to )?(top|bottom|left|right)( (top|bottom|left|right))?))/g
, RE_GRADIENT_TYPE = /((repeating-)?(linear|radial)-gradient\()/g
, RE_TRANSFORM = /\b(transform)\b/g
, RE_FILL_KEYWORD = /\s*\b(fill)\b\s*/g;

var DIRECTIONS = { top: 'bottom', bottom: 'top', left: 'right', right:'left' };

/**
* Expose `normalize`.
*/

exports = module.exports = normalize;

function normalize(property, value, prefix){
var result = value.toString()
, args;

/* Fixing the gradients */
if (~result.indexOf('gradient(')) {

/* Normalize color stops */
result = result.replace(RE_GRADIENT_STOPS,'$1$4$3$2');

/* Normalize legacy gradients */
result = result.replace(RE_GRADIENT_VAL, function(){
args = [].slice.call(arguments, 1);
return normalizeGradient(args, prefix);
});

/* Adding prefixes to the legacy gradients */
if (prefix) result = result.replace(RE_GRADIENT_TYPE, '-' + prefix + '-$1');
}

/* Adding prefixes to the `transform` values of legacy `transition` property */
if (prefix && (property == "'transition'" || property == "'transition-property'")) {
result = result.replace(RE_TRANSFORM, '-' + prefix + '-$1');
}

/* Removing `fill` keyword from the legacy `border-image` property */
if (prefix && (property == "'border-image'" || property == "'border-image-slice'")) {
result = result.replace(RE_FILL_KEYWORD, ' ');
}

return new nodes.Ident(result);
}

function normalizeGradient(parts, prefix){
/* Fix the degrees to the legacy syntax */
var val = parts[0];
if (parts[1]) val += (prefix ? parseFloat((Math.abs(450 - parts[1]) % 360).toFixed(3)) : parts[1]) + 'deg';

/* Fix the directions to the legacy syntax */
if (prefix && parts[4]) {
// `to top` to `bottom` etc.
if (parts[5]) val += DIRECTIONS[parts[5]];
if (parts[6]) val += ' ' + DIRECTIONS[parts[7]];
} else if (!prefix && !parts[4]) {
// `top` to `to bottom` etc.
if (parts[5]) val += 'to ' + DIRECTIONS[parts[5]];
if (parts[6]) val += ' ' + DIRECTIONS[parts[7]];
} else {
if (parts[3]) val += parts[3];
}

return val;
}
Loading

0 comments on commit ab02a97

Please sign in to comment.