Source: breakpoints.styl

/**
 * @namespace Breakpoints
 */



$jig---auto-breakpoint = keys($jig---breakpoint-config)[0]



/**
 * @namespace Breakpoints:get-auto-breakpoint
 */

/**
 * Returns the current auto breakpoint value.
 *
 * @memberof Breakpoints:get-auto-breakpoint
 * @function
 * @name get-auto-breakpoint
 * @alias get-auto-breakpoint
 *
 * @returns {String} the name of the current named auto breakpoint
 *
 * @see set-auto-breakpoint
 * @see reset-auto-breakpoint
 *
 * @example
 * get-auto-breakpoint()
 *   => 'medium'
 */
get-auto-breakpoint()
	return $jig---auto-breakpoint



/**
 * @namespace Breakpoints:set-auto-breakpoint
 */

/**
 * Sets the auto breakpoint to a named breakpoint value.
 * Hint: in Stylus we have to do this manually, if we want to use auto breakpoint values,
 * since blocks are always evaluated _before_ the block mixin around the block, which results
 * in the block only knowing the breakpoint before the mixin.
 *
 * @memberof Breakpoints:set-auto-breakpoint
 * @function
 * @name set-auto-breakpoint
 * @alias set-auto-breakpoint
 *
 * @param {String} $breakpoint - a named breakpoint defined in the jig config
 * @throws error if breakpoint is unknown
 *
 * @see reset-auto-breakpoint

 * @example
 * set-auto-breakpoint(medium)
 * +breakpoint(medium)
 *   ...
 */
set-auto-breakpoint($breakpoint)
	$breakpoint = to-str($breakpoint)

	if $breakpoint in $jig---breakpoint-config
		define('$jig---auto-breakpoint', $breakpoint, true)
	else
		error('jig:set-current-breakpoint | unknown named breakpoint "'+$breakpoint+'"')



/**
 * @namespace Breakpoints:reset-auto-breakpoint
 */

/**
 * Resets the auto breakpoint to the first/smallest named breakpoint defined in the jig config.
 * Hint: although you may do this manually in Stylus, this is automatically called at the end of the
 * breakpoint mixin, so usually you should be fine with set-auto-breakpoint, without resetting, if you
 * use a breakpoint directly after the call.
 *
 * @memberof Breakpoints:reset-auto-breakpoint
 * @function
 * @name reset-auto-breakpoint
 * @alias reset-auto-breakpoint
 *
 * @see set-auto-breakpoint

 * @example
 * reset-auto-breakpoint()
 */
reset-auto-breakpoint()
	define('$jig---auto-breakpoint', keys($jig---breakpoint-config)[0], true)



/**
 * @namespace Breakpoints:is-named-breakpoint
 */

/**
 * Returns if the given breakpoint is a registered named breakpoint to be found in the jig config.
 *
 * @memberof Breakpoints:is-named-breakpoint
 * @function
 * @name is-named-breakpoint
 * @alias is-named-breakpoint
 *
 * @param {String} $breakpoint - a named breakpoint defined in the jig config
 * @returns {Boolean} true if breakpoint is a registered named breakpoint name
 *
 * @example
 * is-named-breakpoint(medium)
 *   => true
 */
is-named-breakpoint($breakpoint)
	$breakpoint = to-str($breakpoint)

	return $breakpoint in $jig---breakpoint-config



/**
 * @namespace Breakpoints:build-breakpoint-range
 */

/**
 * Returns a string to be used in a media query, which defines the range/bounds of a breakpoint with
 * min and/or max value.
 *
 * @memberof Breakpoints:build-breakpoint-range
 * @function
 * @name build-breakpoint-range
 * @alias build-breakpoint-range
 *
 * @param {?Number} [$min=null] - the min width of the breakpoint
 * @param {?Number} [$max=null] - the max width of the breakpoint
 * @returns {String} the media query string for the breakpoint range
 *
 * @example
 * build-breakpoint-range(0, 767px)
 *   => '(min-width: 0) and (max-width: 767px)'
 * build-breakpoint-range(null, 100rem)
 *   => '(max-width: 100rem)'
 */
build-breakpoint-range($min=null, $max=null)
	$min-query = ($min != null) ? '(min-width: '+$min+')' : null
	$max-query = ($max != null) ? '(max-width: '+$max+')' : null

	return str-join(($min-query $max-query), ' and ')



/**
 * @namespace Breakpoints:build-breakpoint-query
 */

