Spinner

by oilvier

HTML

<p>
	<label for="test">Quantité</label>
	<span class="spinner">
		<button type="button" data-entry-modify="remove" data-step="1" data-bound="1" title="Retirer" class="spinner__trigger spinner__trigger--minus">
			<span class="cross cross--minus"><span class="cross__icon"></span></span>
			<span class="hidden">-</span>
		</button>
		<button type="button" data-entry-modify="add" data-step="1" data-bound="-1" title="Ajouter" class="spinner__trigger">
			<span class="cross"><span class="cross__icon"></span></span>
			<span class="hidden">+</span>
		</button>
		<input type="text" pattern="\d*" name="test" id="test" value="1" class="spinner__input cart-table__quantity" data-entry="quantity">
		<i class="spinner__focusable"></i>
	</span>
</p>

SCSS

$base-font-size:16px;
$body-font-size:$base-font-size;

/// Taille de l'icone croix     
/// @type Number (unit)
$cross-size:30px!default;

///  
/// Transformer une valeur en pixels en rem  
/// 
/// Utilise la variable `$base-font-size` comme taille de référence pour
/// la conversion
/// 
/// @param {number} $value - Valeur en pixel
/// 
/// @require $base-font-size
///
/// @example scss - Usage
///   .foo {
///     font-size: rem(15px); 
///     width: rem(200px); 
///     padding: rem(5px);
///   }
/// 
/// @example css - Result
///   .foo {
///     font-size: 0.9375rem; 
///     width: 12.5rem; 
///     padding: 0.3125rem;
///   }
///  
@function rem($value, $base: $base-font-size) {
	@return $value / $base * 1rem;
}


///  
/// Transformer une valeur en pixels en em  
/// 
/// Utilise la variable `$body-font-size` comme taille de référence pour
/// la conversion
/// 
/// @param {number} $value - Valeur en pixel
/// 
/// @require $base-font-size
///
/// @example scss - Usage
///   .foo {
///     font-size: em(12px); 
///     width: em(200px, 12px); 
///     padding: em(5px, 12px);
///   }
/// 
/// @example css - Result
///   .foo {
///     font-size: 0.750em; 
///     width: 16.667em; 
///     padding: 0.417em;
///   }
/// 
@function em($px, $base: $body-font-size) {
    @return ($px / $base) * 1em;
}

*, 
*:before, 
*:after {box-sizing: border-box;}


/* ==========================================================================
   ## Croix
   ========================================================================== */
/**
 * Conteneur pour la croix
 *
<span class="cross">
	<span class="cross__icon"></span>
</span>
 *
 */
.cross {display:inline-block; width:1em; height:1em; font-size:rem($cross-size); line-height:1; text-align:left; vertical-align:middle; box-sizing:content-box; user-select:none; transition:all 0.1s ease-in;}

	/**
	 * Icône de la croix en CSS
	 * Les branches de la croix sont réalisées avec des pseudo-éléments
	 * On utilise la bordure...

JavaScript

// Au clic d'un bouton de modification des quantités
$("[data-entry-modify]").on("click", function() {
	var $this		= $(this);
	var step		= parseInt($this.data("step"));
	var bound		= parseInt($this.data("bound"));
	var type		= $this.data("entry-modify");
	var $quantity	= $("[data-entry=quantity]");
	var quantity	= parseInt($quantity.val());

	// Vérification des bornes
	if (
		("add" === type && -1 !== bound && bound < (quantity + step)) ||
		("remove" === type && bound > (quantity - step))
	) {
		return false;
	}

	// Calcul de la nouvelle quantité
	quantity = ("add" === type) ? (quantity + step) : (quantity - step);

	// Affichage de la nouvelle quantité de la ligne
	$quantity.val(quantity);

	$quantity.change();

	return false;
});