/**
 * Constructs a query to be used in a media query, based on a breakpoint definition.
 * Also automatically converts values to rem.
 *
 * Directions in composite definitions may be "up", "down" or "only".
 *
 * You may also define the special breakpoints "landscape" or "portrait" to cover device orientations.
 *
 * @memberof Breakpoints:build-breakpoint-query
 * @function
 * @name build-breakpoint-query
 * @alias build-breakpoint-query
 *
 * @param {?Number|Literal|List<String>} [$breakpoint-definition=0] - either a simple number or a composite definition of width and direction, where the width may either be a number or a name defined in the named breakpoints
 * @returns {String} the media query string for the breakpoint definition
 * @throws error if named breakpoint is unknown
 * @throws error if an unnamed breakpoint has an "only" direction
 *
 * @example
 * build-breakpoint-query(200rem)
 *   => '(min-width: 200rem)'
 * build-breakpoint-query(small down)
 *   => '(max-width: 199rem)'
 * build-breakpoint-query(('large' 'only'))
 *   => '(min-width: 200rem) and (max-width: 499rem)'
 * build-breakpoint-query(1024px only)
 *   => '(min-width: 64rem) and (max-width: 64rem)'
 * build-breakpoint-query(landscape)
 *   => '(orientation: landscape)'
 */
build-breakpoint-query($breakpoint-definition=0)
	$breakpoint = $breakpoint-definition[0] ? to-str($breakpoint-definition[0], $only-ident:true) : 0
	$direction = $breakpoint-definition[1] ? to-str($breakpoint-definition[1]) : 'up'
	$breakpoint-name = null
	$next-breakpoint = null
	$min = null
	$max = null
	$query-em-conversion-base = 16px // this is always 16px, no matter what is defined on <html>

	if $breakpoint == 'overwrite'
		return '(min-width: 0)'
	else if ($breakpoint == 'landscape') or ($breakpoint == 'portrait')
		return '(orientation: '+$breakpoint+')'
	else if type($breakpoint) == 'string'
		if is-named-breakpoint($breakpoint)
			$breakpoint-name = $breakpoint
			$breakpoint = $jig---breakpoint-config[$breakpoint-name]
			$next-breakpoint = hash-next($jig---breakpoint-config, $breakpoint-name)
		else
			error('jig:build-breakpoint-query | "'+$breakpoint-definition+'" is not a defined breakpoint')

	if ($breakpoint-name == null) and ($direction == 'only')
		error('jig:build-breakpoint-query | only named media queries can have an "only" range')

	// we are building media queries with em instead of rem and px
	// why? => https://zellwk.com/blog/media-query-units/

	if ($direction == 'only') or ($direction == 'up')
		$min = to-em($breakpoint, $query-em-conversion-base)

	if ($direction == 'only') or ($direction == 'down')
		if $breakpoint-name == null
			$max = to-em($breakpoint, $query-em-conversion-base)
		else if $next-breakpoint-name != null
			$max = to-em($next-breakpoint, $query-em-conversion-base) - to-em(1px, $query-em-conversion-base)

	if ($min == 0) and ($max == null)
		$min = null

	return build-breakpoint-range($min, $max)



/**
 * @namespace Breakpoints:breakpoint
 */

/**
 * Renders media queries based one one or more breakpoint definitions.
 *
 * @memberof Breakpoints:breakpoint
 * @function
 * @name breakpoint
 * @alias breakpoint
 *
 * @param {Number|Literal|List<String>|List<Literal>|List<List<String>>} $breakpoint-definitions - a list of breakpoint definitions according to build-breakpoint-query
 *
 * @see set-auto-breakpoint
 *
 * @example
 * +breakpoint(small)
 *   ...
 * +breakpoint(small down, large up)
 *   ...
 */
breakpoint($breakpoint-definitions...)
	for $breakpoint-definition in $breakpoint-definitions
		$query = build-breakpoint-query($breakpoint-definition)
		$breakpoint = $breakpoint-definition[0] ? to-str($breakpoint-definition[0], $only-ident:true) : 0
		$direction = $breakpoint-definition[1] ? to-str($breakpoint-definition[1]) : 'up'
		$breakpoint-index = index(keys($jig---breakpoint-config), $breakpoint)
		$print-breakpoint-index = index(keys($jig---breakpoint-config), $jig---print-breakpoint)

		// set current breakpoint var to mixin breakpoint value to allow for auto-evaluation inside
		if is-named-breakpoint($breakpoint)
			set-auto-breakpoint($breakpoint)

		if $query == ''
			{block}
		else
			if	($breakpoint-index != null) and (($breakpoint-index <= $print-breakpoint-index) or ($direction == 'down'))
				$media-query = s('print, screen and %s', unquote($query))
				@media $media-query
					{block}
			else
				$media-query = s('screen and %s', unquote($query))
				@media $media-query
					{block}

		// restore initial value after mixin has been rendered
		reset-auto-breakpoint()



/**
 * @namespace Breakpoints:breakpoint-value
 */

/**
 * Search for a value, defined for a breakpoint, in a given hash of values.
 * The function escalates in a mobile-first manner. So we take the value for the smallest breakpoint
 * and step up the breakpoints one by one until we reach the defined breakpoint. So, if we want the
 * according value for "large", but we only have a value for "medium", we'll get the "medium" value, which,
 * in mobile-first manner, escalates upwards and is the "large" value if nothing else is defined.
 *
 * @memberof Breakpoints:breakpoint-value
 * @function
 * @name breakpoint-value
 * @alias breakpoint-value
 *
 * @param {*|Hash} $value - a hash of breakpoint-keyed map of values, or a simple value
 * @param {Literal|String} $breakpoint - either "auto" (to use the current breakpoint) or one of the defined named breakpoints
 * @returns {*|null} the breakpoint value or null if nothing was found
 * @throws error if named breakpoint is unknown
 *
 * @example
 * breakpoint-value(
 *   {
 *     'small' : 10px,
 *     'medium' : 20px
 *   },
 *   large
 * )
 *   => 20px
 */
breakpoint-value($value, $breakpoint='auto')
	$breakpoint = to-str($breakpoint)

	if ($breakpoint != 'auto') and !($breakpoint in $jig---breakpoint-config)
		error('jig:breakpoint-value | given breakpoint "'+$breakpoint+'" not defined')

	if type($value) == 'object'
		$res = null

		if $breakpoint == 'auto'
			$breakpoint = get-auto-breakpoint()

		for $breakpoint-name, $breakpoint-definition in $jig---breakpoint-config
			$breakpoint-value = $value[$breakpoint-name]

			if $breakpoint-value != null
				$res = $breakpoint-value

			if $breakpoint-name == $breakpoint
				return $res

		return null
	else
		return $value



/**
 * @namespace Breakpoints:attributes-for-breakpoints
 */

/**
 * Renders attribute values for given attributes for defined breakpoints.
 *
 * Definitions will be rendered together if possible, minimizing the amount of media queries.
 * However, each call of this mixin will, most likely, render multiple media queries, so keep a close eye
 * on your media query structure to avoid unnecessarily doubled definitions and keep media queries to a minimum.
 * If in doubt, it might be a better idea to write the queries manually, perhaps rather using `[]` or
 * `breakpoint-value` to automatically pull values from breakpoint value hashes.
 *
 * @memberof Breakpoints:attributes-for-breakpoints
 * @function
 * @name attributes-for-breakpoints
 * @alias attributes-for-breakpoints
 *
 * @see attribute-for-breakpoints
 *
 * @param {Hash} $attributes - keys are attribute names, while values are either plain values or hashes with breakpoint name keys, providing different values per breakpoint
 * @param {Number} [$factor=null] - if a float factor is provided all values will be multiplied with this factor
 *
 * @example
 * attributes-for-breakpoints(
 *   {
 *     'font-size' : 12px,
 *     'line-height' : {
 *       'small' : 1,
 *       'large' : 1.25
 *     },
 *     'margin-top' : {
 *       'small' : 10px,
 *       'medium' : 20px
 *     }
 *   },
 *   2.0
 * )
 */
attributes-for-breakpoints($attributes, $factor=null)
	$attributes-for-breakpoints = {}
	for $attribute-name, $attribute-value in $attributes
		if type($attribute-value) != 'object'
			if $factor == null
				{$attribute-name} $attribute-value
			else
				{$attribute-name} ($factor * $attribute-value)
		else
			for $breakpoint-name, $breakpoint-definition in $jig---breakpoint-config
				$breakpoint-value = $attribute-value[$breakpoint-name]
				if ($breakpoint-value != null) or (type($breakpoint-value) == 'call')
					if !($breakpoint-name in $attributes-for-breakpoints)
						$attributes-for-breakpoints[$breakpoint-name] = {}
					$attributes-for-breakpoints[$breakpoint-name][$attribute-name] = $breakpoint-value;

	for $breakpoint-name, $breakpoint-definition in $jig---breakpoint-config
		$breakpoint-attributes = $attributes-for-breakpoints[$breakpoint-name]
		if ($breakpoint-attributes != null) and (length($breakpoint-attributes) > 0)
			+breakpoint($breakpoint-name)
				for $attribute-name, $attribute-value in $breakpoint-attributes
					if $factor == null
						{$attribute-name} $attribute-value
					else
						{$attribute-name} ($factor * $attribute-value)



/**
 * @namespace Breakpoints:attribute-for-breakpoints
 */

/**
 * Renders attribute values for given attribute for defined breakpoints.
 *
 * This is the single attribute version of `attributes-for-breakpoints`.
 * Since this version does not optimize the usage of media queries, please make sure to only use this mixin,
 * if you'll definitely only have one attribute to be defined in multiple breakpoints.
 *
 * @memberof Breakpoints:attribute-for-breakpoints
 * @function
 * @name attribute-for-breakpoints
 * @alias attribute-for-breakpoints
 *
 * @see attributes-for-breakpoints
 *
 * @param {String} $attribute - the name of the attribute you want to set
 * @param {*} $value - the value to set the attribute to
 * @param {Number} [$factor=null] - if a float factor is provided the value will be multiplied with this factor
 *
 * @example
 * attribute-for-breakpoints(
 *   'line-height',
 *   {
 *     'small' : 1,
 *     'large' : 1.25
 *   },
 *   1.0
 * )
 */
attribute-for-breakpoints($attribute, $value, $factor=null)
	$attributes = {}
	$attributes[to-str($attribute)] = $value
	attributes-for-breakpoints($attributes, $factor)



/**
 * @namespace Breakpoints:overwrite-breakpoint-for-attributes
 */

/**
 * Use this, if you need to overwrite attribute values previously defined in (a) breakpoint(s).
 *
 * A use case might be, for example, to set a font-size to a static value in an element with a responsive,
 * breakpoint-based font-size definition.
 *
 * @memberof Breakpoints:overwrite-breakpoint-for-attributes
 * @function
 * @name overwrite-breakpoint-for-attributes
 * @alias overwrite-breakpoint-for-attributes
 *
 * @param {Hash} $attributes - keys are attribute names, while values are either plain values or hashes with breakpoint name keys, providing different values per breakpoint
 * @param {Number} [$factor=null] - if a float factor is provided all values will be multiplied with this factor
 *
 * @see overwrite-breakpoint-for-attribute
 *
 * @example
 * overwrite-breakpoint-for-attributes(
 *   {
 *     'font-size' : 12px,
 *     'line-height' : 1.25
 *     'margin-top' : 20px
 *   },
 *   2.0
 * )
 */
overwrite-breakpoint-for-attributes($attributes, $factor=null)
	+breakpoint('overwrite')
		for $attribute-name, $attribute-value in $attributes
			if $factor == null
				{$attribute-name} $attribute-value
			else
				{$attribute-name} ($factor * $attribute-value)



/**
 * @namespace Breakpoints:overwrite-breakpoint-for-attribute
 */

/**
 * Use this, if you need to overwrite an attribut value previously defined in (a) breakpoint(s).
 *
 * A use case might be, for example, to set a font-size to a static value in an element with a responsive,
 * breakpoint-based font-size definition.
 *
 * @memberof Breakpoints:overwrite-breakpoint-for-attribute
 * @function
 * @name overwrite-breakpoint-for-attribute
 * @alias overwrite-breakpoint-for-attribute
 *
 * @see overwrite-breakpoint-for-attributes
 *
 * @param {String} $attribute - the name of the attribute you want to set
 * @param {*} $value - the value to set the attribute to
 * @param {Number} [$factor=null] - if a float factor is provided the value will be multiplied with this factor
 *
 * @example
 * overwrite-breakpoint-for-attribute(font-size, 12px, 2.0)
 */
overwrite-breakpoint-for-attribute($attribute, $value, $factor=null)
	$attributes = {}
	$attributes[to-str($attribute)] = $value
	overwrite-breakpoint-for-attributes($attributes, $factor)



/**
 * @namespace Breakpoints:overwrite-breakpoint
 */

/**
 * Use this, if you need to overwrite something previously defined in (a) breakpoint(s).
 *
 * A use case might be, for example, to redefine something statically in an override situation, which has
 * been defined responsively before.
 *
 * @memberof Breakpoints:overwrite-breakpoint
 * @function
 * @name overwrite-breakpoint
 * @alias overwrite-breakpoint
 *
 * @example
 * +overwrite-breakpoint()
 *   font-size 12xp
 *   margin-top 20px
 */
overwrite-breakpoint()
	+breakpoint('overwrite')
		{block}