├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── _.scss ├── lib ├── _.scss ├── _init.scss ├── constants │ ├── _.scss │ ├── _init.scss │ ├── const.scss │ └── define.scss ├── functions │ ├── _.scss │ ├── class-escape.scss │ ├── class-sanitize.scss │ ├── class-template.scss │ ├── em.scss │ ├── get-function-safe.scss │ ├── important.scss │ ├── is-null.scss │ ├── list-append.scss │ ├── list-contains.scss │ ├── list-each.scss │ ├── list-every.scss │ ├── list-prepend.scss │ ├── list-remove.scss │ ├── list-replace.scss │ ├── list-reverse.scss │ ├── list-sort.scss │ ├── list-unique.scss │ ├── map-append.scss │ ├── map-each-key.scss │ ├── map-each-value.scss │ ├── map-flatten.scss │ ├── map-get-key.scss │ ├── map-prepend.scss │ ├── map-stringify-keys-deep.scss │ ├── map-stringify-keys.scss │ ├── map-unique.scss │ ├── random-color.scss │ ├── rem.scss │ ├── str-append.scss │ ├── str-compare.scss │ ├── str-contains.scss │ ├── str-escape.scss │ ├── str-prepend.scss │ ├── str-remove.scss │ ├── str-replace.scss │ ├── throw.scss │ ├── to-length.scss │ ├── to-negative.scss │ ├── to-number.scss │ ├── to-string.scss │ ├── type-check.scss │ ├── unit-convert.scss │ └── unit-strip.scss ├── mixins │ ├── _.scss │ ├── css-ruleset.scss │ ├── extends.scss │ ├── important.scss │ ├── query.scss │ ├── responsive.scss │ └── type-scale.scss ├── options │ ├── _.scss │ ├── _init.scss │ ├── option.scss │ └── set-option.scss └── tokens │ ├── _.scss │ ├── _init.scss │ ├── get.scss │ ├── helpers │ ├── _.scss │ ├── angle.scss │ ├── background-image.scss │ ├── baseline.scss │ ├── border-radius.scss │ ├── box-shadow.scss │ ├── breakpoint.scss │ ├── color.scss │ ├── coordinate.scss │ ├── duration.scss │ ├── easing.scss │ ├── flex-grid.scss │ ├── font-family.scss │ ├── font-size.scss │ ├── font-weight.scss │ ├── gradient.scss │ ├── keyframe.scss │ ├── letter-spacing.scss │ ├── line-height.scss │ ├── line-style.scss │ ├── line-width.scss │ ├── module.scss │ ├── opacity.scss │ ├── ratio.scss │ ├── spacing.scss │ ├── text-measure.scss │ ├── text-shadow.scss │ └── wrapper-width.scss │ ├── set-default.scss │ ├── set.scss │ └── unset.scss ├── package.json ├── sache.json ├── sassdoc.yaml ├── scarab-logo.svg ├── test ├── constants │ ├── _.scss │ ├── const.scss │ └── define.scss ├── functions │ ├── _.scss │ ├── class-escape.scss │ ├── class-sanitize.scss │ ├── class-template.scss │ ├── em.scss │ ├── get-function-safe.scss │ ├── important.scss │ ├── is-null.scss │ ├── list-append.scss │ ├── list-contains.scss │ ├── list-each.scss │ ├── list-every.scss │ ├── list-prepend.scss │ ├── list-remove.scss │ ├── list-replace.scss │ ├── list-reverse.scss │ ├── list-sort.scss │ ├── list-unique.scss │ ├── map-append.scss │ ├── map-each-key.scss │ ├── map-each-value.scss │ ├── map-flatten.scss │ ├── map-get-key.scss │ ├── map-prepend.scss │ ├── map-stringify-keys-deep.scss │ ├── map-stringify-keys.scss │ ├── map-unique.scss │ ├── random-color.scss │ ├── rem.scss │ ├── str-append.scss │ ├── str-compare.scss │ ├── str-contains.scss │ ├── str-escape.scss │ ├── str-prepend.scss │ ├── str-remove.scss │ ├── str-replace.scss │ ├── throw.scss │ ├── to-length.scss │ ├── to-negative.scss │ ├── to-number.scss │ ├── to-string.scss │ ├── type-check.scss │ ├── unit-convert.scss │ └── unit-strip.scss ├── mixins │ ├── _.scss │ ├── css-ruleset.scss │ ├── extends.scss │ ├── important.scss │ ├── query.scss │ ├── responsive.scss │ └── type-scale.scss ├── options │ ├── _.scss │ ├── option.scss │ └── set-option.scss ├── test_sass.js ├── tests.scss └── tokens │ ├── _.scss │ ├── get.scss │ ├── helpers │ ├── _.scss │ ├── angle.scss │ ├── background-image.scss │ ├── baseline.scss │ ├── border-radius.scss │ ├── box-shadow.scss │ ├── breakpoint.scss │ ├── color.scss │ ├── coordinate.scss │ ├── duration.scss │ ├── easing.scss │ ├── flex-grid.scss │ ├── font-family.scss │ ├── font-size.scss │ ├── font-weight.scss │ ├── gradient.scss │ ├── keyframe.scss │ ├── letter-spacing.scss │ ├── line-height.scss │ ├── line-style.scss │ ├── line-width.scss │ ├── module.scss │ ├── opacity.scss │ ├── ratio.scss │ ├── spacing.scss │ ├── text-measure.scss │ ├── text-shadow.scss │ └── wrapper-width.scss │ ├── set-default.scss │ ├── set.scss │ └── unset.scss └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | node_modules/ 3 | sassdoc/ 4 | 5 | .DS_Store 6 | .sass-cache 7 | *.css.map 8 | 9 | *.log 10 | pids 11 | *.pid 12 | *.seed 13 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | 3 | node_js: 4 | - 'node' 5 | - 'lts/*' 6 | 7 | install: 8 | - npm install 9 | 10 | script: 11 | - npm test 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2018, Kyle Oliveiro 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | * Neither the name of Scarab nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 |

Scarab Core

4 | Sass library for rapid stylesheet development 5 | 6 | Design token management · Responsive mixins · Helper functions 7 | 8 | [![npm-beta](https://img.shields.io/npm/v/@scarab/core.svg)](https://www.npmjs.com/package/@scarab/core) 9 | [![Build Status](https://travis-ci.org/kyleoliveiro/scarab-core.svg)](https://travis-ci.org/kyleoliveiro/scarab-core) 10 | 11 | --- 12 | 13 | [💿 Installation](#installation) · [📚 Documentation](#documentation) · [⭐️ Features](#features) · [🍃 Ecosystem](#ecosystem) 14 |
15 | [🎉 Motivation](#motivation) · [❤️ Contributing](#contributing) · [📃️ License](#license) 16 |
17 | 18 | --- 19 | 20 | ## 💿 Installation 21 | 1. Install Scarab Core as a dev-dependency: 22 | 23 | ```bash 24 | # With yarn 25 | $ yarn add @scarab/core -D 26 | 27 | # Or with npm 28 | $ npm install @scarab/core --save-dev 29 | ``` 30 | 31 | 2. Add `node_modules/` to your Sass [`includePaths`](https://github.com/sass/node-sass#includepaths). 32 | 33 | 3. Import the Scarab Core library before all other stylesheets: 34 | 35 | ```scss 36 | // Import the Scarab Library 37 | @import '@scarab/core/_'; 38 | 39 | // Write your Sass here... 40 | ``` 41 | 42 | 43 | ## 📚 Documentation 44 | API documentation and guides:
45 | [**https://scarab.style/core**](https://scarab.style/core) 46 | 47 | ## ⭐️ Features 48 | 49 | ### Design token management 50 | 51 | Design systems consist of reusable “tokens”. Each token has a name and a value associated with it. Constructing digital interfaces using only the values of tokens that are defined in a design system ensures visual consistency. Scarab provides a simple interface for managing design tokens. 52 | 53 | ### Helper functions 54 | Provides additional syntactic sugar on top of the default Sass functions. 55 | 56 | 57 | ### Responsive mixins 58 | Simplifies working with breakpoints and media queries. 59 | 60 | ## 🍃 Ecosystem 61 | 62 | In addition to the core library, the following packages are available in the Scarab ecosystem: 63 | 64 | | Package name | Description | 65 | | :-- | :-- | 66 | | [**Carapace**](https://github.com/kyleoliveiro/scarab-carapace.git) | CSS utility class generator | 67 | | [**Scarab CLI** (WIP)](https://github.com/kyleoliveiro/scarab-cli.git) | Command-line tools for the Scarab ecosystem | 68 | | [**Scarab snippets** (WIP)](https://github.com/kyleoliveiro/scarab-snippets.git) | Scarab snippets for your favorite text editors and IDE's | 69 | 70 | ## 🎉 Motivation 71 | 72 | ### Why another Sass library? 73 | Scarab is the resulting by-product of years of web development work. It's designed and built as a library to manage design tokens and to provide additional syntactic sugar for writing stylesheets. 74 | 75 | ### Why use Scarab? 76 | 77 | - Define design tokens in Sass (ideal since it's a styling language) 78 | - Use tokens in Sass with Scarab, and in HTML with Carapace 79 | - Ability to export design tokens from Sass to JSON 80 | - Written in Sass; No additional dependencies 81 | - Well tested with 100+ unit tests 82 | - Ecosystem of related packages 83 | 84 | ### Why not just use Sass variables? 85 | Using Sass variables to manage design tokens can be a viable solution for small projects. However, this approach has its limitations. For instance, in Sass, it's not possible to dynamically reference a variable by name. On the other hand, this becomes possible if tokens are stored in a Sass map instead of variables. This opens up many possibilities, and is the main impetus behind the Scarab library. 86 | 87 | ### Alternative libraries 88 | Other options are available, and you should pick one that caters to your project's requirements. 89 | 90 | - [Tailwind](https://tailwindcss.com/) — Generates CSS utility classes with short compile time. Requires PostCSS or Tailwind CLI. 91 | - [Tachyons](https://tachyons.io/) — Good for smaller sites that use native CSS variables (a.k.a. custom properties). 92 | - [BassCSS](http://basscss.com/) — Alternative to Tachyons. Also uses CSS variables. 93 | - [Vue DS](https://vueds.com) — Full-featured design system framework for Vue. 94 | 95 | ### ❤️ Contributing 96 | Issues and feature requests and PR's are welcome! 97 | 98 | ### 📃️ License 99 | Licensed under BSD 3-Clause. Copyright © Kyle Oliveiro 2018. 100 | -------------------------------------------------------------------------------- /_.scss: -------------------------------------------------------------------------------- 1 | //// 2 | /// Scarab 3 | /// Stylesheet tokens management and useful functions for Sass. 4 | /// 5 | /// @author Kyle Oliveiro 6 | //// 7 | 8 | // Import the Scarab library 9 | @import 'lib/_'; 10 | -------------------------------------------------------------------------------- /lib/_.scss: -------------------------------------------------------------------------------- 1 | @import '_init'; 2 | 3 | @import 'functions/_'; 4 | @import 'mixins/_'; 5 | @import 'options/_'; 6 | @import 'constants/_'; 7 | @import 'tokens/_'; 8 | -------------------------------------------------------------------------------- /lib/_init.scss: -------------------------------------------------------------------------------- 1 | /// Global variable where all user configuration is stored. 2 | /// 3 | /// Never modify this variable or its children directly. Instead, use: 4 | /// - `set-option()` / `option()` to manage options 5 | /// - `define()` / `const()` to manage constants 6 | /// - `set()` / `get()` to manage the tokens 7 | /// 8 | /// @access private 9 | /// @group 0_variables 10 | /// 11 | /// @type Map 12 | /// @prop {Map} OPTIONS - Contains Scarab options 13 | /// @prop {Map} CONSTANTS - Contains constant values 14 | /// @prop {Map} TOKENS - Contains the stylesheet tokens 15 | 16 | $__SCARAB: ( 17 | 'CONSTANTS' : (), 18 | 'TOKENS' : (), 19 | 'OPTIONS' : () 20 | ); 21 | -------------------------------------------------------------------------------- /lib/constants/_.scss: -------------------------------------------------------------------------------- 1 | //// 2 | /// Constants 3 | /// 4 | /// Helpers for managing constants. 5 | //// 6 | 7 | @import '_init'; 8 | 9 | @import 'define'; 10 | @import 'const'; 11 | -------------------------------------------------------------------------------- /lib/constants/const.scss: -------------------------------------------------------------------------------- 1 | /// Returns a value from the `CONSTANTS` map. 2 | /// 3 | /// @group 2_constants 4 | /// 5 | /// @requires {variable} __SCARAB 6 | /// @requires {function} to-string 7 | /// 8 | /// @param {ArgList} $path - Path to the key to retrieve the value from 9 | /// 10 | /// @return {*} - Value from the `CONSTANTS` map 11 | /// 12 | /// @example 13 | /// @debug const(MATH, LOG2E); 14 | /// // => 1.4426950408889634 15 | /// 16 | /// @debug const(CSS, MAX_Z_INDEX); 17 | /// // => 2147483647 18 | /// 19 | /// @debug const(INTERVAL, AUGMENTED_FOURTH); 20 | /// // => 1.414 21 | 22 | @function const($path...) { 23 | $result: map-get($__SCARAB, 'CONSTANTS'); 24 | 25 | @each $key in $path { 26 | $result : map-get($result, to-string($key)); 27 | } 28 | 29 | @return $result; 30 | } 31 | -------------------------------------------------------------------------------- /lib/constants/define.scss: -------------------------------------------------------------------------------- 1 | /// Defines a new constant. 2 | /// 3 | /// Constants that already exist may not be re-defined. 4 | /// 5 | /// @group 2_constants 6 | /// 7 | /// @requires {variable} __SCARAB 8 | /// @requires {function} to-string 9 | /// @requires {function} map-stringify-keys-deep 10 | /// 11 | /// @param {ArgList} $definition - Definition of the new constant 12 | /// 13 | /// @return {ArgList} - Definition of the new constant 14 | /// 15 | /// @example 16 | /// $_: define(COMPANY, NAME, 'Acme Inc'); 17 | /// 18 | /// @debug const(COMPANY, NAME); 19 | /// // => 'Acme Inc' 20 | 21 | @function define($definition...) { 22 | // Get a copy of the current $CONSTANTS state 23 | $CONSTANTS: map-get($__SCARAB, 'CONSTANTS'); 24 | 25 | $result: (); // key-value pair that will be merged with $CONSTANTS 26 | 27 | // If there are only 2 args, we can easily determine the result 28 | @if length($definition) == 2 { 29 | $key : nth($definition, 1); 30 | $new-value : nth($definition, 2); 31 | 32 | // Check that the constant does not already exist 33 | @if not map-has-key($CONSTANTS, to-string($key)) { 34 | $result: ($key: $new-value); 35 | } 36 | } 37 | 38 | // For more than 2 args, we have to build the result backwards 39 | @if length($definition) > 2 { 40 | 41 | // The new value is the last arg in $definition 42 | $new-value: nth($definition, -1); 43 | 44 | // Build a list of maps preceding the new one 45 | $maps: ($CONSTANTS,); 46 | 47 | @for $i from 1 through length($definition) - 2 { 48 | $current-key : nth($definition, $i); 49 | $current-map : nth($maps, -1); 50 | $current-value : map-get($current-map, to-string($current-key)) or (); 51 | 52 | $maps: append($maps, $current-value); 53 | } 54 | 55 | @for $i from length($maps) through 1 { 56 | $current-map : nth($maps, $i); 57 | $current-key : nth($definition, $i); 58 | $current-value : map-get($current-map, to-string($current-key)); 59 | 60 | @if $i == length($maps) { 61 | // Check that the constant does not already exist 62 | @if not map-has-key($current-map, to-string($current-key)) { 63 | $current-value: $new-value; 64 | } 65 | } @else { 66 | $current-value: $result; 67 | } 68 | 69 | $result: map-merge($current-map, (to-string($current-key): $current-value)); 70 | } 71 | } 72 | 73 | // Update the local $CONSTANTS map 74 | $CONSTANTS: map-merge($CONSTANTS, map-stringify-keys-deep($result)); 75 | 76 | // Merge the updated $CONSTANTS map back into $__SCARAB 77 | $__SCARAB: map-merge($__SCARAB, ('CONSTANTS': $CONSTANTS)) !global; 78 | @return $definition; 79 | } 80 | 81 | 82 | 83 | /// Calls `@function define()`. 84 | /// 85 | /// @group 2_constants 86 | /// 87 | /// @requires {function} define 88 | /// 89 | /// @param {ArgList} $args - Args for `define` 90 | /// 91 | /// @example 92 | /// @include define(COMPANY, NAME, 'Acme Inc'); 93 | /// 94 | /// @debug const(COMPANY, NAME); 95 | /// // => 'Acme Inc' 96 | 97 | @mixin define($definition...) { 98 | $_: define($definition...); 99 | } 100 | -------------------------------------------------------------------------------- /lib/functions/_.scss: -------------------------------------------------------------------------------- 1 | //// 2 | /// Functions 3 | /// 4 | /// Helper functions. 5 | //// 6 | 7 | @import 'throw'; 8 | @import 'type-check'; 9 | @import 'get-function-safe'; 10 | @import 'important'; 11 | @import 'is-null'; 12 | @import 'to-string'; 13 | @import 'to-length'; 14 | @import 'to-number'; 15 | @import 'to-negative'; 16 | @import 'unit-strip'; 17 | @import 'unit-convert'; 18 | @import 'class-escape'; 19 | @import 'class-sanitize'; 20 | @import 'class-template'; 21 | @import 'random-color'; 22 | @import 'em'; 23 | @import 'rem'; 24 | @import 'str-compare'; 25 | @import 'str-contains'; 26 | @import 'str-replace'; 27 | @import 'str-remove'; 28 | @import 'str-escape'; 29 | @import 'str-prepend'; 30 | @import 'str-append'; 31 | @import 'list-append'; 32 | @import 'list-contains'; 33 | @import 'list-each'; 34 | @import 'list-prepend'; 35 | @import 'list-remove'; 36 | @import 'list-replace'; 37 | @import 'list-reverse'; 38 | @import 'list-sort'; 39 | @import 'list-unique'; 40 | @import 'list-every'; 41 | @import 'map-append'; 42 | @import 'map-prepend'; 43 | @import 'map-get-key'; 44 | @import 'map-flatten'; 45 | @import 'map-stringify-keys'; 46 | @import 'map-stringify-keys-deep'; 47 | @import 'map-unique'; 48 | @import 'map-each-key'; 49 | @import 'map-each-value'; 50 | -------------------------------------------------------------------------------- /lib/functions/class-escape.scss: -------------------------------------------------------------------------------- 1 | /// Escapes a string for use as a CSS class name. 2 | /// 3 | /// @group 5_functions 4 | /// 5 | /// @requires {function} const 6 | /// @requires {function} str-remove 7 | /// @requires {function} str-escape 8 | /// @requires {function} str-prepend 9 | /// @requires {function} list-contains 10 | /// 11 | /// @link https://mathiasbynens.be/notes/css-escapes Notes on CSS escapes 12 | /// 13 | /// @param {String} $class-name - The class name to escape 14 | /// 15 | /// @return {String} - Escaped string 16 | /// 17 | /// @example 18 | /// class-escape('blue') 19 | /// // => 'blue' 20 | /// 21 | /// class-escape('13lue') 22 | /// // => '\31 3lue' 23 | /// 24 | /// class-escape('@cl@ss:(1)') 25 | /// // => '\@cl\@ss\3A \(1\)' 26 | 27 | @function class-escape($class-name) { 28 | $result: $class-name; 29 | $first-char: str-slice($class-name, 1, 1); 30 | 31 | // Remove whitespace 32 | $result: str-remove($result, ' ', true); 33 | 34 | // Escape special characters 35 | $result: str-escape($result); 36 | 37 | // Unicode-escape the first character if it's a number 38 | @if list-contains(const(CHARSPACE, DECIMAL), $first-char) { 39 | $result: str-slice($result, 2); // Remove the first character 40 | $result: str-prepend($result, ' ', $first-char, '\\3'); 41 | } 42 | 43 | @return $result; 44 | } 45 | -------------------------------------------------------------------------------- /lib/functions/class-sanitize.scss: -------------------------------------------------------------------------------- 1 | /// Removes `selector-format` placeholders from a string. 2 | /// 3 | /// @group 5_functions 4 | /// 5 | /// @requires {function} const 6 | /// @requires {function} str-remove 7 | /// 8 | /// @param {String} $class-name - Class name to sanitize 9 | /// 10 | /// @return {String} - Sanitized, unescaped class name 11 | /// 12 | /// @example 13 | /// class-sanitize('{{b}}{{bp}}{{s}}{{sp}}{{rp}}opacity{{rs}}{{vp}}{{v}}--75{{ms}}{{ss}}{{bs}}') 14 | /// // => 'opacity--75' 15 | 16 | @function class-sanitize($class-name) { 17 | $result: $class-name; 18 | 19 | $illegal-strings: const(SCARAB, SELECTOR_FORMAT_PLACEHOLDERS); 20 | @each $string in $illegal-strings { 21 | $result: str-remove($result, $string); 22 | } 23 | 24 | @return $result; 25 | } 26 | -------------------------------------------------------------------------------- /lib/functions/class-template.scss: -------------------------------------------------------------------------------- 1 | /// Returns the result of hydrating the `selector-format` with given values. 2 | /// 3 | /// @group 5_functions 4 | /// 5 | /// @requires {function} option 6 | /// @requires {function} module 7 | /// @requires {function} is-null 8 | /// @requires {function} str-remove 9 | /// @requires {function} str-replace 10 | /// 11 | /// @param {String|Map} $module - Module name, or map containing a `root` key, and optional `prefix` and `suffix` overrides. 12 | /// @param {String} $variant [''] - Class variant 13 | /// @param {String} $modifier [''] - Class modifier 14 | /// 15 | /// @return {String} - Templated, unescaped CSS class name 16 | /// 17 | /// @example 18 | /// class-template(( 19 | /// root: 'margin' 20 | /// ), top, 0) 21 | /// // => 'margin-top:0' 22 | /// 23 | /// class-template(( 24 | /// root: 'padding', 25 | /// variant-prefix: '', 26 | /// modifier-prefix: '--' 27 | /// ), top, 0) 28 | /// // => 'paddingtop--0' 29 | 30 | @function class-template($module, $variant: '', $modifier: '') { 31 | @if type-of($module) == 'string' { 32 | $module: module($module); 33 | } 34 | 35 | $variant: to-string($variant); 36 | $modifier: to-string($modifier); 37 | 38 | // Get module options 39 | $root: map-get($module, 'root'); 40 | 41 | $selector-format : if(map-has-key($module, 'selector-format'), 42 | map-get($module, 'selector-format'), 43 | option(namescheme, selector-format) 44 | ); 45 | 46 | $root-prefix : if(map-has-key($module, 'root-prefix'), 47 | map-get($module, 'root-prefix'), 48 | option(namescheme, root-prefix) 49 | ); 50 | 51 | $root-suffix : if(map-has-key($module, 'root-suffix'), 52 | map-get($module, 'root-suffix'), 53 | option(namescheme, root-suffix) 54 | ); 55 | 56 | $variant-prefix : if(map-has-key($module, 'variant-prefix'), 57 | map-get($module, 'variant-prefix'), 58 | option(namescheme, variant-prefix) 59 | ); 60 | 61 | $variant-suffix : if(map-has-key($module, 'variant-suffix'), 62 | map-get($module, 'variant-suffix'), 63 | option(namescheme, variant-suffix) 64 | ); 65 | 66 | $modifier-prefix : if(map-has-key($module, 'modifier-prefix'), 67 | map-get($module, 'modifier-prefix'), 68 | option(namescheme, modifier-prefix) 69 | ); 70 | 71 | $modifier-suffix : if(map-has-key($module, 'modifier-suffix'), 72 | map-get($module, 'modifier-suffix'), 73 | option(namescheme, modifier-suffix) 74 | ); 75 | 76 | $result: $selector-format; 77 | $template-schema: ( 78 | 'r': ( 79 | 'value' : $root, 80 | 'prefix' : $root-prefix, 81 | 'suffix' : $root-suffix 82 | ), 83 | 'v': ( 84 | 'value' : $variant, 85 | 'prefix' : $variant-prefix, 86 | 'suffix' : $variant-suffix 87 | ), 88 | 'm': ( 89 | 'value' : $modifier, 90 | 'prefix' : $modifier-prefix, 91 | 'suffix' : $modifier-suffix 92 | ) 93 | ); 94 | 95 | // Replace template placeholders with actual values 96 | @each $key, $map in $template-schema { 97 | $value : map-get($map, value); 98 | $prefix : map-get($map, prefix); 99 | $suffix : map-get($map, suffix); 100 | 101 | // Dynamically generate the template placeholders 102 | $p: '{{' + $key + '}}'; 103 | $pp: '{{' + $key + 'p' + '}}'; 104 | $ps: '{{' + $key + 's' + '}}'; 105 | 106 | @if not is-null($value) and str-length($value) > 0 { 107 | $result: str-replace($result, $p, $value); 108 | $result: str-replace($result, $pp, $prefix); 109 | $result: str-replace($result, $ps, $suffix); 110 | } @else { 111 | $result: str-remove($result, $p); 112 | $result: str-remove($result, $pp); 113 | $result: str-remove($result, $ps); 114 | } 115 | } 116 | 117 | @return $result; 118 | } 119 | -------------------------------------------------------------------------------- /lib/functions/em.scss: -------------------------------------------------------------------------------- 1 | /// Converts `px` to `em`. 2 | /// 3 | /// @group 5_functions 4 | /// 5 | /// @requires {function} unit-strip 6 | /// 7 | /// @param {Number} $value - Value (in px) to convert 8 | /// @param {Number} $base-font-size [16] - Value of the base font size (in px) 9 | /// 10 | /// @return {Number} - `$value` in `em` units 11 | /// 12 | /// @example 13 | /// em(32) 14 | /// // => 2em 15 | 16 | @function em($value, $base-font-size: 16) { 17 | $result: $value / unit-strip($base-font-size) * 1em; 18 | @return $result; 19 | } 20 | -------------------------------------------------------------------------------- /lib/functions/get-function-safe.scss: -------------------------------------------------------------------------------- 1 | /// Safely calls native `get-function()`. Intended for use with natice `call()`. 2 | /// 3 | /// @group 5_functions 4 | /// 5 | /// @requires {function} to-string 6 | /// 7 | /// @param {String} $function-name - Function name to call 8 | /// 9 | /// @return {Function|String} - Depending on Sass version 10 | /// 11 | /// @example 12 | /// call(get-function-safe('str-length'), 'hello world') 13 | /// // => 11 14 | 15 | @function get-function-safe($function-name) { 16 | $function-name: to-string($function-name); 17 | 18 | $result: if(function-exists('get-function'), 19 | get-function($function-name), 20 | $function-name 21 | ); 22 | 23 | @return $result; 24 | } 25 | -------------------------------------------------------------------------------- /lib/functions/important.scss: -------------------------------------------------------------------------------- 1 | /// Returns `!important` or an empty string. 2 | /// 3 | /// @group 5_functions 4 | /// 5 | /// @param {Bool} $output [option(output, important)] - Whether to output `!important` 6 | /// 7 | /// @return {String} 8 | /// 9 | /// @example 10 | /// important() 11 | /// // => !important 12 | 13 | @function important($output: option(output, important)) { 14 | $result: if($output, !important, null); 15 | @return $result; 16 | } 17 | -------------------------------------------------------------------------------- /lib/functions/is-null.scss: -------------------------------------------------------------------------------- 1 | /// Checks if the specified value is `null`. 2 | /// 3 | /// @group 5_functions 4 | /// 5 | /// @param {*} $value - Value to evaluate 6 | /// 7 | /// @return {Boolean} - Whether `$value` is `null` 8 | /// 9 | /// @example 10 | /// is-null(null) 11 | /// // => true 12 | /// 13 | /// is-null(false) 14 | /// // => false 15 | /// 16 | /// is-null('') 17 | /// // => false 18 | /// 19 | /// is-null(0) 20 | /// // => false 21 | 22 | @function is-null($value) { 23 | $result: if(type-of($value) == 'null', true, false); 24 | @return $result; 25 | } 26 | -------------------------------------------------------------------------------- /lib/functions/list-append.scss: -------------------------------------------------------------------------------- 1 | /// Adds values to the end of a list. 2 | /// 3 | /// @group 5_functions 4 | /// 5 | /// @param {List} $list - List to append to 6 | /// @param {ArgList} $values - Value(s) to be appended 7 | /// 8 | /// @return {List} - New list appended with `$values` 9 | /// 10 | /// @example 11 | /// list-append((1 2), 3) 12 | /// // => 1 2 3 13 | /// 14 | /// list-append((1 2), 3, 4, 5) 15 | /// // => 1 2 3 4 5 16 | 17 | @function list-append($list, $values...) { 18 | $result: $list; 19 | 20 | @each $value in $values { 21 | $result: append($result, $value); 22 | } 23 | 24 | @return $result; 25 | } 26 | -------------------------------------------------------------------------------- /lib/functions/list-contains.scss: -------------------------------------------------------------------------------- 1 | /// Checks if a list contains the specified value. 2 | /// 3 | /// @group 5_functions 4 | /// 5 | /// @param {List} $list - List to search 6 | /// @param {*} $value - Value to search for 7 | /// 8 | /// @return {Bool} - Whether `$list` contains `$value` 9 | /// 10 | /// @example 11 | /// list-contains((1, 2, 3), 2) 12 | /// // => true 13 | /// 14 | /// list-contains((1, 2, 3), 4) 15 | /// // => false 16 | 17 | @function list-contains($list, $value) { 18 | $result: if(index($list, $value), true, false); 19 | @return $result; 20 | } 21 | -------------------------------------------------------------------------------- /lib/functions/list-each.scss: -------------------------------------------------------------------------------- 1 | /// Calls a function on each item in a list. 2 | /// 3 | /// @group 5_functions 4 | /// 5 | /// @requires {function} get-function-safe 6 | /// 7 | /// @param {List} $list - List to operate on 8 | /// @param {String} $function-name - Name of the function to call on each item 9 | /// @param {List} $args [()] - List of args to pass to the function 10 | /// 11 | /// @return {List} - New list with modified values 12 | /// 13 | /// @example 14 | /// list-each((1.2, 2.5, 3.7), 'round') 15 | /// // => (1, 3, 4) 16 | /// 17 | /// list-each(('hello', 'world'), 'str-insert', ('123', 1)) 18 | /// // => ('123hello', '123world') 19 | 20 | @function list-each($list, $function-name, $args: ()) { 21 | $separator : list-separator($list); 22 | $bracketed : is-bracketed($list); 23 | 24 | $result: (); 25 | 26 | // Apply the transformation to each item in $list 27 | // and push the results into a new list 28 | @each $item in $list { 29 | $item: call(get-function-safe($function-name), $item, $args...); 30 | $result: append($result, $item); 31 | } 32 | 33 | // Preserve list seperator and brackets 34 | $result: join($result, (), $separator, $bracketed); 35 | @return $result; 36 | } 37 | -------------------------------------------------------------------------------- /lib/functions/list-every.scss: -------------------------------------------------------------------------------- 1 | /// Checks if the result of calling a given function on every item in a list is true. 2 | /// 3 | /// @group 5_functions 4 | /// 5 | /// @requires {function} get-function-safe 6 | /// 7 | /// @param {List} $list - List to operate on 8 | /// @param {String} $function-name - Name of the function to call 9 | /// @param {List} $args [()] - List of args to pass to the function 10 | /// 11 | /// @return {Bool} - Whether the result of every item returned `true` 12 | /// 13 | /// @example 14 | /// list-every((1, 2, 3), 'unitless') 15 | /// // => true 16 | /// 17 | /// list-every((1, 2px, 3), 'unitless') 18 | /// // => false 19 | 20 | @function list-every($list, $function-name, $args: ()) { 21 | @each $item in $list { 22 | @if not call(get-function-safe($function-name), $item, $args...) { 23 | @return false; 24 | } 25 | } 26 | 27 | @return true; 28 | } 29 | -------------------------------------------------------------------------------- /lib/functions/list-prepend.scss: -------------------------------------------------------------------------------- 1 | /// Adds values to the start of a list. 2 | /// 3 | /// @group 5_functions 4 | /// 5 | /// @param {List} $list - List to prepend to 6 | /// @param {ArgList} $values - Value(s) to be prepended 7 | /// 8 | /// @return {List} - New list prepended with `$values` 9 | /// 10 | /// @example 11 | /// list-prepend((1 2), 3) 12 | /// // => 3 1 2 13 | /// 14 | /// list-prepend((1 2), 3, 4, 5) 15 | /// // => 3 4 5 1 2 16 | 17 | @function list-prepend($list, $values...) { 18 | $separator : list-separator($list); 19 | $bracketed : is-bracketed($list); 20 | 21 | $result: $list; 22 | 23 | @each $value in $values { 24 | $result: join(($value,), $result); 25 | } 26 | 27 | // Preserve list seperator and brackets 28 | $result: join((), $result, $separator, $bracketed); 29 | @return $result; 30 | } 31 | -------------------------------------------------------------------------------- /lib/functions/list-remove.scss: -------------------------------------------------------------------------------- 1 | /// Finds and removes a value in a list. 2 | /// 3 | /// @group 5_functions 4 | /// 5 | /// @param {List} $list - List to search 6 | /// @param {*} $search - Value to remove 7 | /// @param {Bool} $all [false] - Whether to remove all occurrances of the value 8 | /// 9 | /// @return {List} - New list with value(s) removed 10 | /// 11 | /// @example 12 | /// list-remove(1 2 3 1 2 3, 2) 13 | /// // => (1 3 1 2 3) 14 | /// 15 | /// list-remove(1 2 3 1 2 3, 2, true) 16 | /// // => (1 3 1 3) 17 | 18 | @function list-remove($list, $search, $all: false) { 19 | $separator : list-separator($list); 20 | $bracketed : is-bracketed($list); 21 | 22 | $result: (); 23 | 24 | // Remove the first instance of $search 25 | $first-search-index: index($list, $search); 26 | $i: 0; 27 | 28 | @each $item in $list { 29 | $i: $i + 1; 30 | @if $i != $first-search-index { 31 | $result: append($result, $item); 32 | } 33 | } 34 | 35 | @if $all == true { 36 | // Remove all remanining instances of $search 37 | @while not not index($result, $search) { 38 | $result: list-remove($result, $search); 39 | } 40 | } 41 | 42 | // Preserve list seperator and brackets 43 | $result: join($result, (), $separator, $bracketed); 44 | 45 | @return $result; 46 | } 47 | -------------------------------------------------------------------------------- /lib/functions/list-replace.scss: -------------------------------------------------------------------------------- 1 | /// Finds and replaces a value in a list. 2 | /// 3 | /// @group 5_functions 4 | /// 5 | /// @param {List} $list - List to search 6 | /// @param {*} $search - Value search for 7 | /// @param {*} $replace - Replacement value 8 | /// @param {Bool} $all [false] - Whether to replace all occurrances of the value 9 | /// 10 | /// @return {List} - New list with value(s) replaced 11 | /// 12 | /// @example 13 | /// list-replace((1 2 3), 2) 14 | /// // => (1 2) 15 | /// 16 | /// list-replace((1 2 2 2 3), 2, 4) 17 | /// // => (1 4 2 2 3) 18 | /// 19 | /// list-replace((1 2 2 2 3), 2, 4, true) 20 | /// // => (1 4 4 4 3) 21 | 22 | @function list-replace($list, $search, $replace, $all: false) { 23 | // Replace the first instance of $search 24 | $result: set-nth($list, index($list, $search), $replace); 25 | 26 | @if $all == true { 27 | // Replace all remanining instances of $search 28 | @while not not index($result, $search) { 29 | $result: list-replace($result, $search, $replace); 30 | } 31 | } 32 | 33 | @return $result; 34 | } 35 | -------------------------------------------------------------------------------- /lib/functions/list-reverse.scss: -------------------------------------------------------------------------------- 1 | /// Reverses the order of values in a list. 2 | /// 3 | /// @group 5_functions 4 | /// 5 | /// @requires {function} to-negative 6 | /// 7 | /// @param {List} $list - List to reverse 8 | /// 9 | /// @return {List} - New list with reversed order 10 | /// 11 | /// @example 12 | /// list-reverse(1, a, 3) 13 | /// // => (3, a, 1) 14 | 15 | @function list-reverse($list) { 16 | $separator : list-separator($list); 17 | $bracketed : is-bracketed($list); 18 | 19 | $result: (); 20 | 21 | @for $i from to-negative(length($list)) through -1 { 22 | $result: append($result, nth($list, abs($i))); 23 | } 24 | 25 | // Preserve list seperator and brackets 26 | $result: join($result, (), $separator, $bracketed); 27 | 28 | @return $result; 29 | } 30 | -------------------------------------------------------------------------------- /lib/functions/list-sort.scss: -------------------------------------------------------------------------------- 1 | /// Sorts items in a list. 2 | /// 3 | /// @group 5_functions 4 | /// 5 | /// @requires {function} const 6 | /// @requires {function} str-compare 7 | /// 8 | /// @param {List} $list - List to sort 9 | /// @param {List} $order [const(CHARSPACE, SORT_ORDER)] - Sort order 10 | /// 11 | /// @return {List} - New list with sorted items 12 | /// 13 | /// @example 14 | /// list-sort(b c a) 15 | /// // => (a b c) 16 | /// 17 | /// list-sort(b c a, (c, b, a)) 18 | /// // => (c b a) 19 | 20 | @function list-sort($list, $order: const(CHARSPACE, SORT_ORDER)) { 21 | $separator : list-separator($list); 22 | $bracketed : is-bracketed($list); 23 | $less : (); 24 | $equal : (); 25 | $large : (); 26 | 27 | $result: join($list, (), 'comma', false); 28 | 29 | @if length($list) > 1 { 30 | $seed: nth($list, ceil(length($list) / 2)); 31 | 32 | @each $item in $list { 33 | @if $item == $seed { 34 | $equal: append($equal, $item); 35 | } @else if str-compare($item, $seed, $order) { 36 | $less: append($less, $item); 37 | } @else if not str-compare($item, $seed, $order) { 38 | $large: append($large, $item); 39 | } 40 | } 41 | 42 | $result: join(join(list-sort($less, $order), $equal), list-sort($large, $order)); 43 | } 44 | 45 | $result: join($result, (), $separator, $bracketed); 46 | @return $result; 47 | } 48 | -------------------------------------------------------------------------------- /lib/functions/list-unique.scss: -------------------------------------------------------------------------------- 1 | /// Removes duplicate values from a list. 2 | /// 3 | /// @group 5_functions 4 | /// 5 | /// @param {List} $list - List to remove duplicates from 6 | /// 7 | /// @return {List} - List with duplicates items removed 8 | /// 9 | /// @example 10 | /// list-unique((a, b, c, a, a, c)) 11 | /// // => (a, b, c); 12 | 13 | @function list-unique($list) { 14 | $separator : list-separator($list); 15 | $bracketed : is-bracketed($list); 16 | 17 | $result: (); 18 | 19 | @each $item in $list { 20 | @if not index($result, $item) { 21 | $result: append($result, $item); 22 | } 23 | } 24 | 25 | // Preserve list seperator and brackets 26 | $result: join($result, (), $separator, $bracketed); 27 | 28 | @return $result; 29 | } 30 | 31 | -------------------------------------------------------------------------------- /lib/functions/map-append.scss: -------------------------------------------------------------------------------- 1 | /// Adds a single key-value pair onto the end of a map. 2 | /// 3 | /// @group 5_functions 4 | /// 5 | /// @param {Map} $map - Map to append to 6 | /// @param {*} $key - Key to be appended 7 | /// @param {*} $value - Value to be appended 8 | /// 9 | /// @return {Map} - New map appended with key-value pair 10 | /// 11 | /// @example 12 | /// map-append((a: 1, b: 2), c, 3) 13 | /// // => (a: 1, b: 2, c: 3) 14 | 15 | @function map-append($map, $key, $value) { 16 | $result: map-merge($map, ($key: $value)); 17 | @return $result; 18 | } 19 | -------------------------------------------------------------------------------- /lib/functions/map-each-key.scss: -------------------------------------------------------------------------------- 1 | /// Calls a function on each key in a map. 2 | /// 3 | /// @group 5_functions 4 | /// 5 | /// @requires {function} get-function-safe 6 | /// 7 | /// @param {Map} $map - Map to operate on 8 | /// @param {String} $function-name - Name of the function to call 9 | /// @param {List} $args [()] - List of args to pass to the function 10 | /// 11 | /// @return {Map} - New map with modified keys 12 | /// 13 | /// @example 14 | /// map-each-key((1.1: a, 2.5: b, 3.6: c), 'round') 15 | /// // => (1: a, 3: b, 4: c) 16 | /// 17 | /// map-each-key(('apple': 1, 'orange': 2), 'str-replace', ('a', '4')) 18 | /// // => ('4pple': 1, 'or4nge': 2) 19 | 20 | @function map-each-key($map, $function-name, $args: ()) { 21 | $result: (); 22 | 23 | @each $key, $value in $map { 24 | $key: call(get-function-safe($function-name), $key, $args...); 25 | $result: map-merge($result, ($key: $value)); 26 | } 27 | 28 | @return $result; 29 | } 30 | -------------------------------------------------------------------------------- /lib/functions/map-each-value.scss: -------------------------------------------------------------------------------- 1 | /// Calls a function on each value in a map. 2 | /// 3 | /// @group 5_functions 4 | /// 5 | /// @requires {function} get-function-safe 6 | /// 7 | /// @param {Map} $map - Map to operate on 8 | /// @param {String} $function-name - Name of the function to call 9 | /// @param {List} $args [()] - List of args to pass to the function 10 | /// 11 | /// @return {Map} - New map with modified values 12 | /// 13 | /// @example 14 | /// map-each-value((a: 1.1, b: 2.5, c: 3.6), 'round') 15 | /// // => (a: 1, b: 3, c: 4) 16 | /// 17 | /// map-each-value((a: 'apple', b: 'orange'), 'str-replace', ('a', '4')) 18 | /// // => (a: '4pple', b: 'or4nge') 19 | 20 | @function map-each-value($map, $function-name, $args: ()) { 21 | $result: (); 22 | 23 | @each $key, $value in $map { 24 | $value: call(get-function-safe($function-name), $value, $args...); 25 | $result: map-merge($result, ($key: $value)); 26 | } 27 | 28 | @return $result; 29 | } 30 | -------------------------------------------------------------------------------- /lib/functions/map-flatten.scss: -------------------------------------------------------------------------------- 1 | /// Flattens a map one-level deep. 2 | /// 3 | /// @group 5_functions 4 | /// 5 | /// @requires {function} option 6 | /// @requires {function} map-append 7 | /// 8 | /// @param {Map} $map - Map to operate on 9 | /// @param {String} $separator [option(namescheme, variant-prefix)] - Separator to use for flattened key names 10 | /// 11 | /// @return {Map} - New flattened map 12 | /// 13 | /// @example 14 | /// map-flatten(('cyan': ('1': #00ffff, '2': #00aaaa)), '-') 15 | /// // => ('cyan-1': #00ffff, 'cyan-2': #00aaaa) 16 | 17 | @function map-flatten($map, $separator: option(namescheme, variant-prefix)) { 18 | $result: (); 19 | 20 | @each $key, $val in $map { 21 | @if type-of($val) == 'map' { 22 | $_result: (); 23 | @each $k, $v in $val { 24 | @if $k == option(namescheme, default-key) { 25 | $_result: map-append($_result, $key, $v); 26 | } @else { 27 | $_result: map-append($_result, #{$key}#{$separator}#{$k}, $v); 28 | } 29 | } 30 | 31 | $result: map-merge($result, $_result); 32 | } @else { 33 | $result: map-append($result, $key, $val); 34 | } 35 | } 36 | 37 | @return $result; 38 | } 39 | -------------------------------------------------------------------------------- /lib/functions/map-get-key.scss: -------------------------------------------------------------------------------- 1 | /// Returns the key(s) in a map associated with a given value. 2 | /// 3 | /// @group 5_functions 4 | /// 5 | /// @param {Map} $map - Map to operate on 6 | /// @param {*} $search - Value to search for 7 | /// 8 | /// @return {List} - List containing keys with values that match $search 9 | /// 10 | /// @example 11 | /// map-get-key((a: 1, b: 2, c: 3), 2) 12 | /// // => (b) 13 | /// 14 | /// map-get-key((a: 1, b: 2, c: 2), 2) 15 | /// // => (b, c) 16 | 17 | @function map-get-key($map, $search) { 18 | $result: (); 19 | 20 | $keys: map-keys($map); 21 | $values: map-values($map); 22 | 23 | @for $i from 1 through length($values) { 24 | @if nth($values, $i) == $search { 25 | $result: list-append($result, nth($keys, $i)); 26 | } 27 | } 28 | 29 | // Convert result to comma list 30 | $result: join($result, (), 'comma'); 31 | 32 | @return $result; 33 | } 34 | -------------------------------------------------------------------------------- /lib/functions/map-prepend.scss: -------------------------------------------------------------------------------- 1 | /// Adds a single key-value pair onto the start of a map. 2 | /// 3 | /// @group 5_functions 4 | /// 5 | /// @param {Map} $map - Map to prepend to 6 | /// @param {*} $key - Key to be prepended 7 | /// @param {*} $value - Value to be prepended 8 | /// 9 | /// @return {Map} - New map prepended with key-value pair 10 | /// 11 | /// @example 12 | /// map-prepend((a: 1, b: 2), c, 3) 13 | /// // => (c: 3, a: 1, b: 2) 14 | 15 | @function map-prepend($map, $key, $value) { 16 | $result: map-merge(($key: $value), $map); 17 | @return $result; 18 | } 19 | -------------------------------------------------------------------------------- /lib/functions/map-stringify-keys-deep.scss: -------------------------------------------------------------------------------- 1 | /// Converts all keys in a map to strings, including keys of nested maps. 2 | /// 3 | /// @group 5_functions 4 | /// 5 | /// @requires {function} map-stringify-keys 6 | /// 7 | /// @param {Map} $map - Map to stringify 8 | /// 9 | /// @return {Map} - New map with all keys converted to strings 10 | /// 11 | /// @example 12 | /// $map: ( 13 | /// 1: 1, 14 | /// hello: 2, 15 | /// red: 3, 16 | /// map: ( 17 | /// 1: 1, 18 | /// blue: 2 19 | /// ) 20 | /// ); 21 | /// 22 | /// @each $key, $val in $map { 23 | /// @debug type-of($key); 24 | /// 25 | /// @if type-of($val) == 'map' { 26 | /// @each $k, $v in $val { 27 | /// @debug type-of($v); 28 | /// } 29 | /// } 30 | /// } 31 | /// 32 | /// // DEBUG: number 33 | /// // DEBUG: string 34 | /// // DEBUG: color 35 | /// // DEBUG: string 36 | /// // DEBUG: number 37 | /// // DEBUG: color 38 | /// 39 | /// $stringified-map: stringify-keys($map); 40 | /// 41 | /// @each $key, $val in $stringified-map { 42 | /// @debug type-of($key); 43 | /// } 44 | /// 45 | /// // DEBUG: string 46 | /// // DEBUG: string 47 | /// // DEBUG: string 48 | /// // DEBUG: string 49 | /// // DEBUG: string 50 | /// // DEBUG: string 51 | 52 | @function map-stringify-keys-deep($map) { 53 | $result: map-stringify-keys($map); 54 | 55 | @each $key, $val in $map { 56 | @if type-of($val) == 'map' { 57 | $val: map-stringify-keys-deep($val); 58 | $result: map-merge($result, map-stringify-keys(($key: $val))); 59 | } 60 | } 61 | 62 | @return $result; 63 | } 64 | -------------------------------------------------------------------------------- /lib/functions/map-stringify-keys.scss: -------------------------------------------------------------------------------- 1 | /// Converts direct keys of a map to strings. 2 | /// 3 | /// @group 5_functions 4 | /// 5 | /// @requires {function} to-string 6 | /// 7 | /// @param {Map} $map - Map to stringify 8 | /// 9 | /// @return {Map} - New map with direct keys converted to strings 10 | /// 11 | /// @example 12 | /// $map: ( 13 | /// 1: 1, 14 | /// hello: 2, 15 | /// red: 3, 16 | /// map: ( 17 | /// 1: 1, 18 | /// blue: 2 19 | /// ) 20 | /// ); 21 | /// 22 | /// @each $key, $val in $map { 23 | /// @debug type-of($key); 24 | /// 25 | /// @if type-of($val) == 'map' { 26 | /// @each $k, $v in $val { 27 | /// @debug type-of($v); 28 | /// } 29 | /// } 30 | /// } 31 | /// 32 | /// // DEBUG: number 33 | /// // DEBUG: string 34 | /// // DEBUG: color 35 | /// // DEBUG: string 36 | /// // DEBUG: number 37 | /// // DEBUG: color 38 | /// 39 | /// $stringified-map: stringify-keys($map); 40 | /// 41 | /// @each $key, $val in $stringified-map { 42 | /// @debug type-of($key); 43 | /// } 44 | /// 45 | /// // DEBUG: string 46 | /// // DEBUG: string 47 | /// // DEBUG: string 48 | /// // DEBUG: string 49 | /// // DEBUG: number 50 | /// // DEBUG: color 51 | 52 | @function map-stringify-keys($map) { 53 | $result: (); 54 | 55 | @each $key, $value in $map { 56 | $key: quote(to-string($key)); 57 | $result: map-merge($result, ($key: $value)); 58 | } 59 | 60 | @return $result; 61 | } 62 | 63 | -------------------------------------------------------------------------------- /lib/functions/map-unique.scss: -------------------------------------------------------------------------------- 1 | /// Removes key-value pairs from a map which contain duplicate values. 2 | /// 3 | /// If a map contains key-value pairs with multiple values, 4 | /// the first key in the map is retained, and duplicates are removed. 5 | /// 6 | /// @group 5_functions 7 | /// 8 | /// @param {Map} $map - Map to remove duplicates from 9 | /// 10 | /// @return {Map} - New map with duplicates removed 11 | /// 12 | /// @example 13 | /// map-unique(( 14 | /// blue: #0000ff, 15 | /// red: #ff0000, 16 | /// green: #00ff00, 17 | /// brand: #0000ff 18 | /// )); 19 | /// // => ( 20 | /// // blue: #0000ff, 21 | /// // red: #ff0000, 22 | /// // green: #00ff00 23 | /// // ); 24 | 25 | @function map-unique($map) { 26 | $indices : (); 27 | $values : map-values($map); 28 | 29 | $result: (); 30 | 31 | @each $value in $values { 32 | $indices: append($indices, index($values, $value)); 33 | } 34 | 35 | $last-index: 0; 36 | @each $index in $indices { 37 | @if $index > $last-index { 38 | $result: map-merge($result, ( 39 | nth(nth($map, $index), 1): nth(nth($map, $index), 2) 40 | )); 41 | } 42 | 43 | $last-index: $index; 44 | } 45 | 46 | @return $result; 47 | } 48 | 49 | -------------------------------------------------------------------------------- /lib/functions/random-color.scss: -------------------------------------------------------------------------------- 1 | /// Returns a random color. 2 | /// 3 | /// @group 5_functions 4 | /// 5 | /// @return {Color} - Random color 6 | /// 7 | /// @example 8 | /// type-of(random-color()) 9 | /// // => 'color' 10 | 11 | @function random-color() { 12 | $result: rgb(random(255), random(255), random(255)); 13 | @return $result; 14 | } 15 | -------------------------------------------------------------------------------- /lib/functions/rem.scss: -------------------------------------------------------------------------------- 1 | /// Converts `px` to `rem`. 2 | /// 3 | /// @group 5_functions 4 | /// 5 | /// @requires {function} unit-strip 6 | /// 7 | /// @param {Number} $value - Value (in px) to convert 8 | /// @param {Number} $base-font-size [16] - Value of the base font size (in px) 9 | /// 10 | /// @return {Number} - `$value` in `rem` units 11 | /// 12 | /// @example 13 | /// rem(32) 14 | /// // => 2rem 15 | 16 | @function rem($value, $base-font-size: 16) { 17 | $result: $value / unit-strip($base-font-size) * 1rem; 18 | @return $result; 19 | } 20 | -------------------------------------------------------------------------------- /lib/functions/str-append.scss: -------------------------------------------------------------------------------- 1 | /// Appends to a string. 2 | /// 3 | /// @group 5_functions 4 | /// 5 | /// @requires {function} is-null 6 | /// 7 | /// @param {String} $string - String to append to 8 | /// @param {ArgList} $strings - String(s) to be appended 9 | /// 10 | /// @return {String} 11 | /// 12 | /// @example 13 | /// str-append('hello', 'world') 14 | /// // => 'helloworld' 15 | /// 16 | /// str-append('hello', ' ', 'world') 17 | /// // => 'hello world' 18 | 19 | @function str-append($string, $strings...) { 20 | $result: $string; 21 | 22 | @each $str in $strings { 23 | $str: if(is-null($str), '', $str); 24 | $result: $result + $str; 25 | } 26 | 27 | @return $result; 28 | } 29 | -------------------------------------------------------------------------------- /lib/functions/str-compare.scss: -------------------------------------------------------------------------------- 1 | /// Compares two strings or numbers to determine which comes first. 2 | /// 3 | /// @group 5_functions 4 | /// 5 | /// @requires {function} const 6 | /// @requires {function} to-string 7 | /// 8 | /// @param {String|Number} $a - First string 9 | /// @param {String|Number} $b - Second string 10 | /// @param {List} $order [const(CHARSPACE, SORT_ORDER)] - Sort order 11 | /// 12 | /// @return {Bool} - Whether $a comes before $b in the given $order 13 | /// 14 | /// @example 15 | /// str-compare('a', 'b') 16 | /// // => true 17 | /// 18 | /// str-compare(2, 1) 19 | /// // => false 20 | 21 | @function str-compare($a, $b, $order: const(CHARSPACE, SORT_ORDER)) { 22 | @if type-of($a) == "number" and type-of($b) == "number" { 23 | @return $a < $b; 24 | } 25 | 26 | $a : to-lower-case(to-string($a)); 27 | $b : to-lower-case(to-string($b)); 28 | 29 | @for $i from 1 through min(str-length($a), str-length($b)) { 30 | $char-a: str-slice($a, $i, $i); 31 | $char-b: str-slice($b, $i, $i); 32 | 33 | @if $char-a and $char-b and index($order, $char-a) != index($order, $char-b) { 34 | @return index($order, $char-a) < index($order, $char-b); 35 | } 36 | } 37 | 38 | @return str-length($a) < str-length($b); 39 | } 40 | -------------------------------------------------------------------------------- /lib/functions/str-contains.scss: -------------------------------------------------------------------------------- 1 | /// Checks if a string contains a substring. 2 | /// 3 | /// @group 5_functions 4 | /// 5 | /// @requires {function} is-null 6 | /// 7 | /// @param {String} $string - String to search in 8 | /// @param {String} $substring - Substring to search for 9 | /// 10 | /// @return {Bool} - Whether `$string` contains `$substring` 11 | /// 12 | /// @example 13 | /// str-contains('team', 'i') 14 | /// // => false 15 | /// 16 | /// str-contains('hello', 'hell') 17 | /// // => true 18 | 19 | @function str-contains($string, $substring) { 20 | $result: if(is-null(str-index($string, $substring)), false, true); 21 | @return $result; 22 | } 23 | -------------------------------------------------------------------------------- /lib/functions/str-escape.scss: -------------------------------------------------------------------------------- 1 | /// Escapes CSS special characters within a string. 2 | /// 3 | /// @group 5_functions 4 | /// 5 | /// @requires {function} const 6 | /// @requires {function} str-replace 7 | /// @requires {function} list-contains 8 | /// 9 | /// @link https://mathiasbynens.be/notes/css-escapes Notes on CSS escapes 10 | /// 11 | /// @param {String} $string - String to escape 12 | /// 13 | /// @return {String} 14 | /// 15 | /// @example 16 | /// str-escape('_a:b!😀(b)c-d@') 17 | /// // => '_a\3A b\!😀\(b\)c\-d\@' 18 | 19 | @function str-escape($string) { 20 | $result: $string; 21 | $count: 0; 22 | 23 | @for $i from 1 through str-length($string) { 24 | $char: str-slice($string, $i, $i); 25 | 26 | // Escape special characters with a backslash. 27 | // Although recommended, we do not escape colon `:` as `\3A `, 28 | // because this causes problems when using Webpack. 29 | @if list-contains(const(CSS, SPECIAL_CHARS), $char) { 30 | $result: str-insert($result, '\\', ($i + $count)); 31 | $count: $count + 1; 32 | } 33 | } 34 | 35 | @return $result; 36 | } 37 | -------------------------------------------------------------------------------- /lib/functions/str-prepend.scss: -------------------------------------------------------------------------------- 1 | /// Prepends to a string. 2 | /// 3 | /// @group 5_functions 4 | /// 5 | /// @param {String} $string - String to prepend to 6 | /// @param {ArgList} $strings - String(s) to be prepended 7 | /// 8 | /// @return {String} 9 | /// 10 | /// @example 11 | /// str-prepend('hello', 'world') 12 | /// // => 'worldhello' 13 | /// 14 | /// str-prepend('hello', ' ', 'world') 15 | /// // => 'world hello' 16 | 17 | @function str-prepend($string, $strings...) { 18 | $result: $string; 19 | 20 | @each $string in $strings { 21 | $result: $string + $result; 22 | } 23 | 24 | @return $result; 25 | } 26 | -------------------------------------------------------------------------------- /lib/functions/str-remove.scss: -------------------------------------------------------------------------------- 1 | /// Removes a substring within a string. 2 | /// 3 | /// @group 5_functions 4 | /// 5 | /// @requires {function} str-replace 6 | /// 7 | /// @param {String} $string - String to search in 8 | /// @param {String} $search - Substring to search for 9 | /// @param {Boolean} $all [false] - Whether to remove all occurances 10 | /// 11 | /// @return {String} 12 | /// 13 | /// @example 14 | /// str-remove('Beetle', 'e') 15 | /// // => Betle 16 | /// 17 | /// str-remove('Beetle', 'e', true) 18 | /// // => Btl 19 | 20 | @function str-remove($string, $search, $all: false) { 21 | $result: $string; 22 | $index: str-index($string, $search); 23 | 24 | @if $index { 25 | $result: str-replace($string, $search, '', $all); 26 | } 27 | 28 | @return $result; 29 | } 30 | -------------------------------------------------------------------------------- /lib/functions/str-replace.scss: -------------------------------------------------------------------------------- 1 | /// Replaces a substring within a string. 2 | /// 3 | /// @group 5_functions 4 | /// 5 | /// @requires {function} str-append 6 | /// @requires {function} str-remove 7 | /// @requires {function} str-contains 8 | /// @requires {function} list-append 9 | /// 10 | /// @param {String} $string - String to search in 11 | /// @param {String} $search - Substring to search for 12 | /// @param {String} $replace [''] - Replacement string 13 | /// @param {Boolean} $all [false] - Whether to replace all occurances 14 | /// 15 | /// @return {String} 16 | /// 17 | /// @example 18 | /// str-replace($string, 'e', '3') 19 | /// // => B3etle 20 | /// 21 | /// str-replace($string, 'e', '3', true) 22 | /// // => B33tl3 23 | /// 24 | /// str-replace($string, 'e', true) 25 | /// // => Btl 26 | 27 | @function str-replace($string, $search, $replace: '', $all: false) { 28 | $result: $string; 29 | $first-index: str-index($string, $search); 30 | 31 | @if $first-index { 32 | @if not $all { 33 | // Replace the first occurance 34 | $result: str-append( 35 | str-slice($string, 1, ($first-index - 1)), 36 | $replace, 37 | str-slice($string, $first-index + str-length($search)) 38 | ); 39 | } @else { 40 | $indexes: []; 41 | $occurances: 0; 42 | $_string: $string; 43 | 44 | @while str-contains($_string, $search) { 45 | $index: str-index($_string, $search) + ($occurances * str-length($replace)); 46 | $indexes: list-append($indexes, $index); 47 | $_string: str-remove($_string, $search); 48 | $occurances: $occurances + 1; 49 | } 50 | 51 | @each $index in $indexes { 52 | // Remove $search at $index 53 | $result: str-append( 54 | str-slice($result, 1, $index - 1), 55 | str-slice($result, ($index + str-length($search))) 56 | ); 57 | 58 | // Insert $replace at $index 59 | $result: str-insert($result, $replace, $index); 60 | } 61 | } 62 | } 63 | 64 | @return $result; 65 | } 66 | -------------------------------------------------------------------------------- /lib/functions/throw.scss: -------------------------------------------------------------------------------- 1 | /// Throws an error. 2 | /// 3 | /// @group 5_functions 4 | /// 5 | /// @param {String} $exception - Exception type 6 | /// @param {String} $message - Message to return 7 | /// @param {Boolean} $throw [option(throw-errors)] - Whether to throw or return the error as a string 8 | /// 9 | /// @return {String} 10 | /// @throws `[$exception] $message` 11 | 12 | @function throw($exception, $message, $throw: option(throw-errors)) { 13 | $result: '[#{$exception}] #{$message}'; 14 | 15 | @if $throw { 16 | @error $result; 17 | } 18 | 19 | @return $result 20 | } 21 | 22 | 23 | 24 | @mixin throw($args...) { 25 | $_: throw($args...); 26 | } 27 | -------------------------------------------------------------------------------- /lib/functions/to-length.scss: -------------------------------------------------------------------------------- 1 | /// Adds a unit to a value 2 | /// 3 | /// @author Hugo Giraudel 4 | /// 5 | /// @group 5_functions 6 | /// 7 | /// @param {Number} $value - Value to add unit to 8 | /// @param {String} $unit - String representation of the unit 9 | /// 10 | /// @return {Number} - `$value` expressed in `$unit` 11 | 12 | @function to-length($value, $unit) { 13 | $units: ( 14 | 'px' : 1px, 15 | 'cm' : 1cm, 16 | 'mm' : 1mm, 17 | '%' : 1%, 18 | 'ch' : 1ch, 19 | 'pc' : 1pc, 20 | 'in' : 1in, 21 | 'em' : 1em, 22 | 'rem' : 1rem, 23 | 'pt' : 1pt, 24 | 'ex' : 1ex, 25 | 'vw' : 1vw, 26 | 'vh' : 1vh, 27 | 'vmin' : 1vmin, 28 | 'vmax' : 1vmax 29 | ); 30 | 31 | @return $value * map-get($units, $unit); 32 | } 33 | -------------------------------------------------------------------------------- /lib/functions/to-negative.scss: -------------------------------------------------------------------------------- 1 | /// Converts a number, list, or map of values to negative value(s). 2 | /// 3 | /// @group 5_functions 4 | /// 5 | /// @requires {function} list-each 6 | /// @requires {function} map-append 7 | /// 8 | /// @param {Number|List|Map} $value - Number, list, or map to convert 9 | /// 10 | /// @return {Number|List|Map} - Converted value 11 | /// 12 | /// @example 13 | /// to-negative(10px) 14 | /// // => -10px; 15 | /// 16 | /// to-negative((1, -2rem, 30px)) 17 | /// // => (-1, -2rem, -30px); 18 | /// 19 | /// to-negative((a: 1, b: (1, -2rem, 30px))) 20 | /// // => (a: -1, b: (-1, -2rem, -30px)); 21 | 22 | @function to-negative($value) { 23 | $result: $value; 24 | 25 | @if type-of($value) == 'number' { 26 | $result: abs($value) * -1; 27 | } 28 | 29 | @else if type-of($value) == 'list' { 30 | $result: list-each($value, 'to-negative'); 31 | } 32 | 33 | @else if type-of($value) == 'map' { 34 | $result: (); 35 | 36 | $map : $value; 37 | $keys : map-keys($map); 38 | $values : map-values($map); 39 | 40 | $index: 0; 41 | @each $val in $values { 42 | $index : $index + 1; 43 | $key : nth($keys, $index); 44 | $val : to-negative($val); 45 | 46 | $result: map-append($result, $key, $val); 47 | } 48 | } 49 | 50 | @return $result; 51 | } 52 | -------------------------------------------------------------------------------- /lib/functions/to-number.scss: -------------------------------------------------------------------------------- 1 | /// Converts a value to a number. 2 | /// 3 | /// @author Hugo Giraudel 4 | /// 5 | /// @group 5_functions 6 | /// 7 | /// @param {*} $value - Value to convert 8 | /// 9 | /// @return {Number} - Numeric value 10 | /// 11 | /// @example 12 | /// to-number('10px') 13 | /// // => 10px 14 | /// 15 | /// to-number('-0.2674') 16 | /// // => -0.2674 17 | 18 | @function to-number($value) { 19 | @if type-of($value) == 'number' { 20 | @return $value; 21 | } 22 | 23 | $result: 0; 24 | $digits: 0; 25 | $minus: str-slice($value, 1, 1) == '-'; 26 | $numbers: ('0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9); 27 | 28 | @for $i from if($minus, 2, 1) through str-length($value) { 29 | $character: str-slice($value, $i, $i); 30 | 31 | @if not (index(map-keys($numbers), $character) or $character == '.') { 32 | @return if($minus, -$result, $result); 33 | } 34 | 35 | @if $character == '.' { 36 | $digits: 1; 37 | } @else if $digits == 0 { 38 | $result: $result * 10 + map-get($numbers, $character); 39 | } @else { 40 | $digits: $digits * 10; 41 | $result: $result + map-get($numbers, $character) / $digits; 42 | } 43 | } 44 | 45 | @return if($minus, -$result, $result);; 46 | } 47 | -------------------------------------------------------------------------------- /lib/functions/to-string.scss: -------------------------------------------------------------------------------- 1 | /// Converts a value to a string. 2 | /// 3 | /// @group 5_functions 4 | /// 5 | /// @param {*} $value - Value to convert 6 | /// 7 | /// @return {String} - Stringified value 8 | /// 9 | /// @example 10 | /// to-string(2.1) 11 | /// // => '2.1' 12 | /// 13 | /// type-of(to-string(red)) 14 | /// // => 'string' 15 | 16 | @function to-string($value) { 17 | @if type-of($value) == 'string' { 18 | $value: unquote($value); 19 | } 20 | 21 | $result: inspect($value); 22 | @return $result; 23 | } 24 | -------------------------------------------------------------------------------- /lib/functions/type-check.scss: -------------------------------------------------------------------------------- 1 | /// Performs type checks on values. 2 | /// 3 | /// Returns `true` if all checks pass. Throws an error otherwise. 4 | /// 5 | /// @group 5_functions 6 | /// 7 | /// @requires {function} throw 8 | /// 9 | /// @param {String} $called-from - Name of the calling function or mixin 10 | /// @param {List} $checks - Map of checks to perform 11 | /// @param {Boolean} $throw - Whether to throw or return the error as a string 12 | /// 13 | /// @return {Boolean|String} - `true` if all checks pass 14 | /// @throws [TypeError] `$called-from` expected `$valid-types`, was: `$value` {`$value-type`} 15 | 16 | @function type-check($called-from, $checks, $throw) { 17 | // Perform type checks on each variable 18 | @each $check in $checks { 19 | $value: nth(nth($check, 1), 1); 20 | $value-type: type-of($value); 21 | $valid-types: nth(nth($check, 1), 2); 22 | 23 | @if not index($valid-types, $value-type) { 24 | @return throw('TypeError', '#{$called-from} expected {#{$valid-types}}, was: #{$value} {#{$value-type}}', $throw) 25 | } 26 | } 27 | 28 | @return true; 29 | } 30 | -------------------------------------------------------------------------------- /lib/functions/unit-convert.scss: -------------------------------------------------------------------------------- 1 | /// Converts units of a value. 2 | /// 3 | /// Can only convert comparable units. 4 | /// 5 | /// @group 5_functions 6 | /// 7 | /// @param {Number} $value - Value to convert 8 | /// @param {String} $unit - Unit to convert to 9 | /// 10 | /// @return {Number} - Converted value 11 | /// 12 | /// @example 13 | /// unit-convert(10px, pt) 14 | /// // => 7.5pt 15 | /// 16 | /// unit-convert(180deg, turn) 17 | /// // => 0.5turn 18 | 19 | @function unit-convert($value, $unit) { 20 | $valid-units: ( 21 | px: 0px, pt: 0pt, pc: 0pc, mm: 0mm, cm: 0cm, in: 0in, 22 | deg: 0deg, grad: 0grad, rad: 0rad, turn: 0turn, 23 | Hz: 0Hz, kHz: 0kHz, 24 | ms: 0ms, s: 0s 25 | ); 26 | 27 | $result: map-get($valid-units, $unit) + $value; 28 | @return $result; 29 | } 30 | -------------------------------------------------------------------------------- /lib/functions/unit-strip.scss: -------------------------------------------------------------------------------- 1 | /// Strips units from a value. 2 | /// 3 | /// @group 5_functions 4 | /// 5 | /// @param {Number} $value - Value to strip units from 6 | /// 7 | /// @return {Number} - Unitless value 8 | /// 9 | /// @example 10 | /// unit-strip(10px) 11 | /// // => 10 12 | 13 | @function unit-strip($value) { 14 | $result: $value / ($value * 0 + 1); 15 | @return $result; 16 | } 17 | -------------------------------------------------------------------------------- /lib/mixins/_.scss: -------------------------------------------------------------------------------- 1 | //// 2 | /// Mixins 3 | /// 4 | /// Mixins that output CSS. 5 | //// 6 | 7 | @import 'query'; 8 | @import 'extends'; 9 | @import 'important'; 10 | @import 'responsive'; 11 | @import 'type-scale'; 12 | @import 'css-ruleset'; 13 | -------------------------------------------------------------------------------- /lib/mixins/css-ruleset.scss: -------------------------------------------------------------------------------- 1 | /// Generates CSS ruleset(s) from a Scarab module. 2 | /// 3 | /// @group 6_mixins 4 | /// 5 | /// @requires {function} get 6 | /// @requires {function} option 7 | /// @requires {function} class-template 8 | /// @requires {function} class-sanitize 9 | /// @requires {function} class-escape 10 | /// @requires {function} str-replace 11 | /// @requires {function} is-null 12 | /// 13 | /// @param {Map} $module - Contains `root`, `breakpoints`, `states`, and `prefix/suffix` overrides 14 | /// @param {String} $variant - Selector variant 15 | /// @param {String} $modifier - Selector modifier 16 | /// 17 | /// @output CSS ruleset(s) 18 | 19 | @mixin css-ruleset($module, $variant: '', $modifier: '') { 20 | @if type-of($module) == 'string' { 21 | $module: module($module); 22 | } 23 | 24 | $variant: to-string($variant); 25 | $modifier: to-string($modifier); 26 | 27 | // Get module options 28 | $root : map-get($module, 'root'); 29 | $breakpoints : map-get($module, 'breakpoints'); 30 | $states : map-get($module, 'states'); 31 | 32 | // Allow $breakpoints to accept a list 33 | @if type-of($breakpoints) == 'list' { 34 | $_breakpoints: (); 35 | 36 | @each $name in $breakpoints { 37 | $_breakpoints: map-append($_breakpoints, to-string($name), get(breakpoint, $name)); 38 | } 39 | 40 | $breakpoints: $_breakpoints; 41 | } 42 | 43 | // Allow $states to accept a list 44 | @if type-of($states) == 'list' { 45 | $_states: (); 46 | 47 | @each $state in $states { 48 | $state-key: nth(map-get-key(option(namescheme, states), $state), 1); 49 | $_states: map-append($_states, $state-key, $state); 50 | } 51 | 52 | $states: $_states; 53 | } 54 | 55 | // Allow $module to overwrite global prefix/suffix options 56 | $breakpoint-prefix : if(is-null(map-get($module, 'breakpoint-prefix')), 57 | option(namescheme, breakpoint-prefix), 58 | map-get($module, 'breakpoint-prefix') 59 | ); 60 | 61 | $breakpoint-suffix : if(is-null(map-get($module, 'breakpoint-suffix')), 62 | option(namescheme, breakpoint-suffix), 63 | map-get($module, 'breakpoint-suffix') 64 | ); 65 | 66 | $state-prefix : if(is-null(map-get($module, 'state-prefix')), 67 | option(namescheme, state-prefix), 68 | map-get($module, 'state-prefix') 69 | ); 70 | 71 | $state-suffix : if(is-null(map-get($module, 'state-suffix')), 72 | option(namescheme, state-suffix), 73 | map-get($module, 'state-suffix') 74 | ); 75 | 76 | // Build the selector 77 | $class-template: class-template($module, $variant, $modifier); 78 | 79 | // Output base class 80 | .#{class-escape(class-sanitize($class-template))} { 81 | @content; 82 | } 83 | 84 | // Output stateful classes 85 | @if not is-null($states) { 86 | @each $state-name, $state-value in $states { 87 | $state-selector: str-replace($class-template, '{{s}}', $state-name); 88 | $state-selector: str-replace($state-selector, '{{sp}}', $state-prefix); 89 | $state-selector: str-replace($state-selector, '{{ss}}', $state-suffix); 90 | 91 | .#{class-escape(class-sanitize($state-selector))}:#{$state-value} { 92 | @content; 93 | } 94 | } 95 | } 96 | 97 | @if not is-null($breakpoints) { 98 | // Output responsive classes 99 | @each $bp-name, $bp-value in $breakpoints { 100 | $bp-selector: str-replace($class-template, '{{b}}', $bp-name); 101 | $bp-selector: str-replace($bp-selector, '{{bp}}', $breakpoint-prefix); 102 | $bp-selector: str-replace($bp-selector, '{{bs}}', $breakpoint-suffix); 103 | 104 | @include query($bp-value) { 105 | // Output base responsive class 106 | .#{class-escape(class-sanitize($bp-selector))} { 107 | @content; 108 | } 109 | 110 | // Output responsive, stateful classes 111 | @if not is-null($states) { 112 | @each $state-name, $state-value in $states { 113 | $rs-selector: str-replace($bp-selector, '{{s}}', $state-name); 114 | $rs-selector: str-replace($rs-selector, '{{sp}}', $state-prefix); 115 | $rs-selector: str-replace($rs-selector, '{{ss}}', $state-suffix); 116 | 117 | .#{class-escape(class-sanitize($rs-selector))}:#{$state-value} { 118 | @content; 119 | } 120 | } 121 | } 122 | } 123 | } 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /lib/mixins/extends.scss: -------------------------------------------------------------------------------- 1 | /// Extends multiple classes 2 | /// 3 | /// @group 6_mixins 4 | /// 5 | /// @requires {function} to-string 6 | /// @requires {function} class-escape 7 | /// 8 | /// @param {Arglist} $classes - Arglist of classes to extend 9 | /// 10 | /// @output Multiple Sass `@extend` directives 11 | 12 | @mixin extends($classes...) { 13 | @each $class in $classes { 14 | @extend .#{class-escape(to-string($class))}; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lib/mixins/important.scss: -------------------------------------------------------------------------------- 1 | /// Generates `!important` property declaration(s). 2 | /// 3 | /// @group 6_mixins 4 | /// 5 | /// @param {Map} $property-map - Map of properties to values 6 | /// 7 | /// @output !important property declaration(s) 8 | 9 | @mixin important($property-map) { 10 | @each $property, $value in $property-map { 11 | #{$property}: #{$value} !important; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /lib/mixins/query.scss: -------------------------------------------------------------------------------- 1 | /// Wraps declarations inside an `@media` block. 2 | /// 3 | /// @group 6_mixins 4 | /// 5 | /// @requires {function} get 6 | /// @requires {function} class-template 7 | /// 8 | /// @param {Number|List|Map} $query 9 | /// 10 | /// @output Style declarations inside an `@media` block 11 | /// 12 | /// @todo Add support for other types of media queries (besides width) 13 | 14 | @mixin query($query) { 15 | $breakpoint: (); 16 | $media-query: (); 17 | 18 | // If $query is a number, generate a `min-width: ` media query 19 | @if type-of($query) == 'number' { 20 | $breakpoint: $query; 21 | $media-query: '(min-width: #{$breakpoint})' 22 | } 23 | 24 | // If $query is a list, accept the following formats: 25 | // - query(from #{$bp}) => @media (min-width: #{$bp}) 26 | // - query(above #{$bp}) => @media (min-width: #{$bp} + 1px) 27 | // - query(until #{$bp}) => @media (max-width: #{$bp}) 28 | // - query(below #{$bp}) => @media (max-width: #{$bp} - 1px) 29 | // - query(from #{$bp1} to #{$bp2}) => @media (min-width: #{$bp1}) and (max-width: #{$bp2}) 30 | @else if type-of($query) == 'list' { 31 | 32 | @if (length($query) == 2) { 33 | $breakpoint: nth($query, 2); 34 | 35 | @if type-of($breakpoint) == 'number' { 36 | // "from #{$bp}" syntax 37 | @if nth($query, 1) == 'from' { 38 | $media-query: (min-width: #{$breakpoint}); 39 | } 40 | 41 | // "above #{$bp}" syntax 42 | @if nth($query, 1) == 'above' { 43 | $original-unit: unit($breakpoint); 44 | 45 | @if (unit($breakpoint) == 'em') or (unit($breakpoint) == 'rem') { 46 | $breakpoint: unit-strip((unit-strip($breakpoint) * 16px) + 1px) / 16#{$original-unit}; 47 | } @else { 48 | $breakpoint: unit-convert(unit-convert($breakpoint, 'px') + 1px, $original-unit); 49 | } 50 | 51 | $media-query: (min-width: #{$breakpoint}); 52 | } 53 | 54 | // "until #{$bp}" syntax 55 | @if nth($query, 1) == 'until' { 56 | $media-query: (max-width: #{$breakpoint}); 57 | } 58 | 59 | // "below #{$bp}" syntax 60 | @if nth($query, 1) == 'below' { 61 | $original-unit: unit($breakpoint); 62 | 63 | @if (unit($breakpoint) == 'em') or (unit($breakpoint) == 'rem') { 64 | $breakpoint: unit-strip((unit-strip($breakpoint) * 16px) - 1px) / 16#{$original-unit}; 65 | } @else { 66 | $breakpoint: unit-convert(unit-convert($breakpoint, 'px') - 1px, $original-unit); 67 | } 68 | 69 | $media-query: (max-width: #{$breakpoint}); 70 | } 71 | } 72 | } 73 | 74 | // "from #{$bp1} to #{$bp2}" syntax 75 | @if length($query) == 4 { 76 | $bp1: nth($query, 2); 77 | $bp2: nth($query, 4); 78 | 79 | $media-query: '(min-width: #{$bp1}) and (max-width: #{$bp2})'; 80 | } 81 | 82 | } 83 | 84 | // If $query is a map, expect it to have `type` and `condition` keys 85 | @else if type-of($query) == 'map' { 86 | $type: if(map-has-key($query, type), map-get($query, type), null); 87 | $condition: if(map-has-key($query, condition), map-get($query, condition), null); 88 | 89 | @if ($type) and ($condition) { 90 | $media-query: '#{$type} and #{unquote($condition)}'; 91 | } 92 | 93 | @else if $type { 94 | $media-query: #{$type}; 95 | } 96 | 97 | @else if $condition { 98 | $media-query: #{$condition}; 99 | } 100 | } 101 | 102 | @media #{$media-query} { 103 | @content; 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /lib/mixins/responsive.scss: -------------------------------------------------------------------------------- 1 | /// Generates responsive property declaration(s). 2 | /// 3 | /// @group 6_mixins 4 | /// 5 | /// @requires {function} get 6 | /// @requires {function} option 7 | /// @requires {mixin} query 8 | /// 9 | /// @param {String|List} $properties - Properties to declare 10 | /// @param {Map} $breakpoint-map - Map of breakpoint values to property values 11 | /// @param {Null|Boolean} $important [null] - Whether to ouput !important rules 12 | /// 13 | /// @output Responsive properties 14 | 15 | @mixin responsive($properties, $breakpoint-map, $important: null) { 16 | @each $breakpoint, $value in $breakpoint-map { 17 | @if $breakpoint == option(namescheme, default-key) { 18 | @each $property in $properties { 19 | #{$property}: $value important($important); 20 | } 21 | } @else { 22 | // If $breakpoint is a string, get the breakpoint value 23 | @if type-of($breakpoint) == 'string' { 24 | $breakpoint: get(breakpoint, $breakpoint); 25 | } 26 | 27 | @include query($breakpoint) { 28 | @each $property in $properties { 29 | #{$property}: $value important($important); 30 | } 31 | } 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /lib/mixins/type-scale.scss: -------------------------------------------------------------------------------- 1 | /// Generates `font-size` and `line-height` property declaration(s). 2 | /// 3 | /// @group 6_mixins 4 | /// 5 | /// @requires {function} get 6 | /// @requires {mixin} responsive 7 | /// 8 | /// @param {String} $size - Name of size in `get(font-sizes)` and `get(line-heights)` 9 | /// @param {Null|Boolean} $important [null] - Whether to ouput !important rules 10 | /// 11 | /// @output Property declarations for `font-size` and `line-height` 12 | 13 | @mixin type-scale($size, $important: null) { 14 | $font-size: get(font-size, $size); 15 | $line-height: get(line-height, $size); 16 | 17 | @if type-of($font-size) == 'map' { 18 | @include responsive(font-size, get(font-size, $size), $important); 19 | } @else { 20 | font-size: $font-size important($important); 21 | } 22 | 23 | @if type-of($line-height) == 'map' { 24 | @include responsive(line-height, get(line-height, $size), $important); 25 | } @else { 26 | line-height: $line-height important($important); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /lib/options/_.scss: -------------------------------------------------------------------------------- 1 | //// 2 | /// Options 3 | /// 4 | /// Function for managing Scarab options. 5 | //// 6 | 7 | @import '_init'; 8 | 9 | @import 'option'; 10 | @import 'set-option'; 11 | -------------------------------------------------------------------------------- /lib/options/_init.scss: -------------------------------------------------------------------------------- 1 | /// Options for the Scarab framework. 2 | /// 3 | /// Scarab options can be configured using `set-option()`. 4 | /// Refer to the table below for a description of each option. 5 | /// 6 | /// *During initialization, the `$__SCARAB_OPTIONS` variable is merged into `$__SCARAB`. 7 | /// Subsequently, its value is set to `null`.* 8 | /// 9 | /// @access private 10 | /// @group 0_variables 11 | /// 12 | /// @type Map 13 | /// @prop {Bool} throw-errors [true] - Whether to throw or return errors as strings 14 | /// @prop {Map} output - Contains options for the CSS output 15 | /// @prop {Bool} output.classes [true] - Whether Scarab should ouput CSS classes 16 | /// @prop {Bool} output.placeholders [true] - Whether Scarab should ouput Sass placeholders 17 | /// @prop {Bool} ouput.reset [true] - Whether Scarab should ouput CSS reset rules 18 | /// @prop {Bool} ouput.normalize [true] - Whether Scarab should ouput CSS normalize rules 19 | /// @prop {Bool} important [true] - Whether to append !important to generated modules 20 | /// @prop {Map} namescheme - Contains options for the naming scheme 21 | /// @prop {String} namescheme.default-key ['_'] - Key name to use for the "default" value in a map 22 | /// @prop {Map} namescheme.directions - Map of directional shorthands to values 23 | /// @prop {Map} namescheme.states - Map of state shorthands to values 24 | /// @prop {String} namescheme.selector-format - Format for programmatically generated CSS selectors 25 | /// @prop {String} namescheme.root-prefix [''] - Root prefix 26 | /// @prop {String} namescheme.root-suffix [''] - Root suffix 27 | /// @prop {String} namescheme.variant-prefix ['-'] - Variant prefix 28 | /// @prop {String} namescheme.variant-suffix [''] - Variant suffix 29 | /// @prop {String} namescheme.modifier-prefix [':'] - Modifier prefix 30 | /// @prop {String} namescheme.modifier-suffix [''] - Modifier suffix 31 | /// @prop {String} namescheme.breakpoint-prefix ['('] - Breakpoint prefix 32 | /// @prop {String} namescheme.breakpoint-suffix [')'] - Breakpoint suffix 33 | /// @prop {String} namescheme.state-prefix ['('] - State prefix 34 | /// @prop {String} namescheme.state-suffix [')'] - State suffix 35 | 36 | $__SCARAB_OPTIONS: ( 37 | 'throw-errors' : true, 38 | 'output' : ( 39 | 'classes' : true, 40 | 'placeholders' : true, 41 | 'reset' : true, 42 | 'normalize' : true, 43 | 'important' : true 44 | ), 45 | 'namescheme' : ( 46 | 'default-key' : '_', 47 | 'directions' : ( 48 | 'x' : horizontal, 49 | 'y' : vertical, 50 | 't' : top, 51 | 'r' : right, 52 | 'b' : bottom, 53 | 'l' : left 54 | ), 55 | 'anchors' : ( 56 | 't' : top, 57 | 'b' : bottom, 58 | 'l' : left, 59 | 'r' : right, 60 | 'c' : center, 61 | 'tr' : top right, 62 | 'tl' : top left, 63 | 'br' : bottom right, 64 | 'bl' : bottom left 65 | ), 66 | 'states' : ( 67 | 'hv': hover, 68 | 'fc': focus, 69 | 'ac': active 70 | ), 71 | 'selector-format' : '{{b}}{{bp}}{{s}}{{sp}}{{rp}}{{r}}{{rs}}{{vp}}{{v}}{{vs}}{{mp}}{{m}}{{ms}}{{ss}}{{bs}}', 72 | 'root-prefix' : '', 73 | 'root-suffix' : '', 74 | 'variant-prefix' : '-', 75 | 'variant-suffix' : '', 76 | 'modifier-prefix' : ':', 77 | 'modifier-suffix' : '', 78 | 'breakpoint-prefix' : '(', 79 | 'breakpoint-suffix' : ')', 80 | 'state-prefix' : '(', 81 | 'state-suffix' : ')' 82 | ) 83 | ); 84 | 85 | // Merge into $__SCARAB 86 | $__SCARAB: map-merge($__SCARAB, ('OPTIONS': $__SCARAB_OPTIONS)); 87 | $__SCARAB_OPTIONS: null; 88 | -------------------------------------------------------------------------------- /lib/options/option.scss: -------------------------------------------------------------------------------- 1 | /// Returns a value from the `OPTIONS` map 2 | /// 3 | /// @group 1_options 4 | /// 5 | /// @requires {variable} __SCARAB 6 | /// @requires {function} to-string 7 | /// 8 | /// @see {mixin} set 9 | /// 10 | /// @param {ArgList} $path - Path of the key to retrieve the value from 11 | /// @return {*} 12 | /// 13 | /// @example 14 | /// @include set-option(throw-errors, false); 15 | /// 16 | /// option(throw-errors); 17 | /// // => false 18 | 19 | @function option($path...) { 20 | $result: map-get($__SCARAB, 'OPTIONS'); 21 | 22 | @each $key in $path { 23 | $result: map-get($result, to-string($key)); 24 | } 25 | 26 | @return $result; 27 | } 28 | -------------------------------------------------------------------------------- /lib/options/set-option.scss: -------------------------------------------------------------------------------- 1 | /// Sets or updates a value of a key in the `OPTIONS` map 2 | /// 3 | /// @group 1_options 4 | /// 5 | /// @requires {variable} __SCARAB 6 | /// @requires {function} to-string 7 | /// @requires {function} map-stringify-keys-deep 8 | /// 9 | /// @see {function} option 10 | /// 11 | /// @param {ArgList} $definition - Definition of the new value 12 | /// 13 | /// @return {ArgList} - Definition of the new value 14 | /// 15 | /// @example 16 | /// $_: set-option(throw-errors, false); 17 | /// 18 | /// option(throw-errors); 19 | /// // => false 20 | 21 | @function set-option($definition...) { 22 | 23 | // Get a copy of the current $OPTIONS state 24 | $OPTIONS: map-get($__SCARAB, 'OPTIONS'); 25 | 26 | $result: (); // key-value pair that will be merged with $OPTIONS 27 | 28 | // If there are only 2 args, we can easily determine the result 29 | @if length($definition) == 2 { 30 | $key : nth($definition, 1); 31 | $new-value : nth($definition, 2); 32 | 33 | $result: ($key: $new-value); 34 | } 35 | 36 | // For more than 2 args, we have to build the result backwards 37 | @if length($definition) > 2 { 38 | 39 | // The new value is the last arg in $definition 40 | $new-value: nth($definition, -1); 41 | 42 | // Build a list of maps preceding the new one 43 | $maps: ($OPTIONS,); 44 | 45 | @for $i from 1 through length($definition) - 2 { 46 | $current-map : nth($maps, -1); 47 | $current-key : nth($definition, $i); 48 | $current-value : map-get($current-map, to-string($current-key)) or (); 49 | 50 | $maps: append($maps, $current-value); 51 | } 52 | 53 | @for $i from length($maps) through 1 { 54 | $current-map : nth($maps, $i); 55 | $current-key : nth($definition, $i); 56 | $current-value : (); 57 | 58 | @if $i == length($maps) { 59 | $current-value: $new-value; 60 | } @else { 61 | $current-value: $result; 62 | } 63 | 64 | $result: map-merge($current-map, (to-string($current-key): $current-value)); 65 | } 66 | } 67 | 68 | // Update the local $OPTIONS map 69 | $OPTIONS: map-merge($OPTIONS, map-stringify-keys-deep($result)); 70 | 71 | // Merge the updated $OPTIONS map back into $__SCARAB 72 | $__SCARAB: map-merge($__SCARAB, ('OPTIONS': $OPTIONS)) !global; 73 | @return $definition; 74 | 75 | } 76 | 77 | 78 | 79 | /// Calls `set-option` 80 | /// 81 | /// @group 1_options 82 | /// 83 | /// @requires {function} set-option 84 | /// 85 | /// @param {ArgList} $args - Args for `set-option` 86 | /// 87 | /// @example 88 | /// @include set-option(throw-errors, false); 89 | /// 90 | /// option(throw-errors); 91 | /// // => false 92 | 93 | @mixin set-option($args...) { 94 | $_: set-option($args...); 95 | } 96 | -------------------------------------------------------------------------------- /lib/tokens/_.scss: -------------------------------------------------------------------------------- 1 | //// 2 | /// Inventory 3 | /// 4 | /// Functions for design token management. 5 | //// 6 | 7 | @import '_init'; 8 | 9 | @import 'get'; 10 | @import 'set'; 11 | @import 'set-default'; 12 | @import 'unset'; 13 | 14 | @import 'helpers/_'; 15 | -------------------------------------------------------------------------------- /lib/tokens/_init.scss: -------------------------------------------------------------------------------- 1 | /// The global stylesheet tokens. 2 | /// 3 | /// Token values can be configured using `set()`. 4 | /// They can be retrieved using `get()`, or any of the tokens helper functions like `font-size()`, `fz()`, etc. 5 | /// 6 | /// *During initialization, the `$__SCARAB_TOKENS` variable is merged into `$__SCARAB`. 7 | /// Subsequently, its value is set to `null`.* 8 | /// 9 | /// @access private 10 | /// @group 0_variables 11 | /// 12 | /// @type Map 13 | 14 | $__SCARAB_TOKENS : ( 15 | 'baseline' : 1rem, 16 | 'breakpoint' : (), 17 | 'color' : (), 18 | 'gradient' : (), 19 | 'opacity' : (), 20 | 'background-image' : (), 21 | 'letter-spacing' : (), 22 | 'line-height' : (), 23 | 'font-family' : (), 24 | 'font-size' : (), 25 | 'font-weight' : (), 26 | 'line-style' : (), 27 | 'line-width' : (), 28 | 'text-measure' : (), 29 | 'wrapper-width' : (), 30 | 'spacing' : (), 31 | 'coordinate' : (), 32 | 'flex-grid' : (), 33 | 'ratio' : (), 34 | 'angle' : (), 35 | 'duration' : (), 36 | 'easing' : (), 37 | 'border-radius' : (), 38 | 'box-shadow' : (), 39 | 'text-shadow' : (), 40 | 'keyframe' : (), 41 | 'module' : () 42 | ); 43 | 44 | // Merge into $__SCARAB 45 | $__SCARAB: map-merge($__SCARAB, ('TOKENS': $__SCARAB_TOKENS)); 46 | $__SCARAB_TOKENS: null; 47 | -------------------------------------------------------------------------------- /lib/tokens/get.scss: -------------------------------------------------------------------------------- 1 | /// Returns the value of a token. 2 | /// 3 | /// @group 3_tokens 4 | /// 5 | /// @requires {variable} __SCARAB 6 | /// @requires {function} to-string 7 | /// 8 | /// @param {ArgList} $path - Path to the token 9 | /// 10 | /// @return {*} - Token value 11 | /// 12 | /// @example 13 | /// @include set(breakpoint, ( 14 | /// small : 600px, 15 | /// medium : 1024px, 16 | /// large : 1300px, 17 | /// huge : 1600px 18 | /// ) ); 19 | /// 20 | /// get(breakpoint, small) 21 | /// // => 600px 22 | /// 23 | /// get(breakpoint) 24 | /// // => ( 25 | /// // small : 600px, 26 | /// // medium : 1024px, 27 | /// // large : 1300px, 28 | /// // huge : 1600px 29 | /// // ) 30 | 31 | @function get($path...) { 32 | $result: map-get($__SCARAB, 'TOKENS'); 33 | 34 | @each $key in $path { 35 | $result: map-get($result, to-string($key)); 36 | } 37 | 38 | @return $result; 39 | } 40 | -------------------------------------------------------------------------------- /lib/tokens/helpers/_.scss: -------------------------------------------------------------------------------- 1 | //// 2 | /// Token Helpers 3 | /// 4 | /// Helper functions for retrieving values in the stylesheet tokens. 5 | //// 6 | 7 | @import 'baseline'; 8 | @import 'breakpoint'; 9 | @import 'color'; 10 | @import 'gradient'; 11 | @import 'opacity'; 12 | @import 'background-image'; 13 | @import 'letter-spacing'; 14 | @import 'line-height'; 15 | @import 'font-family'; 16 | @import 'font-size'; 17 | @import 'font-weight'; 18 | @import 'line-style'; 19 | @import 'line-width'; 20 | @import 'text-measure'; 21 | @import 'wrapper-width'; 22 | @import 'flex-grid'; 23 | @import 'spacing'; 24 | @import 'coordinate'; 25 | @import 'ratio'; 26 | @import 'angle'; 27 | @import 'duration'; 28 | @import 'easing'; 29 | @import 'border-radius'; 30 | @import 'box-shadow'; 31 | @import 'text-shadow'; 32 | @import 'keyframe'; 33 | @import 'module'; 34 | -------------------------------------------------------------------------------- /lib/tokens/helpers/angle.scss: -------------------------------------------------------------------------------- 1 | /// Returns the value of an angle token. 2 | /// 3 | /// @group 4_token-helpers 4 | /// 5 | /// @requires {function} get 6 | /// 7 | /// @param {String} $path - Path to the token 8 | /// 9 | /// @return {*} 10 | 11 | @function angle($path...) { 12 | $result: get(angle, $path...); 13 | @return $result; 14 | } 15 | -------------------------------------------------------------------------------- /lib/tokens/helpers/background-image.scss: -------------------------------------------------------------------------------- 1 | /// Returns the value of a background image token. 2 | /// 3 | /// **Aliases** 4 | /// - `@function bgi()` 5 | /// 6 | /// @group 4_token-helpers 7 | /// 8 | /// @requires {function} get 9 | /// 10 | /// @param {String} $path - Path to the token 11 | /// 12 | /// @return {*} 13 | 14 | @function background-image($path...) { 15 | $result: get(background-image, $path...); 16 | @return $result; 17 | } 18 | 19 | 20 | 21 | /// @group 4_token-helpers 22 | /// @alias background-image 23 | 24 | @function bgi($args...) { 25 | @return background-image($args...); 26 | } 27 | -------------------------------------------------------------------------------- /lib/tokens/helpers/baseline.scss: -------------------------------------------------------------------------------- 1 | /// Returns a multiple of the global typographic baseline value. 2 | /// 3 | /// **Aliases** 4 | /// - `@function bl()` 5 | /// 6 | /// @group 4_token-helpers 7 | /// 8 | /// @requires {function} get 9 | /// 10 | /// @param {Number} $multiplier [1] - Baseline multiplier 11 | /// 12 | /// @return {Number} - Unit depends on the baseline value 13 | /// 14 | /// @example 15 | /// @include set(baseline, 1rem); 16 | /// 17 | /// baseline(2) 18 | /// // => 2rem 19 | /// 20 | /// bl(2.5) 21 | /// // => 2.5rem 22 | 23 | @function baseline($multiplier: 1) { 24 | $result: get(baseline) * $multiplier; 25 | @return $result; 26 | } 27 | 28 | 29 | 30 | /// @group 4_token-helpers 31 | /// @alias baseline 32 | 33 | @function bl($args...) { 34 | @return baseline($args...); 35 | } 36 | -------------------------------------------------------------------------------- /lib/tokens/helpers/border-radius.scss: -------------------------------------------------------------------------------- 1 | /// Returns the value of a border-radius token. 2 | /// 3 | /// **Aliases** 4 | /// - `@function radius()` 5 | /// - `@function bdr()` 6 | /// 7 | /// @group 4_token-helpers 8 | /// 9 | /// @requires {function} get 10 | /// 11 | /// @param {String} $path - Path to the token 12 | /// @return {*} 13 | 14 | @function border-radius($path...) { 15 | $result: get(border-radius, $path...); 16 | @return $result; 17 | } 18 | 19 | 20 | /// @group 4_token-helpers 21 | /// @alias border-radius 22 | 23 | @function bdr($args...) { 24 | @return border-radius($args...); 25 | } 26 | 27 | 28 | 29 | /// @group 4_token-helpers 30 | /// @alias border-radius 31 | 32 | @function radius($args...) { 33 | @return border-radius($args...); 34 | } 35 | -------------------------------------------------------------------------------- /lib/tokens/helpers/box-shadow.scss: -------------------------------------------------------------------------------- 1 | /// Returns the value of a box-shadow token. 2 | /// 3 | /// **Aliases** 4 | /// - `@function bsh()` 5 | /// 6 | /// @group 4_token-helpers 7 | /// 8 | /// @requires {function} get 9 | /// 10 | /// @param {String} $path - Path to the token 11 | /// @return {*} 12 | 13 | @function box-shadow($path...) { 14 | $result: get(box-shadow, $path...); 15 | @return $result; 16 | } 17 | 18 | 19 | 20 | /// @group 4_token-helpers 21 | /// @alias box-shadow 22 | 23 | @function bsh($args...) { 24 | @return box-shadow($args...); 25 | } 26 | -------------------------------------------------------------------------------- /lib/tokens/helpers/breakpoint.scss: -------------------------------------------------------------------------------- 1 | /// Returns the value of a breakpoint token. 2 | /// 3 | /// **Aliases** 4 | /// - `@function bp()` 5 | /// 6 | /// @group 4_token-helpers 7 | /// 8 | /// @requires {function} get 9 | /// 10 | /// @param {String} $path - Path to the token 11 | /// @return {*} 12 | 13 | @function breakpoint($path...) { 14 | $result: get(breakpoint, $path...); 15 | @return $result; 16 | } 17 | 18 | 19 | 20 | /// @group 4_token-helpers 21 | /// @alias breakpoint 22 | 23 | @function bp($args...) { 24 | @return breakpoint($args...); 25 | } 26 | -------------------------------------------------------------------------------- /lib/tokens/helpers/color.scss: -------------------------------------------------------------------------------- 1 | /// Returns the value of a color token. 2 | /// 3 | /// **Aliases** 4 | /// - `@function c()` 5 | /// - `@function palette()` 6 | /// 7 | /// @group 4_token-helpers 8 | /// 9 | /// @requires {function} get 10 | /// 11 | /// @param {String} $path - Path to the token 12 | /// @return {*} 13 | 14 | @function color($path...) { 15 | $result: get(color, $path...); 16 | 17 | @if type-of($result) == 'map' { 18 | $result: map-get($result, option(namescheme, default-key)); 19 | } 20 | 21 | @return $result; 22 | } 23 | 24 | 25 | 26 | /// @group 4_token-helpers 27 | /// @alias color 28 | 29 | @function c($args...) { 30 | @return color($args...); 31 | } 32 | -------------------------------------------------------------------------------- /lib/tokens/helpers/coordinate.scss: -------------------------------------------------------------------------------- 1 | /// Returns the value of a coordinate token. 2 | /// 3 | /// **Aliases** 4 | /// - `@function coord()` 5 | /// 6 | /// @group 4_token-helpers 7 | /// 8 | /// @requires {function} get 9 | /// 10 | /// @param {String} $path - Path to the token 11 | /// @return {*} 12 | 13 | @function coordinate($path...) { 14 | $result: get(coordinate, $path...); 15 | @return $result; 16 | } 17 | 18 | 19 | 20 | /// @group 4_token-helpers 21 | /// @alias coordinate 22 | 23 | @function coord($args...) { 24 | @return coordinate($args...); 25 | } 26 | 27 | -------------------------------------------------------------------------------- /lib/tokens/helpers/duration.scss: -------------------------------------------------------------------------------- 1 | /// Returns the value of a duration token. 2 | /// 3 | /// **Aliases** 4 | /// - `@function dur()` 5 | /// 6 | /// @group 4_token-helpers 7 | /// 8 | /// @requires {function} get 9 | /// 10 | /// @param {String} $path - Path to the token 11 | /// @return {*} 12 | 13 | @function duration($path...) { 14 | $result: get(duration, $path...); 15 | @return $result; 16 | } 17 | 18 | 19 | 20 | /// @group 4_token-helpers 21 | /// @alias duration 22 | 23 | @function dur($args...) { 24 | @return duration($args...); 25 | } 26 | -------------------------------------------------------------------------------- /lib/tokens/helpers/easing.scss: -------------------------------------------------------------------------------- 1 | /// Returns the value of an easing token. 2 | /// 3 | /// **Aliases** 4 | /// - `@function ease()` 5 | /// 6 | /// @group 4_token-helpers 7 | /// 8 | /// @requires {function} get 9 | /// 10 | /// @param {String} $path - Path to the token 11 | /// @return {*} 12 | 13 | @function easing($path...) { 14 | $result: get(easing, $path...); 15 | @return $result; 16 | } 17 | 18 | 19 | 20 | /// @group 4_token-helpers 21 | /// @alias easing 22 | 23 | @function ease($args...) { 24 | @return easing($args...); 25 | } 26 | -------------------------------------------------------------------------------- /lib/tokens/helpers/flex-grid.scss: -------------------------------------------------------------------------------- 1 | /// Returns the value of a flex-grid token. 2 | /// 3 | /// @group 4_token-helpers 4 | /// 5 | /// @requires {function} get 6 | /// 7 | /// @param {String} $path - Path to the token 8 | /// @return {*} 9 | 10 | @function flex-grid($path...) { 11 | $result: get(flex-grid, $path...); 12 | @return $result; 13 | } 14 | -------------------------------------------------------------------------------- /lib/tokens/helpers/font-family.scss: -------------------------------------------------------------------------------- 1 | /// Returns the value of a font family token. 2 | /// 3 | /// **Aliases** 4 | /// - `@function ff()` 5 | /// - `@function typeface()` 6 | /// 7 | /// @group 4_token-helpers 8 | /// 9 | /// @requires {function} get 10 | /// 11 | /// @param {String} $path - Path to the token 12 | /// @return {*} 13 | 14 | @function font-family($path...) { 15 | $result: get(font-family, $path...); 16 | @return $result; 17 | } 18 | 19 | 20 | 21 | /// @group 4_token-helpers 22 | /// @alias font-family 23 | 24 | @function ff($args...) { 25 | @return font-family($args...); 26 | } 27 | 28 | 29 | 30 | /// @group 4_token-helpers 31 | /// @alias font-family 32 | 33 | @function typeface($args...) { 34 | @return font-family($args...); 35 | } 36 | -------------------------------------------------------------------------------- /lib/tokens/helpers/font-size.scss: -------------------------------------------------------------------------------- 1 | /// Returns the value of a font size token. 2 | /// 3 | /// **Aliases** 4 | /// - `@function fz()` 5 | /// 6 | /// @group 4_token-helpers 7 | /// 8 | /// @requires {function} get 9 | /// 10 | /// @param {String} $path - Path to the token 11 | /// @return {*} 12 | 13 | @function font-size($path...) { 14 | $result: get(font-size, $path...); 15 | @return $result; 16 | } 17 | 18 | 19 | 20 | /// @group 4_token-helpers 21 | /// @alias font-size 22 | 23 | @function fz($args...) { 24 | @return font-size($args...); 25 | } 26 | -------------------------------------------------------------------------------- /lib/tokens/helpers/font-weight.scss: -------------------------------------------------------------------------------- 1 | /// Returns the value of a font weight token. 2 | /// 3 | /// **Aliases** 4 | /// - `@function fw()` 5 | /// 6 | /// @group 4_token-helpers 7 | /// 8 | /// @requires {function} get 9 | /// 10 | /// @param {String} $path - Path to the token 11 | /// @return {*} 12 | 13 | @function font-weight($path...) { 14 | $result: get(font-weight, $path...); 15 | @return $result; 16 | } 17 | 18 | 19 | 20 | /// @group 4_token-helpers 21 | /// @alias font-weight 22 | 23 | @function fw($args...) { 24 | @return font-weight($args...); 25 | } 26 | -------------------------------------------------------------------------------- /lib/tokens/helpers/gradient.scss: -------------------------------------------------------------------------------- 1 | /// Returns the value of a gradient token. 2 | /// 3 | /// **Aliases** 4 | /// - `@function g()` 5 | /// 6 | /// @group 4_token-helpers 7 | /// 8 | /// @requires {function} get 9 | /// 10 | /// @param {String} $path - Path to the token 11 | /// @return {*} 12 | 13 | @function gradient($path...) { 14 | $result: get(gradient, $path...); 15 | @return $result; 16 | } 17 | 18 | 19 | 20 | /// @group 4_token-helpers 21 | /// @alias gradient 22 | 23 | @function g($args...) { 24 | @return gradient($args...); 25 | } 26 | -------------------------------------------------------------------------------- /lib/tokens/helpers/keyframe.scss: -------------------------------------------------------------------------------- 1 | /// Returns the value of a keyframe token. 2 | /// 3 | /// @group 4_token-helpers 4 | /// 5 | /// @requires {function} get 6 | /// 7 | /// @param {String} $path - Path to the token 8 | /// @return {*} 9 | 10 | @function keyframe($path...) { 11 | $result: get(keyframe, $path...); 12 | @return $result; 13 | } 14 | -------------------------------------------------------------------------------- /lib/tokens/helpers/letter-spacing.scss: -------------------------------------------------------------------------------- 1 | /// Returns the value of a letter spacing token. 2 | /// 3 | /// **Aliases** 4 | /// - `@function ls()` 5 | /// - `@function tracking()` 6 | /// 7 | /// @group 4_token-helpers 8 | /// 9 | /// @requires {function} get 10 | /// 11 | /// @param {String} $path - Path to the token 12 | /// @return {*} 13 | 14 | @function letter-spacing($path...) { 15 | $result: get(letter-spacing, $path...); 16 | @return $result; 17 | } 18 | 19 | 20 | 21 | /// @group 4_token-helpers 22 | /// @alias letter-spacing 23 | 24 | @function ls($args...) { 25 | @return letter-spacing($args...); 26 | } 27 | 28 | 29 | 30 | /// @group 4_token-helpers 31 | /// @alias letter-spacing 32 | 33 | @function tracking($args...) { 34 | @return letter-spacing($args...); 35 | } 36 | -------------------------------------------------------------------------------- /lib/tokens/helpers/line-height.scss: -------------------------------------------------------------------------------- 1 | /// Returns the value of a line height token. 2 | /// 3 | /// **Aliases** 4 | /// - `@function lh()` 5 | /// - `@function leading()` 6 | /// 7 | /// @group 4_token-helpers 8 | /// 9 | /// @requires {function} get 10 | /// 11 | /// @param {String} $path - Path to the token 12 | /// @return {*} 13 | 14 | @function line-height($path...) { 15 | $result: get(line-height, $path...); 16 | @return $result; 17 | } 18 | 19 | 20 | 21 | /// @group 4_token-helpers 22 | /// @alias line-height 23 | 24 | @function lh($args...) { 25 | @return line-height($args...); 26 | } 27 | 28 | 29 | 30 | /// @group 4_token-helpers 31 | /// @alias line-height 32 | 33 | @function leading($args...) { 34 | @return line-height($args...); 35 | } 36 | -------------------------------------------------------------------------------- /lib/tokens/helpers/line-style.scss: -------------------------------------------------------------------------------- 1 | /// Returns the value of a line style token. 2 | /// 3 | /// **Aliases** 4 | /// - `@function c()` 5 | /// - `@function palette()` 6 | /// 7 | /// @group 4_token-helpers 8 | /// 9 | /// @requires {function} get 10 | /// 11 | /// @param {String} $path - Path to the token 12 | /// @return {*} 13 | 14 | @function line-style($path...) { 15 | $result: get(line-style, $path...); 16 | @return $result; 17 | } 18 | 19 | 20 | 21 | /// @group 4_token-helpers 22 | /// @alias line-style 23 | 24 | @function lns($args...) { 25 | @return line-style($args...); 26 | } 27 | 28 | -------------------------------------------------------------------------------- /lib/tokens/helpers/line-width.scss: -------------------------------------------------------------------------------- 1 | /// Returns the value of a line width token. 2 | /// 3 | /// **Aliases** 4 | /// - `@function lnw()` 5 | /// 6 | /// @group 4_token-helpers 7 | /// 8 | /// @requires {function} get 9 | /// 10 | /// @param {String} $path - Path to the token 11 | /// @return {*} 12 | 13 | @function line-width($path...) { 14 | $result: get(line-width, $path...); 15 | @return $result; 16 | } 17 | 18 | 19 | 20 | /// @group 4_token-helpers 21 | /// @alias line-width 22 | 23 | @function lnw($args...) { 24 | @return line-width($args...); 25 | } 26 | 27 | -------------------------------------------------------------------------------- /lib/tokens/helpers/module.scss: -------------------------------------------------------------------------------- 1 | /// Returns the value of a module token. 2 | /// 3 | /// @group 4_token-helpers 4 | /// 5 | /// @requires {function} get 6 | /// 7 | /// @param {String} $path - Path to the token 8 | /// @return {*} 9 | 10 | @function module($path...) { 11 | $result: get(module, $path...); 12 | @return $result; 13 | } 14 | -------------------------------------------------------------------------------- /lib/tokens/helpers/opacity.scss: -------------------------------------------------------------------------------- 1 | /// Returns the value of an opacity token. 2 | /// 3 | /// 4 | /// **Aliases** 5 | /// - `@function o()` 6 | /// 7 | /// @group 4_token-helpers 8 | /// 9 | /// @requires {function} get 10 | /// 11 | /// @param {String} $path - Path to the token 12 | /// @return {*} 13 | 14 | @function opacity($path...) { 15 | $result: get(opacity, $path...); 16 | @return $result; 17 | } 18 | 19 | 20 | 21 | /// @group 4_token-helpers 22 | /// @alias opacity 23 | 24 | @function o($args...) { 25 | @return opacity($args...); 26 | } 27 | -------------------------------------------------------------------------------- /lib/tokens/helpers/ratio.scss: -------------------------------------------------------------------------------- 1 | /// Returns the value of an aspect ratio token. 2 | /// 3 | /// @group 4_token-helpers 4 | /// 5 | /// @requires {function} get 6 | /// 7 | /// @param {String} $path - Path to the token 8 | /// @return {*} 9 | 10 | @function ratio($path...) { 11 | $result: get(ratio, $path...); 12 | @return $result; 13 | } 14 | -------------------------------------------------------------------------------- /lib/tokens/helpers/spacing.scss: -------------------------------------------------------------------------------- 1 | /// Returns the value of a spacing token. 2 | /// 3 | /// **Aliases** 4 | /// - `@function s()` 5 | /// 6 | /// @group 4_token-helpers 7 | /// 8 | /// @requires {function} get 9 | /// 10 | /// @param {String} $path - Path to the token 11 | /// @return {*} 12 | 13 | @function spacing($path...) { 14 | $result: get(spacing, $path...); 15 | @return $result; 16 | } 17 | 18 | 19 | 20 | /// @group 4_token-helpers 21 | /// @alias spacing 22 | 23 | @function s($args...) { 24 | @return spacing($args...); 25 | } 26 | 27 | -------------------------------------------------------------------------------- /lib/tokens/helpers/text-measure.scss: -------------------------------------------------------------------------------- 1 | /// Returns the value of a text measure token. 2 | /// 3 | /// **Aliases** 4 | /// - `@function measure()` 5 | /// 6 | /// @group 4_token-helpers 7 | /// 8 | /// @requires {function} get 9 | /// 10 | /// @param {String} $path - Path to the token 11 | /// @return {*} 12 | 13 | @function text-measure($path...) { 14 | $result: get(text-measure, $path...); 15 | @return $result; 16 | } 17 | 18 | 19 | 20 | /// @group 4_token-helpers 21 | /// @alias text-measure 22 | 23 | @function measure($args...) { 24 | @return text-measure($args...); 25 | } 26 | -------------------------------------------------------------------------------- /lib/tokens/helpers/text-shadow.scss: -------------------------------------------------------------------------------- 1 | /// Returns the value of a text-shadow token. 2 | /// 3 | /// **Aliases** 4 | /// - `@function tsh()` 5 | /// 6 | /// @group 4_token-helpers 7 | /// 8 | /// @requires {function} get 9 | /// 10 | /// @param {String} $path - Path to the token 11 | /// @return {*} 12 | 13 | @function text-shadow($path...) { 14 | $result: get(text-shadow, $path...); 15 | @return $result; 16 | } 17 | 18 | 19 | 20 | /// @group 4_token-helpers 21 | /// @alias text-shadow 22 | 23 | @function tsh($args...) { 24 | @return text-shadow($args...); 25 | } 26 | -------------------------------------------------------------------------------- /lib/tokens/helpers/wrapper-width.scss: -------------------------------------------------------------------------------- 1 | /// Returns the value of a wrapper width token. 2 | /// 3 | /// **Aliases** 4 | /// - `@function wrap()` 5 | /// 6 | /// @group 4_token-helpers 7 | /// 8 | /// @requires {function} get 9 | /// 10 | /// @param {String} $path - Path to the token 11 | /// @return {*} 12 | 13 | @function wrapper-width($path...) { 14 | $result: get(wrapper-width, $path...); 15 | @return $result; 16 | } 17 | 18 | 19 | 20 | /// @group 4_token-helpers 21 | /// @alias wrapper-width 22 | 23 | @function wrap($args...) { 24 | @return wrapper-width($args...); 25 | } 26 | -------------------------------------------------------------------------------- /lib/tokens/set-default.scss: -------------------------------------------------------------------------------- 1 | /// Sets a default value for a key in the stylesheet tokens. 2 | /// 3 | /// @group 3_tokens 4 | /// 5 | /// @requires {variable} __SCARAB 6 | /// @requires {function} set 7 | /// @requires {function} to-string 8 | /// 9 | /// @param {ArgList} $definition - Definition of the default value 10 | /// 11 | /// @return {ArgList} - Definition of the default value 12 | /// 13 | /// @example 14 | /// // Sets a default value 15 | /// $_: set-default(baseline, 1rem); 16 | /// 17 | /// get(baseline) 18 | /// // => 1rem 19 | /// 20 | /// // Updates the value 21 | /// $_: set(baseline, 1.25rem); 22 | /// 23 | /// get(baseline) 24 | /// // => 1.25rem 25 | /// 26 | /// // Doesn't update the value since it already exists 27 | /// $_: set-default(baseline, 1rem); 28 | /// 29 | /// get(baseline) 30 | /// // => 1.25rem 31 | 32 | @function set-default($definition...) { 33 | 34 | // Get a copy of the current $TOKENS state 35 | $TOKENS: map-get($__SCARAB, 'TOKENS'); 36 | 37 | // Check if the key exists to determine whether to set the new value 38 | $key-exists: true; 39 | 40 | @if length($definition) == 2 { 41 | $key: nth($definition, 1); 42 | 43 | @if not map-has-key($TOKENS, to-string($key)) { 44 | $key-exists: false; 45 | } 46 | } 47 | 48 | @else if length($definition) > 2 { 49 | $current-map: $TOKENS; 50 | 51 | @for $i from 1 through length($definition) - 1 { 52 | $current-key: nth($definition, $i); 53 | 54 | @if not map-has-key($current-map, to-string($current-key)) { 55 | $key-exists: false; 56 | } @else { 57 | $current-map: map-get($current-map, to-string($current-key)); 58 | } 59 | } 60 | } 61 | 62 | @if not $key-exists { 63 | $_: set($definition...); 64 | } 65 | 66 | @return $definition; 67 | 68 | } 69 | 70 | 71 | /// Calls `set-default` 72 | /// 73 | /// @group 3_tokens 74 | /// 75 | /// @requires {function} set-default 76 | /// 77 | /// @param {ArgList} $args - Args for `set-default` 78 | /// 79 | /// @example 80 | /// // Sets a default value 81 | /// @include set-default(baseline, 1rem); 82 | /// 83 | /// get(baseline) 84 | /// // => 1rem 85 | /// 86 | /// // Updates the value 87 | /// @include set(baseline, 1.25rem); 88 | /// 89 | /// get(baseline) 90 | /// // => 1.25rem 91 | /// 92 | /// // Doesn't update the value since it already exists 93 | /// @include set-default(baseline, 1rem); 94 | /// 95 | /// get(baseline) 96 | /// // => 1.25rem 97 | 98 | @mixin set-default($args...) { 99 | $_: set-default($args...); 100 | } 101 | -------------------------------------------------------------------------------- /lib/tokens/set.scss: -------------------------------------------------------------------------------- 1 | /// Sets or updates a value of a key in the stylesheet tokens. 2 | /// 3 | /// @group 3_tokens 4 | /// 5 | /// @requires {variable} __SCARAB 6 | /// @requires {function} to-string 7 | /// @requires {function} map-stringify-keys-deep 8 | /// 9 | /// @param {ArgList} $definition - Definition of the new value 10 | /// 11 | /// @return {ArgList} - Definition of the new value 12 | /// 13 | /// @example 14 | /// $_: set(baseline, 1.25rem); 15 | /// 16 | /// $_: set(breakpoint, ( 17 | /// s : 600px, 18 | /// m : 1024px, 19 | /// l : 1300px, 20 | /// xl : 1600px 21 | /// )); 22 | /// 23 | /// get(baseline) 24 | /// // => 1.25rem 25 | /// 26 | /// get(breakpoint) 27 | /// // => ( 28 | /// // small : 600px, 29 | /// // medium : 1024px, 30 | /// // large : 1300px, 31 | /// // huge : 1600px 32 | /// // ) 33 | /// 34 | /// get(breakpoints, small) 35 | /// // => 600px 36 | /// 37 | /// @todo Improve performance by optimizing `map-stringify-keys-deep` 38 | 39 | @function set($definition...) { 40 | 41 | // Get a copy of the current $TOKENS state 42 | $TOKENS: map-get($__SCARAB, 'TOKENS'); 43 | 44 | $result: (); // key-value pair that will be merged with $TOKENS 45 | 46 | // If there are only 2 args, we can easily determine the result 47 | @if length($definition) == 2 { 48 | $key : nth($definition, 1); 49 | $new-value : nth($definition, 2); 50 | 51 | $result: ($key: $new-value); 52 | } 53 | 54 | // For more than 2 args, we have to build the result backwards 55 | @if length($definition) > 2 { 56 | 57 | // The new value is the last arg in $definition 58 | $new-value: nth($definition, -1); 59 | 60 | // Build a list of maps preceding the new one 61 | $maps: ($TOKENS,); 62 | 63 | @for $i from 1 through length($definition) - 2 { 64 | $current-map : nth($maps, -1); 65 | $current-key : nth($definition, $i); 66 | $current-value : map-get($current-map, to-string($current-key)) or (); 67 | 68 | $maps: append($maps, $current-value); 69 | } 70 | 71 | @for $i from length($maps) through 1 { 72 | $current-map : nth($maps, $i); 73 | $current-key : nth($definition, $i); 74 | $current-value : (); 75 | 76 | @if $i == length($maps) { 77 | $current-value: $new-value; 78 | } @else { 79 | $current-value: $result; 80 | } 81 | 82 | $result: map-merge($current-map, (to-string($current-key): $current-value)); 83 | } 84 | } 85 | 86 | // Update the local $TOKENS map 87 | $TOKENS: map-merge($TOKENS, map-stringify-keys-deep($result)); 88 | 89 | // Merge the updated $TOKENS map back into $__SCARAB 90 | $__SCARAB: map-merge($__SCARAB, ('TOKENS': $TOKENS)) !global; 91 | @return $definition; 92 | 93 | } 94 | 95 | 96 | 97 | /// Calls `set` 98 | /// 99 | /// @group 3_tokens 100 | /// 101 | /// @requires {function} set 102 | /// 103 | /// @param {ArgList} $args - Args for `set` 104 | /// 105 | /// @example 106 | /// @include set(baseline, 1.25rem); 107 | /// 108 | /// @include set(breakpoints, ( 109 | /// s : 600px, 110 | /// m : 1024px, 111 | /// l : 1300px, 112 | /// xl : 1600px 113 | /// )); 114 | /// 115 | /// @debug get(baseline); // 1.25rem 116 | /// 117 | /// @debug get(breakpoints); 118 | /// // => ( 119 | /// // small : 600px, 120 | /// // medium : 1024px, 121 | /// // large : 1300px, 122 | /// // huge : 1600px 123 | /// // ) 124 | /// 125 | /// @debug get(breakpoints, small); // 600px 126 | 127 | @mixin set($args...) { 128 | $_: set($args...); 129 | } 130 | -------------------------------------------------------------------------------- /lib/tokens/unset.scss: -------------------------------------------------------------------------------- 1 | /// Removes a key-value pair from the stylesheet tokens. 2 | /// 3 | /// @group 3_tokens 4 | /// 5 | /// @requires {variable} __SCARAB 6 | /// @requires {function} set 7 | /// @requires {function} list-each 8 | /// @requires {function} list-remove 9 | /// 10 | /// @param {ArgList} $path - Path to the key to remove 11 | /// 12 | /// @return {ArgList} - Path to the key to remove 13 | /// 14 | /// @example 15 | /// $_: set(breakpoint, ( 16 | /// small : 600px, 17 | /// medium : 1024px, 18 | /// large : 1300px, 19 | /// huge : 1600px 20 | /// ) ); 21 | /// 22 | /// $_: unset(breakpoint, medium); 23 | /// 24 | /// @debug get(breakpoint); 25 | /// // => ( 26 | /// // small : 600px, 27 | /// // large : 1300px, 28 | /// // huge : 1600px 29 | /// // ) 30 | 31 | @function unset($path...) { 32 | 33 | // Get a copy of the current $TOKENS state 34 | $TOKENS: map-get($__SCARAB, 'TOKENS'); 35 | 36 | @if length($path) == 1 { 37 | $key: nth($path, 1); 38 | 39 | $TOKENS: map-remove($TOKENS, to-string($key)); 40 | $__SCARAB: map-merge($__SCARAB, ('TOKENS': $TOKENS)) !global; 41 | } 42 | 43 | @else if length($path) > 1 { 44 | $path : list-each($path, to-string); 45 | $last-key : nth($path, -1); 46 | $key-address : list-remove($path, $last-key); 47 | $last-map : map-remove(get($key-address...), $last-key); 48 | $definition : (); 49 | 50 | @each $key in $key-address { 51 | $definition: append($definition, $key); 52 | } 53 | 54 | $definition: append($definition, $last-map); 55 | 56 | $_: set($definition...); 57 | } 58 | 59 | @return $path; 60 | 61 | } 62 | 63 | 64 | 65 | /// Calls `unset` 66 | /// 67 | /// @group 3_tokens 68 | /// 69 | /// @requires {function} unset 70 | /// 71 | /// @param {ArgList} $args - Args for `unset` 72 | /// 73 | /// @example 74 | /// @include set(breakpoint, ( 75 | /// small : 600px, 76 | /// medium : 1024px, 77 | /// large : 1300px, 78 | /// huge : 1600px 79 | /// ) ); 80 | /// 81 | /// @include unset(breakpoint, medium); 82 | /// 83 | /// @debug get(breakpoint); 84 | /// // ( 85 | /// // small : 600px, 86 | /// // large : 1300px, 87 | /// // huge : 1600px 88 | /// // ) 89 | 90 | @mixin unset($args...) { 91 | $_: unset($args...); 92 | } 93 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@scarab/core", 3 | "version": "7.0.0-rc.7", 4 | "description": "Sass library for rapid stylesheet development", 5 | "keywords": [ 6 | "sass", 7 | "scss", 8 | "design tokens", 9 | "library", 10 | "helpers", 11 | "mixins", 12 | "responsive", 13 | "front-end" 14 | ], 15 | "main": "_.scss", 16 | "scripts": { 17 | "start": "onchange \"lib/**/*\" \"test/**/*\" \"*.scss\" -- npm test || true", 18 | "watch:mocha": "onchange \"lib/**/*\" \"test/**/*\" \"*.scss\" -- npm run test", 19 | "watch:node": "onchange \"lib/**/*\" \"test/**/*\" \"*.scss\" -- npm run test:node", 20 | "watch:ruby": "onchange \"lib/**/*\" \"test/**/*\" \"*.scss\" -- npm run test:ruby", 21 | "watch:sassdoc": "onchange \"lib/**/*\" \"test/**/*\" \"*.scss\" -- npm run build-sassdoc", 22 | "test:node": "clrscr && node-sass --include-path node_modules test/tests.scss || true", 23 | "test:ruby": "clrscr && sass -I node_modules test/tests.scss || true", 24 | "test": "mocha", 25 | "build": "node-sass --include-path node_modules scarab.scss -o build/", 26 | "build-sassdoc": "clrscr && sassdoc ./ --config sassdoc.yaml" 27 | }, 28 | "author": "Kyle Oliveiro ", 29 | "license": "BSD-3-Clause", 30 | "repository": { 31 | "type": "git", 32 | "url": "https://github.com/kyleoliveiro/scarab-core" 33 | }, 34 | "devDependencies": { 35 | "clrscr": "^1.0.4", 36 | "mocha": "^4.1.0", 37 | "node-sass": "^4.9.4", 38 | "onchange": "^3.3.0", 39 | "sass-true": "^3.1.0", 40 | "sassdoc": "^2.5.1" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /sache.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@scarab/core", 3 | "description": "Sass library for rapid stylesheet development", 4 | "tags": ["design tokens", "design system", "library", "framework", "utilities", "helpers", "responsive", "functions", "mixins", "variables"] 5 | } 6 | -------------------------------------------------------------------------------- /sassdoc.yaml: -------------------------------------------------------------------------------- 1 | dest: ./sassdoc 2 | display: 3 | alias: false 4 | watermark: false 5 | exclude: 6 | - node_modules/**/* 7 | - build/**/* 8 | - test/**/* 9 | - docs/**/* 10 | groups: 11 | 0_variables: Variables 12 | 1_options: Options 13 | 2_constants: Constants 14 | 3_tokens: Stylesheet tokens 15 | 4_token-helpers: Token helpers 16 | 5_functions: Pure functions 17 | 6_mixins: Mixins 18 | verbose: true 19 | basePath: https://github.com/kyleoliveiro/scarab-core/tree/master 20 | googleAnalytics: UA-106098263-1 21 | -------------------------------------------------------------------------------- /scarab-logo.svg: -------------------------------------------------------------------------------- 1 | Asset 5 -------------------------------------------------------------------------------- /test/constants/_.scss: -------------------------------------------------------------------------------- 1 | @import 'const'; 2 | @import 'define'; 3 | 4 | // Reset $__SCARAB 5 | @import '../../lib/options/_init'; 6 | @import '../../lib/constants/_init'; 7 | @import '../../lib/tokens/_init'; 8 | -------------------------------------------------------------------------------- /test/constants/const.scss: -------------------------------------------------------------------------------- 1 | @include describe('const [func]') { 2 | 3 | @include it('Returns a value from the `CONSTANTS` map') { 4 | $__SCARAB: ( 5 | 'TOKENS': (), 6 | 'CONSTANTS': ( 7 | 'c' : 299792458, 8 | 'g' : 9.80665, 9 | 'e' : 2.71828182845904523536028747135266249775724709369995, 10 | 'pi' : 3.1415926535897932384626433832795028841971693993751, 11 | 'phi' : 1.6180339887498, 12 | 'ln10' : 2.302585092994046, 13 | 'ln2' : 0.6931471805599453, 14 | 'log10e' : 0.4342944819032518, 15 | 'log2e' : 1.4426950408889634, 16 | 'sqrt1_2' : 0.7071067811865476, 17 | 'sqrt2' : 1.4142135623730951, 18 | 'min_z_index' : -2147483647, 19 | 'max_z_index' : 2147483647, 20 | 'sort_order' : ( 21 | "!" "#" "$" "%" "&" "'" "(" ")" "*" "+" "," "-" "." "/" "[" "\\" "]" "^" 22 | "_" "{" "|" "}" "~" "0" "1" "2" "3" "4" "5" "6" "7" "8" "9" "a" "b" "c" 23 | "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o" "p" "q" "r" "s" "t" "u" 24 | "v" "w" "x" "y" "z" 25 | ), 26 | 'custom' : ( 27 | 'red' : 1 28 | ) 29 | ) 30 | ) !global; 31 | 32 | 33 | @include assert-equal( 34 | const(pi), 35 | 3.1415926535897932384626433832795028841971693993751, 36 | 'Root-level constant' 37 | ); 38 | 39 | @include assert-equal( 40 | const(custom, red), 41 | 1, 42 | 'Nested constant' 43 | ); 44 | 45 | @include assert-equal( 46 | const(custom, 'red'), 47 | 1, 48 | 'Use single quoted keys' 49 | ); 50 | 51 | @include assert-equal( 52 | const(custom, "red"), 53 | 1, 54 | 'Use double quoted keys' 55 | ); 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /test/constants/define.scss: -------------------------------------------------------------------------------- 1 | @include describe('define [func]') { 2 | 3 | @include it('Defines a new constant') { 4 | $__SCARAB: ( 5 | 'CONSTANTS': () 6 | ) !global; 7 | 8 | @include define(custom, 100); 9 | 10 | @include assert-equal( 11 | inspect($__SCARAB), 12 | inspect(( 13 | 'CONSTANTS': ( 14 | 'custom': 100 15 | ) 16 | )) 17 | ); 18 | 19 | 20 | 21 | $__SCARAB: ( 22 | 'CONSTANTS': () 23 | ) !global; 24 | 25 | @include define(custom2, a, blue, 1); 26 | 27 | @include assert-equal( 28 | inspect($__SCARAB), 29 | inspect(( 30 | 'CONSTANTS': ( 31 | 'custom2': ( 32 | 'a': ( 33 | 'blue': 1 34 | ) 35 | ) 36 | ) 37 | )), 38 | 'Defines a nested constant' 39 | ); 40 | 41 | 42 | 43 | $__SCARAB: ( 44 | 'CONSTANTS': ( 45 | 'pi': 3.1415926535897932384626433832795028841971693993751 46 | ) 47 | ) !global; 48 | 49 | @include define(pi, apple); 50 | 51 | @include assert-equal( 52 | inspect($__SCARAB), 53 | inspect(( 54 | 'CONSTANTS': ( 55 | 'pi': 3.1415926535897932384626433832795028841971693993751 56 | ) 57 | )), 58 | 'Fails to define a constant that already exists' 59 | ); 60 | 61 | 62 | 63 | $__SCARAB: ( 64 | 'CONSTANTS': ( 65 | 'custom': ( 66 | 'a': ( 67 | '1': 1, 68 | '2': 2, 69 | '3': 3 70 | ) 71 | ) 72 | ) 73 | ) !global; 74 | 75 | @include define(custom, a, 2, two); 76 | 77 | @include assert-equal( 78 | inspect($__SCARAB), 79 | inspect(( 80 | 'CONSTANTS': ( 81 | 'custom': ( 82 | 'a': ( 83 | '1': 1, 84 | '2': 2, 85 | '3': 3 86 | ) 87 | ) 88 | ) 89 | )), 90 | 'Fails to define a nested constant that already exists' 91 | ); 92 | } 93 | 94 | } 95 | -------------------------------------------------------------------------------- /test/functions/_.scss: -------------------------------------------------------------------------------- 1 | @import 'throw'; 2 | @import 'type-check'; 3 | @import 'get-function-safe'; 4 | @import 'important'; 5 | @import 'is-null'; 6 | @import 'to-string'; 7 | @import 'to-length'; 8 | @import 'to-number'; 9 | @import 'to-negative'; 10 | @import 'unit-strip'; 11 | @import 'unit-convert'; 12 | @import 'class-escape'; 13 | @import 'class-sanitize'; 14 | @import 'class-template'; 15 | @import 'random-color'; 16 | @import 'em'; 17 | @import 'rem'; 18 | @import 'str-compare'; 19 | @import 'str-contains'; 20 | @import 'str-replace'; 21 | @import 'str-remove'; 22 | @import 'str-escape'; 23 | @import 'str-prepend'; 24 | @import 'str-append'; 25 | @import 'list-append'; 26 | @import 'list-contains'; 27 | @import 'list-each'; 28 | @import 'list-prepend'; 29 | @import 'list-remove'; 30 | @import 'list-replace'; 31 | @import 'list-reverse'; 32 | @import 'list-sort'; 33 | @import 'list-unique'; 34 | @import 'list-every'; 35 | @import 'map-append'; 36 | @import 'map-prepend'; 37 | @import 'map-get-key'; 38 | @import 'map-flatten'; 39 | @import 'map-stringify-keys'; 40 | @import 'map-stringify-keys-deep'; 41 | @import 'map-unique'; 42 | @import 'map-each-key'; 43 | @import 'map-each-value'; 44 | 45 | // Reset $__SCARAB 46 | @import '../../lib/options/_init'; 47 | @import '../../lib/constants/_init'; 48 | @import '../../lib/tokens/_init'; 49 | 50 | -------------------------------------------------------------------------------- /test/functions/class-escape.scss: -------------------------------------------------------------------------------- 1 | @include describe('class-escape [func]') { 2 | 3 | @include it('Escapes a class name') { 4 | @include assert-equal( 5 | class-escape('blue'), 6 | 'blue', 7 | 'Returns valid class name as-is' 8 | ); 9 | 10 | @include assert-equal( 11 | class-escape('$cl@ss:*(1)'), 12 | '\\$cl\\@ss\\:\\*\\(1\\)', 13 | 'Escapes special characters' 14 | ); 15 | 16 | @include assert-equal( 17 | class-escape('13lue'), 18 | '\\31 3lue', 19 | 'Escapes class names beginning with a number' 20 | ); 21 | 22 | @include assert-equal( 23 | class-escape('13l++ue!'), 24 | '\\31 3l\\+\\+ue\\!', 25 | 'Escapes special characters and class names beginning with a number' 26 | ); 27 | 28 | @include assert-equal( 29 | class-escape('bl_ u e !'), 30 | 'bl_ue\\!', 31 | 'Removes whitespace in class names' 32 | ); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /test/functions/class-sanitize.scss: -------------------------------------------------------------------------------- 1 | @include describe('class-sanitize [func]') { 2 | 3 | @include it('Removes Scarab template placeholders from a string') { 4 | @include assert-equal( 5 | class-sanitize('{{b}}{{bp}}{{s}}{{sp}}{{rp}}opacity{{rs}}{{vp}}{{v}}--75{{ms}}{{ss}}{{bs}}'), 6 | 'opacity--75' 7 | ); 8 | } 9 | 10 | } 11 | -------------------------------------------------------------------------------- /test/functions/class-template.scss: -------------------------------------------------------------------------------- 1 | @include describe('class-template [func]') { 2 | 3 | @include it('Returns a class template with breakpoint and state placeholders') { 4 | 5 | @include assert-equal( 6 | class-template(('root': 'm')), 7 | '{{b}}{{bp}}{{s}}{{sp}}m{{ss}}{{bs}}', 8 | 'No variant, no modifier' 9 | ); 10 | 11 | @include assert-equal( 12 | class-template(('root': 'm'), 'l'), 13 | '{{b}}{{bp}}{{s}}{{sp}}m-l{{ss}}{{bs}}', 14 | 'With variant, no modifier' 15 | ); 16 | 17 | @include assert-equal( 18 | class-template(('root': 'm'), 'l', '0'), 19 | '{{b}}{{bp}}{{s}}{{sp}}m-l:0{{ss}}{{bs}}', 20 | 'With variant, with modifier' 21 | ); 22 | 23 | @include assert-equal( 24 | class-template(('root': 'm', 'variant-prefix': '**'), 'l', '0'), 25 | '{{b}}{{bp}}{{s}}{{sp}}m**l:0{{ss}}{{bs}}', 26 | 'With variant, with modifier, with custom prefix' 27 | ); 28 | 29 | @include assert-equal( 30 | class-template(( 31 | 'root' : 'm', 32 | 'root-prefix' : '__', 33 | 'root-suffix' : '_!', 34 | 'variant-prefix' : '**', 35 | 'variant-suffix' : ')(', 36 | 'modifier-prefix' : '199', 37 | 'modifier-suffix' : '-+=', 38 | 'selector-format' : '{{b}}{{bp}}{{s}}{{sp}}{{v}}{{vp}}{{vs}}{{rp}}{{r}}{{rs}}{{mp}}{{m}}{{ms}}{{ss}}{{bs}}' 39 | ), 'l', '0'), 40 | '{{b}}{{bp}}{{s}}{{sp}}l**)(__m_!1990-+={{ss}}{{bs}}', 41 | 'With variant, with modifier, with custom prefixes and format' 42 | ); 43 | 44 | } 45 | 46 | } 47 | 48 | -------------------------------------------------------------------------------- /test/functions/em.scss: -------------------------------------------------------------------------------- 1 | @include describe('em [func]') { 2 | 3 | @include it('Converts px to em') { 4 | @include assert-equal( 5 | em(32), 6 | 2em, 7 | 'Default base font size' 8 | ); 9 | 10 | @include assert-equal( 11 | em(32, 10), 12 | 3.2em, 13 | 'Custom base font size' 14 | ); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /test/functions/get-function-safe.scss: -------------------------------------------------------------------------------- 1 | @include describe('get-function-safe [func]') { 2 | 3 | @include it('Safely calls native `get-function` if supported') { 4 | // Expect {func} if `get-function` is supported. 5 | // Otherwise, expect a {string} 6 | @if function-exists('get-function') { 7 | @include assert-equal( 8 | get-function-safe('rgb'), 9 | get-function('rgb'), 10 | 'Current Sass compiler supports `get-function()`' 11 | ); 12 | } @else { 13 | @include assert-equal( 14 | get-function-safe('rgb'), 15 | 'rgb', 16 | 'Current Sass compuler does not support `get-function()`' 17 | ); 18 | } 19 | } 20 | 21 | @include it('Can be used safely with `call()`') { 22 | @include assert-equal( 23 | call(get-function-safe('str-length'), 'hello world'), 24 | 11 25 | ); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /test/functions/important.scss: -------------------------------------------------------------------------------- 1 | @include describe('important [func]') { 2 | 3 | 4 | @include it('Returns returns null when $output is null') { 5 | @include assert-equal( 6 | important(null), 7 | null 8 | ); 9 | } 10 | 11 | @include it('Returns returns null when $output is false') { 12 | @include assert-equal( 13 | important(false), 14 | null 15 | ); 16 | } 17 | 18 | @include it('Returns returns `!important` when $output is true') { 19 | @include assert-equal( 20 | important(true), 21 | '!important' 22 | ); 23 | } 24 | 25 | @include it('Returns returns `!important` when output.important option is true') { 26 | $_: set-option(output, important, true); 27 | 28 | @include assert-equal( 29 | important(), 30 | '!important' 31 | ); 32 | } 33 | 34 | @include it('Returns returns null when output.important option is false') { 35 | $_: set-option(output, important, false); 36 | 37 | @include assert-equal( 38 | important(), 39 | null 40 | ); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /test/functions/is-null.scss: -------------------------------------------------------------------------------- 1 | @include describe('is-null [func]') { 2 | 3 | @include it('Returns whether the specified value is `null`') { 4 | @include assert-true( 5 | is-null(null), 6 | 'Null is null' 7 | ); 8 | 9 | @include assert-false( 10 | is-null(false), 11 | 'false is not null' 12 | ); 13 | 14 | @include assert-false( 15 | is-null(0), 16 | '0 is not null' 17 | ); 18 | 19 | @include assert-false( 20 | is-null(''), 21 | 'Empty string is not null' 22 | ); 23 | 24 | $list: []; 25 | @include assert-false( 26 | is-null($list), 27 | 'Empty list is not null' 28 | ); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /test/functions/list-append.scss: -------------------------------------------------------------------------------- 1 | @include describe('list-append [func]') { 2 | 3 | @include it('Appends a single value to the end of a list') { 4 | @include assert-equal( 5 | list-append(1 2, 3), 6 | (1 2 3), 7 | 'Supports space lists' 8 | ); 9 | 10 | @include assert-equal( 11 | list-append((1, 2), 3), 12 | (1, 2, 3), 13 | 'Supports comma lists' 14 | ); 15 | 16 | @include assert-equal( 17 | list-append([1 2], 3), 18 | [1 2 3], 19 | 'Supports bracketed space lists' 20 | ); 21 | 22 | @include assert-equal( 23 | list-append([1, 2], 3), 24 | [1, 2, 3], 25 | 'Supports bracketed comma lists' 26 | ); 27 | } 28 | 29 | @include it('Appends multiple values to the end of a list') { 30 | @include assert-equal( 31 | list-append(1 2, 3, 4, 5 6), 32 | (1 2 3 4 (5 6)), 33 | 'Supports space lists' 34 | ); 35 | 36 | @include assert-equal( 37 | list-append((1, 2), 3, 4, (5, 6)), 38 | (1, 2, 3, 4, (5, 6)), 39 | 'Supports comma lists' 40 | ); 41 | 42 | @include assert-equal( 43 | list-append([1 2], 3, 4, [5 6]), 44 | [1 2 3 4 [5 6]], 45 | 'Supports bracketed space lists' 46 | ); 47 | 48 | @include assert-equal( 49 | list-append([1, 2], 3, 4, [5, 6]), 50 | [1, 2, 3, 4, [5, 6]], 51 | 'Supports bracketed comma lists' 52 | ); 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /test/functions/list-contains.scss: -------------------------------------------------------------------------------- 1 | @include describe('list-contains [func]') { 2 | 3 | @include it('Returns true if a list contains a value') { 4 | @include assert-true( 5 | list-contains(1 2 3, 2), 6 | 'Supports space lists' 7 | ); 8 | 9 | @include assert-true( 10 | list-contains((1, 2, 3), 2), 11 | 'Supports comma lists' 12 | ); 13 | 14 | @include assert-true( 15 | list-contains([1 2 3], 2), 16 | 'Supports bracketed space lists' 17 | ); 18 | 19 | @include assert-true( 20 | list-contains([1, 2, 3], 2), 21 | 'Supports bracketed comma lists' 22 | ); 23 | } 24 | 25 | @include it('Returns false if a list does not contain a value') { 26 | @include assert-false( 27 | list-contains(1 2 3, 4), 28 | 'Supports space lists' 29 | ); 30 | 31 | @include assert-false( 32 | list-contains((1, 2, 3), 4), 33 | 'Supports comma lists' 34 | ); 35 | 36 | @include assert-false( 37 | list-contains([1 2 3], 4), 38 | 'Supports bracketed space lists' 39 | ); 40 | 41 | @include assert-false( 42 | list-contains([1, 2, 3], 4), 43 | 'Supports bracketed comma lists' 44 | ); 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /test/functions/list-each.scss: -------------------------------------------------------------------------------- 1 | @include describe('list-each [func]') { 2 | 3 | @include it('Calls a function on each item in a list') { 4 | @include assert-equal( 5 | list-each(1.2 2.5 3.7, 'round'), 6 | (1 3 4), 7 | 'Supports space lists' 8 | ); 9 | 10 | @include assert-equal( 11 | list-each((1.2, 2.5, 3.7), 'round'), 12 | (1, 3, 4), 13 | 'Supports comma lists' 14 | ); 15 | 16 | @include assert-equal( 17 | list-each([1.2 2.5 3.7], 'round'), 18 | [1 3 4], 19 | 'Supports bracketed space lists' 20 | ); 21 | 22 | @include assert-equal( 23 | list-each([1.2, 2.5, 3.7], 'round'), 24 | [1, 3, 4], 25 | 'Supports bracketed comma lists' 26 | ); 27 | } 28 | 29 | @include it('Supports passing args to the called function') { 30 | @include assert-equal( 31 | list-each(('hello', 'world'), 'str-insert', ('123', 1)), 32 | ('123hello', '123world') 33 | ); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /test/functions/list-every.scss: -------------------------------------------------------------------------------- 1 | @include describe('list-every [func]') { 2 | 3 | @include it('Checks if every value in a list returns true for a given function') { 4 | @include assert-true( 5 | list-every(1.2 2.5 3.7, 'unitless') 6 | ); 7 | 8 | @include assert-false( 9 | list-every(1.2 2.5rem 3.7, 'unitless') 10 | ); 11 | } 12 | 13 | @include it('Supports passing args to the called function') { 14 | @include assert-equal( 15 | true, 16 | true 17 | ); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /test/functions/list-prepend.scss: -------------------------------------------------------------------------------- 1 | @include describe('list-prepend [func]') { 2 | 3 | @include it('Prepends a single value to the start of a list') { 4 | @include assert-equal( 5 | list-prepend(10px 20px, 30px), 6 | (30px 10px 20px), 7 | 'Supports space lists' 8 | ); 9 | 10 | @include assert-equal( 11 | list-prepend((10px, 20px), 30px), 12 | (30px, 10px, 20px), 13 | 'Supports comma lists' 14 | ); 15 | 16 | @include assert-equal( 17 | list-prepend([10px 20px], 30px), 18 | [30px 10px 20px], 19 | 'Supports bracketed space lists' 20 | ); 21 | 22 | @include assert-equal( 23 | list-prepend([10px, 20px], 30px), 24 | [30px, 10px, 20px], 25 | 'Supports bracketed comma lists' 26 | ); 27 | } 28 | 29 | @include it('Prepends multiple values to the start of a list') { 30 | @include assert-equal( 31 | list-prepend(1 2, 3, 4, 5 6), 32 | ((5 6) 4 3 1 2), 33 | 'Supports space lists' 34 | ); 35 | 36 | @include assert-equal( 37 | list-prepend((1, 2), 3, 4, (5, 6)), 38 | ((5, 6), 4, 3, 1, 2), 39 | 'Supports comma lists' 40 | ); 41 | 42 | @include assert-equal( 43 | list-prepend([1 2], 3, 4, [5 6]), 44 | [[5 6] 4 3 1 2], 45 | 'Supports bracketed space lists' 46 | ); 47 | 48 | @include assert-equal( 49 | list-prepend([1, 2], 3, 4, [5, 6]), 50 | [[5, 6], 4, 3, 1, 2], 51 | 'Supports bracketed comma lists' 52 | ); 53 | } 54 | } -------------------------------------------------------------------------------- /test/functions/list-remove.scss: -------------------------------------------------------------------------------- 1 | @include describe('list-remove [func]') { 2 | 3 | @include it('Removes the first occurance of a value in a list') { 4 | @include assert-equal( 5 | list-remove(1 2 3 1 2 3, 2), 6 | 1 3 1 2 3, 7 | 'Supports space lists' 8 | ); 9 | 10 | @include assert-equal( 11 | list-remove((1, 2, 3, 1, 2, 3), 2), 12 | (1, 3, 1, 2, 3), 13 | 'Supports comma lists' 14 | ); 15 | 16 | @include assert-equal( 17 | list-remove([1 2 3 1 2 3], 2), 18 | [1 3 1 2 3], 19 | 'Supports bracketed space lists' 20 | ); 21 | 22 | @include assert-equal( 23 | list-remove([1, 2, 3, 1, 2, 3], 2), 24 | [1, 3, 1, 2, 3], 25 | 'Supports bracketed comma lists' 26 | ); 27 | } 28 | 29 | @include it('Removes all occurances of a value in a list') { 30 | @include assert-equal( 31 | list-remove(1 2 3 1 2 3, 2, true), 32 | 1 3 1 3, 33 | 'Support space lists' 34 | ); 35 | 36 | @include assert-equal( 37 | list-remove((1, 2, 3, 1, 2, 3), 2, true), 38 | (1, 3, 1, 3), 39 | 'Support comma lists' 40 | ); 41 | 42 | @include assert-equal( 43 | list-remove([1 2 3 1 2 3], 2, true), 44 | [1 3 1 3], 45 | 'Support bracketed lists' 46 | ); 47 | 48 | @include assert-equal( 49 | list-remove([1, 2, 3, 1, 2, 3], 2, true), 50 | [1, 3, 1, 3], 51 | 'Support bracketed comma lists' 52 | ); 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /test/functions/list-replace.scss: -------------------------------------------------------------------------------- 1 | @include describe('list-replace [func]') { 2 | 3 | @include it('Replaces the first occurance of a value in a list') { 4 | @include assert-equal( 5 | list-replace(1 2 2 2 3, 2, 4), 6 | 1 4 2 2 3, 7 | 'Supports space lists' 8 | ); 9 | 10 | @include assert-equal( 11 | list-replace((1, 2, 2, 2, 3), 2, 4), 12 | (1, 4, 2, 2, 3), 13 | 'Supports comma lists' 14 | ); 15 | 16 | @include assert-equal( 17 | list-replace([1 2 2 2 3], 2, 4), 18 | [1 4 2 2 3], 19 | 'Supports bracketed space lists' 20 | ); 21 | 22 | @include assert-equal( 23 | list-replace([1, 2, 2, 2, 3], 2, 4), 24 | [1, 4, 2, 2, 3], 25 | 'Supports bracketed comma lists' 26 | ); 27 | } 28 | 29 | @include it('Replaces all occurances of a value in a list') { 30 | @include assert-equal( 31 | list-replace(1 2 3 1 1 1 2 2 2 3 3 3, 2, 4, true), 32 | 1 4 3 1 1 1 4 4 4 3 3 3, 33 | 'Support space lists' 34 | ); 35 | 36 | @include assert-equal( 37 | list-replace((1, 2, 3, 1, 1, 1, 2, 2, 2, 3, 3, 3), 2, 4, true), 38 | (1, 4, 3, 1, 1, 1, 4, 4, 4, 3, 3, 3), 39 | 'Support comma lists' 40 | ); 41 | 42 | @include assert-equal( 43 | list-replace([1 2 3 1 1 1 2 2 2 3 3 3], 2, 4, true), 44 | [1 4 3 1 1 1 4 4 4 3 3 3], 45 | 'Support bracketed lists' 46 | ); 47 | 48 | @include assert-equal( 49 | list-replace([1, 2, 3, 1, 1, 1, 2, 2, 2, 3, 3, 3], 2, 4, true), 50 | [1, 4, 3, 1, 1, 1, 4, 4, 4, 3, 3, 3], 51 | 'Support bracketed comma lists' 52 | ); 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /test/functions/list-reverse.scss: -------------------------------------------------------------------------------- 1 | @include describe('list-reverse [func]') { 2 | 3 | @include it('Reverses items in a list') { 4 | @include assert-equal( 5 | list-reverse(b c a d), 6 | d a c b, 7 | 'Supports space lists' 8 | ); 9 | 10 | @include assert-equal( 11 | list-reverse((b, c, a, d)), 12 | (d, a, c, b), 13 | 'Supports comma lists' 14 | ); 15 | 16 | @include assert-equal( 17 | list-reverse([b c a d]), 18 | [d a c b], 19 | 'Supports bracketed space lists' 20 | ); 21 | 22 | @include assert-equal( 23 | list-reverse([b, c, a, d]), 24 | [d, a, c, b], 25 | 'Supports bracketed comma lists' 26 | ); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /test/functions/list-sort.scss: -------------------------------------------------------------------------------- 1 | @include describe('list-sort [func]') { 2 | 3 | @include it('Sorts strings in a list') { 4 | @include assert-equal( 5 | list-sort(b c a d), 6 | a b c d, 7 | 'Supports space lists' 8 | ); 9 | 10 | @include assert-equal( 11 | list-sort((b, c, a, d)), 12 | (a, b, c, d), 13 | 'Supports comma lists' 14 | ); 15 | 16 | @include assert-equal( 17 | list-sort([b c a d]), 18 | [a b c d], 19 | 'Supports bracketed space lists' 20 | ); 21 | 22 | @include assert-equal( 23 | list-sort([b, c, a, d]), 24 | [a, b, c, d], 25 | 'Supports bracketed comma lists' 26 | ); 27 | } 28 | 29 | @include it('Sorts numbers in a list') { 30 | @include assert-equal( 31 | list-sort(2 4 1 3), 32 | 1 2 3 4, 33 | 'Supports space lists' 34 | ); 35 | 36 | @include assert-equal( 37 | list-sort((2, 4, 1, 3)), 38 | (1, 2, 3, 4), 39 | 'Supports comma lists' 40 | ); 41 | 42 | @include assert-equal( 43 | list-sort([2 4 1 3]), 44 | [1 2 3 4], 45 | 'Supports bracketed space lists' 46 | ); 47 | 48 | @include assert-equal( 49 | list-sort([2, 4, 1, 3]), 50 | [1, 2, 3, 4], 51 | 'Supports bracketed comma lists' 52 | ); 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /test/functions/list-unique.scss: -------------------------------------------------------------------------------- 1 | @include describe('list-unqiue [func]') { 2 | 3 | @include it('Removes duplicate values from a list') { 4 | @include assert-equal( 5 | list-unique((1 a (b: 3) cyan a cyan 1 2 3 red (b: 3))), 6 | (1 a (b: 3) cyan 2 3 red), 7 | 'Supports space lists' 8 | ); 9 | 10 | @include assert-equal( 11 | list-unique((1, a, (b: 3), cyan, a, cyan, 1, 2, 3, red, (b: 3))), 12 | (1, a, (b: 3), cyan, 2, 3, red), 13 | 'Supports comma lists' 14 | ); 15 | 16 | @include assert-equal( 17 | list-unique([1 a (b: 3) cyan a cyan 1 2 3 red (b: 3)]), 18 | ([1 a (b: 3) cyan 2 3 red]), 19 | 'Supports bracketed space lists' 20 | ); 21 | 22 | @include assert-equal( 23 | list-unique([1, a, (b: 3), cyan, a, cyan, 1, 2, 3, red, (b: 3)]), 24 | ([1, a, (b: 3), cyan, 2, 3, red]), 25 | 'Supports bracketed comma lists' 26 | ); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /test/functions/map-append.scss: -------------------------------------------------------------------------------- 1 | @include describe('map-append [func]') { 2 | 3 | @include it('Appends a single key-value pair onto the end of a map') { 4 | @include assert-equal( 5 | map-append((a: 1, b: 2), c, 3), 6 | (a: 1, b: 2, c: 3) 7 | ); 8 | } 9 | 10 | } 11 | -------------------------------------------------------------------------------- /test/functions/map-each-key.scss: -------------------------------------------------------------------------------- 1 | @include describe('map-each-key [func]') { 2 | 3 | @include it('Calls a function on each key in a map') { 4 | @include assert-equal( 5 | map-each-key(( 6 | a : 1, 7 | b : 2, 8 | c : 3 9 | ), 'to-upper-case'), 10 | ( 11 | A : 1, 12 | B : 2, 13 | C : 3 14 | ) 15 | ); 16 | } 17 | 18 | @include it('Supports passing args to the called function') { 19 | @include assert-equal( 20 | map-each-key(( 21 | 'apple' : 1, 22 | 'orange' : 2, 23 | 'banana' : 3 24 | ), 'str-replace', ('a', '4', true)), 25 | ( 26 | '4pple' : 1, 27 | 'or4nge' : 2, 28 | 'b4n4n4' : 3 29 | ) 30 | ); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /test/functions/map-each-value.scss: -------------------------------------------------------------------------------- 1 | @include describe('map-each-value [func]') { 2 | 3 | @include it('Calls a function on each value in a map') { 4 | @include assert-equal( 5 | map-each-value(( 6 | 1 : 1.1, 7 | 'a' : 2.5, 8 | blue : 3.7 9 | ), 'round'), 10 | ( 11 | 1 : 1, 12 | 'a' : 3, 13 | blue : 4 14 | ) 15 | ); 16 | } 17 | 18 | @include it('Supports passing args to the called function') { 19 | @include assert-equal( 20 | map-each-value(( 21 | a : 'apple', 22 | b : 'orange', 23 | c : 'banana' 24 | ), 'str-replace', ('a', '4', true)), 25 | ( 26 | a : '4pple', 27 | b : 'or4nge', 28 | c : 'b4n4n4' 29 | ) 30 | ); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /test/functions/map-flatten.scss: -------------------------------------------------------------------------------- 1 | @include describe('map-flatten [func]') { 2 | 3 | @include it('Flattens a map one level deep') { 4 | @include assert-equal( 5 | map-flatten(( 6 | 'blue': #0000ff, 7 | 'red': ( 8 | '1': #ff0000, 9 | '2': #cc0000 10 | ), 11 | 'cyan': ( 12 | '1': ( 13 | 'a': #00ffff, 14 | 'b': #00cccc 15 | ), 16 | '2': ( 17 | 'a': #00ffff, 18 | 'b': #00cccc 19 | ) 20 | ) 21 | )), 22 | ( 23 | 'blue': #0000ff, 24 | 'red-1': #ff0000, 25 | 'red-2': #cc0000, 26 | 'cyan-1': ( 27 | 'a': #00ffff, 28 | 'b': #00cccc 29 | ), 30 | 'cyan-2': ( 31 | 'a': #00ffff, 32 | 'b': #00cccc 33 | ) 34 | ) 35 | ); 36 | } 37 | 38 | @include it('Accepts a custom separator') { 39 | @include assert-equal( 40 | map-flatten(( 41 | 'blue': #0000ff, 42 | 'red': ( 43 | '1': #ff0000, 44 | '2': #cc0000 45 | ), 46 | 'cyan': ( 47 | '1': ( 48 | 'a': #00ffff, 49 | 'b': #00cccc 50 | ), 51 | '2': ( 52 | 'a': #00ffff, 53 | 'b': #00cccc 54 | ) 55 | ) 56 | ), '@='), 57 | ( 58 | 'blue': #0000ff, 59 | 'red@=1': #ff0000, 60 | 'red@=2': #cc0000, 61 | 'cyan@=1': ( 62 | 'a': #00ffff, 63 | 'b': #00cccc 64 | ), 65 | 'cyan@=2': ( 66 | 'a': #00ffff, 67 | 'b': #00cccc 68 | ) 69 | ) 70 | ); 71 | } 72 | 73 | @include it('Does not generate variant for default key') { 74 | @include assert-equal( 75 | map-flatten(( 76 | transparent: transparent, 77 | grey: ( 78 | _: #cccccc, 79 | 1: #999999, 80 | 2: #333333 81 | ) 82 | )), 83 | ( 84 | transparent: transparent, 85 | grey: #cccccc, 86 | grey-1: #999999, 87 | grey-2: #333333 88 | ) 89 | ); 90 | } 91 | 92 | } 93 | -------------------------------------------------------------------------------- /test/functions/map-get-key.scss: -------------------------------------------------------------------------------- 1 | @include describe('map-get-key [func]') { 2 | 3 | @include it('Returns the key(s) in a map associated with a given value.') { 4 | @include assert-equal( 5 | map-get-key((a: 1, b: 2, c: 3), 2), 6 | (b,), 7 | 'Single matching key' 8 | ); 9 | 10 | @include assert-equal( 11 | map-get-key((a: 1, b: 2, c: 2), 2), 12 | (b, c), 13 | 'Multiple matching keys' 14 | ); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /test/functions/map-prepend.scss: -------------------------------------------------------------------------------- 1 | @include describe('map-prepend [func]') { 2 | 3 | @include it('Prepends a single key-value pair onto the start of a map') { 4 | @include assert-equal( 5 | map-prepend((a: 1, b: 2), c, 3), 6 | (c: 3, a: 1, b: 2) 7 | ); 8 | } 9 | 10 | } 11 | -------------------------------------------------------------------------------- /test/functions/map-stringify-keys-deep.scss: -------------------------------------------------------------------------------- 1 | @include describe('map-stringify-keys-deep [func]') { 2 | 3 | @include it('Converts keys of nested maps') { 4 | @include assert-equal( 5 | map-stringify-keys-deep(( 6 | #000000: ( 7 | red: ( 8 | 1: 1, 9 | 2: ( 10 | blue: 1 11 | ) 12 | ), 13 | 2: 2, 14 | a: 3 15 | ), 16 | white: 2 17 | )), 18 | ( 19 | '#000000': ( 20 | 'red': ( 21 | '1': 1, 22 | '2': ( 23 | 'blue': 1 24 | ) 25 | ), 26 | '2': 2, 27 | 'a': 3 28 | ), 29 | 'white': 2 30 | ) 31 | ); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /test/functions/map-stringify-keys.scss: -------------------------------------------------------------------------------- 1 | @include describe('map-stringify-keys [func]') { 2 | 3 | @include it('Converts direct keys of a map to strings') { 4 | @include assert-equal( 5 | map-stringify-keys(( 6 | 1: 1, 7 | a: 2, 8 | red: 3, 9 | )), 10 | ( 11 | '1': 1, 12 | 'a': 2, 13 | 'red': 3 14 | ) 15 | ); 16 | 17 | @include assert-equal( 18 | map-stringify-keys(( 19 | #000000: 1, 20 | white: 2 21 | )), 22 | ( 23 | '#000000': 1, 24 | 'white': 2 25 | ), 26 | 'Converts colors' 27 | ); 28 | 29 | @include assert-equal( 30 | map-stringify-keys(( 31 | 1: 1, 32 | 20px: 2, 33 | 300rem: 3, 34 | 4s: 4 35 | )), 36 | ( 37 | '1': 1, 38 | '20px': 2, 39 | '300rem': 3, 40 | '4s': 4 41 | ), 42 | 'Converts numbers' 43 | ); 44 | } 45 | 46 | @include it('Does not convert keys of nested maps') { 47 | @include assert-equal( 48 | map-stringify-keys(( 49 | #000000: ( 50 | red: 1, 51 | 2: 2, 52 | a: 3 53 | ), 54 | white: 2, 55 | )), 56 | ( 57 | '#000000': ( 58 | red: 1, 59 | 2: 2, 60 | a: 3 61 | ), 62 | 'white': 2 63 | ) 64 | ); 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /test/functions/map-unique.scss: -------------------------------------------------------------------------------- 1 | @include describe('map-unique [func]') { 2 | 3 | @include it('Removes key-value pairs from a map which contain duplicate values') { 4 | @include assert-equal( 5 | map-unique((a: 1, b: 2, c: 3, d: 1, e: 1, f: 3)), 6 | (a: 1, b: 2, c: 3) 7 | ); 8 | } 9 | 10 | } 11 | -------------------------------------------------------------------------------- /test/functions/random-color.scss: -------------------------------------------------------------------------------- 1 | @include describe('random-color [func]') { 2 | 3 | @include it('Returns a random color value') { 4 | @include assert-equal( 5 | type-of(random-color()), 6 | color 7 | ); 8 | } 9 | 10 | } 11 | -------------------------------------------------------------------------------- /test/functions/rem.scss: -------------------------------------------------------------------------------- 1 | @include describe('rem [func]') { 2 | 3 | @include it('Converts px to rem') { 4 | @include assert-equal( 5 | rem(32), 6 | 2rem, 7 | 'Default base font size' 8 | ); 9 | 10 | @include assert-equal( 11 | rem(32, 10), 12 | 3.2rem, 13 | 'Custom base font size' 14 | ); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /test/functions/str-append.scss: -------------------------------------------------------------------------------- 1 | @include describe('str-append [func]') { 2 | 3 | @include it('Appends to a string') { 4 | @include assert-equal( 5 | str-append('hello', 'world'), 6 | 'helloworld', 7 | 'Single string' 8 | ); 9 | 10 | @include assert-equal( 11 | str-append('hello', 'world', 'foo', 'bar'), 12 | 'helloworldfoobar', 13 | 'Multiple strings' 14 | ); 15 | } 16 | 17 | @include it('Treats null as empty string') { 18 | @include assert-equal( 19 | str-append('hello', null, 'world'), 20 | 'helloworld' 21 | ) 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /test/functions/str-compare.scss: -------------------------------------------------------------------------------- 1 | @include describe('str-compare [func]') { 2 | 3 | @include it('Compares two strings to determine which comes first') { 4 | @include assert-true( 5 | str-compare('a', 'b'), 6 | 'Letter `a` comes before `b`' 7 | ); 8 | 9 | @include assert-false( 10 | str-compare('b', 'a'), 11 | 'Letter `b` comes before `a`' 12 | ); 13 | 14 | @include assert-true( 15 | str-compare('apples', 'oranges'), 16 | '`apples` comes before `oranges`' 17 | ); 18 | 19 | @include assert-false( 20 | str-compare('oranges', 'apples'), 21 | '`oranges` comes before `apples`' 22 | ); 23 | 24 | @include assert-true( 25 | str-compare('room-13', 'room-24'), 26 | '`room-13` comes before `room-24`' 27 | ); 28 | 29 | @include assert-false( 30 | str-compare('room-24', 'room-13'), 31 | '`room-24` comes before `room-13`' 32 | ); 33 | 34 | @include assert-true( 35 | str-compare('room 13', 'room 24'), 36 | '`room 13` comes before `room 24`' 37 | ); 38 | 39 | @include assert-false( 40 | str-compare('room 24', 'room 13'), 41 | '`room 24` comes before `room 13`' 42 | ); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /test/functions/str-contains.scss: -------------------------------------------------------------------------------- 1 | @include describe('str-contains [func]') { 2 | 3 | @include it('Checks if a string contains a substring') { 4 | @include assert-true( 5 | str-contains('hello world', 'hello'), 6 | '`hello world` contains `hello`' 7 | ); 8 | 9 | @include assert-false( 10 | str-contains('team', 'i'), 11 | '`team` does not contain `i`' 12 | ); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /test/functions/str-escape.scss: -------------------------------------------------------------------------------- 1 | @include describe('str-escape [func]') { 2 | 3 | @include it('Escapes special characters in a string') { 4 | @include assert-equal( 5 | str-escape('a@d#5!^g:g5&#f%)_3+='), 6 | 'a\\@d\\#5\\!\\^g\\:g5\\&\\#f\\%\\)_3\\+\\=', 7 | 'Escapes CSS special characters' 8 | ); 9 | 10 | @include assert-equal( 11 | str-escape('look---_,_some_underscores_!'), 12 | 'look---_\\,_some_underscores_\\!', 13 | 'Does not escape underscores' 14 | ); 15 | 16 | @include assert-equal( 17 | str-escape('😮 emoji\'s and weird stuff ♥ go unnoticed! 😀©'), 18 | '😮 emoji\\\'s and weird stuff ♥ go unnoticed\\! 😀©', 19 | 'Does not escape characters with no special meaning in CSS' 20 | ) 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /test/functions/str-prepend.scss: -------------------------------------------------------------------------------- 1 | @include describe('str-prepend [func]') { 2 | 3 | @include it('Prepends to a string') { 4 | @include assert-equal( 5 | str-prepend('world', 'hello'), 6 | 'helloworld', 7 | 'Single string' 8 | ); 9 | 10 | @include assert-equal( 11 | str-prepend('bar', 'foo', 'world', 'hello'), 12 | 'helloworldfoobar', 13 | 'Multiple strings' 14 | ); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /test/functions/str-remove.scss: -------------------------------------------------------------------------------- 1 | @include describe('str-remove [func]') { 2 | 3 | @include it('Removes first occurance of text in a string') { 4 | @include assert-equal( 5 | str-remove('beetle', 'e'), 6 | 'betle' 7 | ); 8 | } 9 | 10 | @include it('Removes all occurances of text in a string') { 11 | @include assert-equal( 12 | str-remove('beetle', 'e', true), 13 | 'btl' 14 | ); 15 | } 16 | 17 | @include it('Returns original string if no substrings are found') { 18 | @include assert-equal( 19 | str-remove('beetle', '1'), 20 | 'beetle' 21 | ); 22 | 23 | @include assert-equal( 24 | str-remove('beetle', '1', true), 25 | 'beetle' 26 | ); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /test/functions/str-replace.scss: -------------------------------------------------------------------------------- 1 | @include describe('str-replace [func]') { 2 | 3 | @include it('Replaces first occurance of text in a string') { 4 | @include assert-equal( 5 | str-replace('beetle', 'e', '3'), 6 | 'b3etle', 7 | 'Replaces text' 8 | ); 9 | 10 | @include assert-equal( 11 | str-replace('beetlee', 'e', 'ee'), 12 | 'beeetlee', 13 | 'Replaces text where $replace contains $search' 14 | ); 15 | 16 | @include assert-equal( 17 | str-replace('beetlee', 'ee', 'ee'), 18 | 'beetlee', 19 | 'Replaces text where $replace == $search' 20 | ); 21 | 22 | @include assert-equal( 23 | str-replace('beetlee', 'ee', 'e'), 24 | 'betlee', 25 | 'Replaces text where $search contains $replace' 26 | ); 27 | 28 | @include assert-equal( 29 | str-replace('beetle', 'e'), 30 | 'betle', 31 | 'Removes text if no $replacement is defined' 32 | ); 33 | } 34 | 35 | @include it('Replaces all occurances of text in a string') { 36 | @include assert-equal( 37 | str-replace('beetle', 'e', '3', true), 38 | 'b33tl3', 39 | 'Replaces text' 40 | ); 41 | 42 | @include assert-equal( 43 | str-replace('beetlee', 'e', 'ee', true), 44 | 'beeeetleeee', 45 | 'Replaces text where $replace contains $search' 46 | ); 47 | 48 | @include assert-equal( 49 | str-replace('beetlee', 'ee', 'ee', true), 50 | 'beetlee', 51 | 'Replaces text where $replace == $search' 52 | ); 53 | 54 | @include assert-equal( 55 | str-replace('beetlee', 'ee', 'e', true), 56 | 'betle', 57 | 'Replaces text where $search contains $replace' 58 | ); 59 | 60 | @include assert-equal( 61 | str-replace('beetle', 'e', '', true), 62 | 'btl', 63 | 'Removes text if no $replacement is defined' 64 | ); 65 | } 66 | 67 | @include it('Returns original string if no substrings are found') { 68 | @include assert-equal( 69 | str-replace('beetle', '1', '3'), 70 | 'beetle' 71 | ); 72 | 73 | @include assert-equal( 74 | str-replace('beetle', '1', '3', true), 75 | 'beetle' 76 | ); 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /test/functions/throw.scss: -------------------------------------------------------------------------------- 1 | @include describe('throw [func]') { 2 | 3 | @include it('Throws an error') { 4 | 5 | @include assert-equal( 6 | throw('exception', 'message', false), 7 | '[exception] message' 8 | ); 9 | 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /test/functions/to-length.scss: -------------------------------------------------------------------------------- 1 | @include describe('to-length [func]') { 2 | 3 | @include it('Adds a unit to a value') { 4 | 5 | @include assert-equal( 6 | to-length(10, '%'), 7 | 10% 8 | ); 9 | 10 | } 11 | 12 | } 13 | 14 | -------------------------------------------------------------------------------- /test/functions/to-negative.scss: -------------------------------------------------------------------------------- 1 | @include describe('to-negative [func]') { 2 | 3 | @include it('Converts a value to a negative value') { 4 | @include assert-equal( 5 | to-negative(1), 6 | -1 7 | ); 8 | } 9 | 10 | @include it('Converts a list containing numbers to negative values') { 11 | @include assert-equal( 12 | to-negative((a, 1, -2, 3.142)), 13 | (a, -1, -2, -3.142) 14 | ); 15 | } 16 | 17 | @include it('Converts a map containing numbers to a negative value') { 18 | @include assert-equal( 19 | to-negative((a: 1, b: -2, c: (1: 5))), 20 | (a: -1, b: -2, c: (1: -5)) 21 | ); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /test/functions/to-number.scss: -------------------------------------------------------------------------------- 1 | @include describe('to-number [func]') { 2 | 3 | @include it('Converts a value to a number') { 4 | @include assert-equal( 5 | to-number('10'), 6 | 10 7 | ); 8 | 9 | @include assert-equal( 10 | to-number('4px'), 11 | 4px 12 | ); 13 | 14 | @include assert-equal( 15 | to-number('1em'), 16 | 1em 17 | ); 18 | 19 | @include assert-equal( 20 | to-number('1xxx'), 21 | 1 22 | ); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /test/functions/to-string.scss: -------------------------------------------------------------------------------- 1 | @include describe('to-string [func]') { 2 | 3 | @include it('Converts a value to an unquoted string') { 4 | @include assert-equal( 5 | to-string(false), 6 | 'false', 7 | 'Boolean' 8 | ); 9 | 10 | @include assert-equal( 11 | to-string(null), 12 | 'null', 13 | 'Null' 14 | ); 15 | 16 | @include assert-equal( 17 | to-string(1), 18 | '1', 19 | 'Integer' 20 | ); 21 | 22 | @include assert-equal( 23 | to-string(3.142), 24 | '3.142', 25 | 'Float' 26 | ); 27 | 28 | @include assert-equal( 29 | to-string(32px), 30 | '32px', 31 | 'Number with units' 32 | ); 33 | 34 | @include assert-equal( 35 | to-string(blue), 36 | 'blue', 37 | 'Color' 38 | ); 39 | 40 | @include assert-equal( 41 | to-string((1,2,3)), 42 | '1, 2, 3', 43 | 'Comma list' 44 | ); 45 | 46 | @include assert-equal( 47 | to-string((1 2 3)), 48 | '1 2 3', 49 | 'Space list' 50 | ); 51 | 52 | @include assert-equal( 53 | to-string([1,2,3]), 54 | '[1, 2, 3]', 55 | 'Comma bracket list' 56 | ); 57 | 58 | @include assert-equal( 59 | to-string([1 2 3]), 60 | '[1 2 3]', 61 | 'Space bracket list' 62 | ); 63 | 64 | @include assert-equal( 65 | to-string((a: 1, b: 2)), 66 | '(a: 1, b: 2)', 67 | 'Map' 68 | ); 69 | 70 | @include assert-equal( 71 | to-string(hello), 72 | inspect(hello), 73 | 'Unquoted string' 74 | ); 75 | 76 | @include assert-equal( 77 | to-string('hello'), 78 | inspect(hello), 79 | 'Single quoted string' 80 | ); 81 | 82 | @include assert-equal( 83 | to-string("hello"), 84 | inspect(hello), 85 | 'Double quoted string' 86 | ); 87 | } 88 | 89 | } 90 | -------------------------------------------------------------------------------- /test/functions/type-check.scss: -------------------------------------------------------------------------------- 1 | @include describe('type-check [func]') { 2 | 3 | @include it('Returns true if all checks pass') { 4 | $arg1: 'a'; 5 | $arg2: 2; 6 | $arg3: red; 7 | 8 | @include assert-true( 9 | type-check('func', [ 10 | ($arg1: string) 11 | ], false) 12 | ); 13 | 14 | @include assert-true( 15 | type-check('func', [ 16 | ($arg1: string), 17 | ($arg2: number), 18 | ($arg3: color) 19 | ], false) 20 | ); 21 | 22 | } 23 | 24 | @include it('Returns error string if one or more checks fail') { 25 | $arg1: 'a'; 26 | $arg2: 2; 27 | $arg3: red; 28 | 29 | @include assert-equal( 30 | type-check('my-function', [ 31 | ($arg1: number) 32 | ], false), 33 | '[TypeError] my-function expected {number}, was: #{$arg1} {#{type-of($arg1)}}' 34 | ); 35 | 36 | @include assert-equal( 37 | type-check('my-function', [ 38 | ($arg1: string), 39 | ($arg2: number), 40 | ($arg3: number) 41 | ], false), 42 | '[TypeError] my-function expected {number}, was: #{$arg3} {#{type-of($arg3)}}' 43 | ); 44 | 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /test/functions/unit-convert.scss: -------------------------------------------------------------------------------- 1 | @include describe('unit-convert [func]') { 2 | 3 | @include it('Converts units of a value') { 4 | @include assert-equal( 5 | unit-convert(10px, pt), 6 | 7.5pt, 7 | 'Length' 8 | ); 9 | 10 | @include assert-equal( 11 | unit-convert(42ms, 's'), 12 | 0.042s, 13 | 'Time' 14 | ); 15 | 16 | @include assert-equal( 17 | unit-convert(1turn, 'deg'), 18 | 360deg, 19 | 'Rotation' 20 | ); 21 | 22 | @include assert-equal( 23 | unit-convert(60Hz, 'kHz'), 24 | 0.06kHz, 25 | 'Frequency' 26 | ); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /test/functions/unit-strip.scss: -------------------------------------------------------------------------------- 1 | @include describe('unit-strip [func]') { 2 | 3 | @include it('Strips units from a number') { 4 | @include assert-equal( 5 | unit-strip(1rem), 6 | 1, 7 | 'rem' 8 | ); 9 | 10 | @include assert-equal( 11 | unit-strip(2em), 12 | 2, 13 | 'em' 14 | ); 15 | 16 | @include assert-equal( 17 | unit-strip(3px), 18 | 3, 19 | 'px' 20 | ); 21 | 22 | @include assert-equal( 23 | unit-strip(4s), 24 | 4, 25 | 's' 26 | ); 27 | 28 | @include assert-equal( 29 | unit-strip(5ms), 30 | 5, 31 | 'ms' 32 | ); 33 | 34 | @include assert-equal( 35 | unit-strip(6deg), 36 | 6, 37 | 'deg' 38 | ); 39 | 40 | @include assert-equal( 41 | unit-strip(-20px), 42 | -20, 43 | 'Negative number' 44 | ); 45 | 46 | @include assert-equal( 47 | unit-strip(3.142px), 48 | 3.142, 49 | 'Positive float' 50 | ); 51 | 52 | @include assert-equal( 53 | unit-strip(-3.142px), 54 | -3.142, 55 | 'Negative float' 56 | ); 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /test/mixins/_.scss: -------------------------------------------------------------------------------- 1 | @import 'query'; 2 | // @import 'extends'; 3 | @import 'important'; 4 | @import 'responsive'; 5 | @import 'type-scale'; 6 | @import 'css-ruleset'; 7 | 8 | // Reset $__SCARAB 9 | @import '../../lib/options/_init'; 10 | @import '../../lib/constants/_init'; 11 | @import '../../lib/tokens/_init'; 12 | -------------------------------------------------------------------------------- /test/mixins/extends.scss: -------------------------------------------------------------------------------- 1 | @include describe('extends [mixin]') { 2 | 3 | @include it('Extends a class') { 4 | 5 | @include assert { 6 | @include output(false) { 7 | .bold { 8 | font-weight: bold; 9 | } 10 | 11 | .component { 12 | @include extends('bold'); 13 | } 14 | } 15 | 16 | @include expect(false) { 17 | .bold, 18 | .component { 19 | font-weight: bold; 20 | } 21 | } 22 | } 23 | 24 | } 25 | 26 | } 27 | 28 | -------------------------------------------------------------------------------- /test/mixins/important.scss: -------------------------------------------------------------------------------- 1 | @include describe('important [mixin]') { 2 | 3 | @include it('Applies `!important` to all property declarations inside it') { 4 | 5 | @include assert('Single property') { 6 | @include output { 7 | @include important(( 8 | margin: 20px 9 | )); 10 | } 11 | 12 | @include expect { 13 | margin: 20px !important; 14 | } 15 | } 16 | 17 | @include assert('Multiple properties') { 18 | @include output { 19 | @include important(( 20 | margin: 20px, 21 | color: red, 22 | font-weight: bold 23 | )); 24 | } 25 | 26 | @include expect { 27 | margin: 20px !important; 28 | color: red !important; 29 | font-weight: bold !important; 30 | } 31 | } 32 | 33 | } 34 | 35 | } 36 | 37 | -------------------------------------------------------------------------------- /test/mixins/query.scss: -------------------------------------------------------------------------------- 1 | @include describe('query [mixin]') { 2 | 3 | @include it('Wraps styles in a media query block') { 4 | 5 | @include assert('when $query is a number, generates a `min-width` media query') { 6 | @include output { 7 | @include query(30em) { 8 | color: red; 9 | } 10 | } 11 | 12 | @include expect { 13 | @media (min-width: 30em) { 14 | color: red; 15 | } 16 | } 17 | } 18 | 19 | @include assert('accepts query as a list with "from $bp" syntax') { 20 | @include output { 21 | @include query(from 30em) { 22 | color: red; 23 | } 24 | } 25 | 26 | @include expect { 27 | @media (min-width: 30em) { 28 | color: red; 29 | } 30 | } 31 | } 32 | 33 | @include assert('accepts query as a list with "above $bp" syntax') { 34 | @include output { 35 | @include query(above 30em) { 36 | color: red; 37 | } 38 | 39 | @include query(above 100px) { 40 | color: green; 41 | } 42 | 43 | @include query(above 10in) { 44 | color: blue; 45 | } 46 | 47 | @include query(above 20pt) { 48 | color: yellow; 49 | } 50 | } 51 | 52 | @include expect { 53 | @media (min-width: 30.0625em) { 54 | color: red; 55 | } 56 | 57 | @media (min-width: 101px) { 58 | color: green; 59 | } 60 | 61 | @media (min-width: 10.01042in) { 62 | color: blue; 63 | } 64 | 65 | @media (min-width: 20.75pt) { 66 | color: yellow; 67 | } 68 | } 69 | } 70 | 71 | @include assert('accepts query as a list with "until $bp" syntax') { 72 | @include output { 73 | @include query(until 30em) { 74 | color: red; 75 | } 76 | } 77 | 78 | @include expect { 79 | @media (max-width: 30em) { 80 | color: red; 81 | } 82 | } 83 | } 84 | 85 | @include assert('accepts query as a list with "below $bp" syntax') { 86 | @include output { 87 | @include query(below 30em) { 88 | color: red; 89 | } 90 | 91 | @include query(below 100px) { 92 | color: green; 93 | } 94 | 95 | @include query(below 10in) { 96 | color: blue; 97 | } 98 | 99 | @include query(below 20pt) { 100 | color: yellow; 101 | } 102 | } 103 | 104 | @include expect { 105 | @media (max-width: 29.9375em) { 106 | color: red; 107 | } 108 | 109 | @media (max-width: 99px) { 110 | color: green; 111 | } 112 | 113 | @media (max-width: 9.98958in) { 114 | color: blue; 115 | } 116 | 117 | @media (max-width: 19.25pt) { 118 | color: yellow; 119 | } 120 | } 121 | } 122 | 123 | @include assert('accepts query as a list with "from $bp1 to $bp2" syntax') { 124 | @include output { 125 | @include query(from 30em to 40em) { 126 | color: red; 127 | } 128 | } 129 | 130 | @include expect { 131 | @media (min-width: 30em) and (max-width: 40em) { 132 | color: red; 133 | } 134 | } 135 | } 136 | 137 | @include assert('accepts $query as a map with a `type` key') { 138 | @include output { 139 | @include query(( 140 | type: print 141 | )) { 142 | color: red; 143 | } 144 | } 145 | 146 | @include expect { 147 | @media print { 148 | color: red; 149 | } 150 | } 151 | } 152 | 153 | @include assert('accepts $query as a map with a `condition` key') { 154 | @include output { 155 | @include query(( 156 | condition: "(min-width: 30em)" 157 | )) { 158 | color: red; 159 | } 160 | } 161 | 162 | @include expect { 163 | @media (min-width: 30em) { 164 | color: red; 165 | } 166 | } 167 | } 168 | 169 | @include assert('accepts $query as a map with `type` and `condition` keys') { 170 | @include output { 171 | @include query(( 172 | type: print, 173 | condition: "(min-width: 30em)" 174 | )) { 175 | color: red; 176 | } 177 | } 178 | 179 | @include expect { 180 | @media print and (min-width: 30em) { 181 | color: red; 182 | } 183 | } 184 | } 185 | 186 | } 187 | 188 | @include it('Can contain a class declaration') { 189 | @include assert { 190 | @include output { 191 | @include query(30em) { 192 | .class { 193 | color: red; 194 | } 195 | } 196 | } 197 | 198 | @include expect { 199 | @media (min-width: 30em) { 200 | .class { 201 | color: red; 202 | } 203 | } 204 | } 205 | } 206 | } 207 | 208 | } 209 | 210 | -------------------------------------------------------------------------------- /test/mixins/responsive.scss: -------------------------------------------------------------------------------- 1 | @include describe('responsive [mixin]') { 2 | 3 | @include it('Generates responsive properties') { 4 | 5 | @include assert('Single property') { 6 | @include output { 7 | @include responsive(margin, ( 8 | _ : 11px, 9 | 111px : 27px, 10 | 278px : 34px, 11 | 394px : 46px 12 | )); 13 | } 14 | 15 | @include expect { 16 | margin: 11px; 17 | 18 | @media (min-width: 111px) { 19 | margin: 27px; 20 | } 21 | 22 | @media (min-width: 278px) { 23 | margin: 34px; 24 | } 25 | 26 | @media (min-width: 394px) { 27 | margin: 46px; 28 | } 29 | } 30 | } 31 | 32 | @include assert('Multiple properties') { 33 | @include output { 34 | @include responsive((margin, padding), ( 35 | _ : 11px, 36 | 111px : 27px, 37 | 278px : 34px, 38 | 394px : 46px 39 | )); 40 | } 41 | 42 | @include expect { 43 | margin: 11px; 44 | padding: 11px; 45 | 46 | @media (min-width: 111px) { 47 | margin: 27px; 48 | padding: 27px; 49 | } 50 | 51 | @media (min-width: 278px) { 52 | margin: 34px; 53 | padding: 34px; 54 | } 55 | 56 | @media (min-width: 394px) { 57 | margin: 46px; 58 | padding: 46px; 59 | } 60 | } 61 | } 62 | 63 | } 64 | 65 | @include it('Accepts breakpoint names in the breakpoint map') { 66 | 67 | @include assert { 68 | 69 | @include output { 70 | @include set(breakpoint, ( 71 | small: 400px, 72 | medium: 600px, 73 | large: 900px 74 | )); 75 | 76 | @include responsive(margin, ( 77 | _ : 11px, 78 | small : 27px, 79 | medium : 34px, 80 | large : 46px 81 | )); 82 | } 83 | 84 | @include expect { 85 | margin: 11px; 86 | 87 | @media (min-width: 400px) { 88 | margin: 27px; 89 | } 90 | 91 | @media (min-width: 600px) { 92 | margin: 34px; 93 | } 94 | 95 | @media (min-width: 900px) { 96 | margin: 46px; 97 | } 98 | } 99 | } 100 | 101 | } 102 | 103 | } 104 | -------------------------------------------------------------------------------- /test/mixins/type-scale.scss: -------------------------------------------------------------------------------- 1 | @include describe('type-scale [mixin]') { 2 | 3 | @include it('Generates font-size and line-height property declarations') { 4 | 5 | @include assert('Non-responsive sizes') { 6 | @include output { 7 | $_: set(font-size, ( 8 | 's': 11px, 9 | 'm': 17px, 10 | 'l': 24px 11 | )); 12 | 13 | $_: set(line-height, ( 14 | 's': 16px, 15 | 'm': 25px, 16 | 'l': 36px 17 | )); 18 | 19 | @include type-scale(s); 20 | } 21 | 22 | @include expect { 23 | font-size: 11px; 24 | line-height: 16px; 25 | } 26 | } 27 | 28 | @include assert('Responsive sizes') { 29 | @include output { 30 | $_: set(breakpoint, ( 31 | s: 200px, 32 | m: 444px 33 | )); 34 | 35 | $_: set(font-size, m, ( 36 | _ : 16px, 37 | s : 20px, 38 | m : 55px 39 | )); 40 | 41 | $_: set(line-height, m, ( 42 | _ : 20px, 43 | s : 25px, 44 | m : 64px 45 | )); 46 | 47 | @include type-scale(m); 48 | } 49 | 50 | @include expect { 51 | font-size: 16px; 52 | line-height: 20px; 53 | 54 | @media (min-width: 200px) { 55 | font-size: 20px; 56 | } 57 | 58 | @media (min-width: 444px) { 59 | font-size: 55px; 60 | } 61 | 62 | @media (min-width: 200px) { 63 | line-height: 25px; 64 | } 65 | 66 | @media (min-width: 444px) { 67 | line-height: 64px; 68 | } 69 | } 70 | } 71 | 72 | } 73 | 74 | } 75 | 76 | -------------------------------------------------------------------------------- /test/options/_.scss: -------------------------------------------------------------------------------- 1 | @import 'option'; 2 | @import 'set-option'; 3 | 4 | // Reset $__SCARAB 5 | @import '../../lib/options/_init'; 6 | @import '../../lib/constants/_init'; 7 | @import '../../lib/tokens/_init'; 8 | 9 | -------------------------------------------------------------------------------- /test/options/option.scss: -------------------------------------------------------------------------------- 1 | @include describe('get [func]') { 2 | 3 | @include it('Returns a value from the `OPTIONS` map') { 4 | $__SCARAB: ( 5 | 'OPTIONS': ( 6 | 'throw-errors': true, 7 | 'namescheme' : ( 8 | 'selector-format' : '{{b}}{{bp}}{{s}}{{sp}}{{rp}}{{r}}{{rs}}{{vp}}{{v}}{{vs}}{{mp}}{{m}}{{ms}}{{ss}}{{bs}}', 9 | 'default-key' : '_', 10 | 'root-prefix' : '', 11 | 'root-suffix' : '', 12 | 'variant-prefix' : '-', 13 | 'variant-suffix' : '', 14 | 'modifier-prefix' : ':', 15 | 'modifier-suffix' : '', 16 | 'breakpoint-prefix' : '(', 17 | 'breakpoint-suffix' : ')', 18 | 'state-prefix' : '(', 19 | 'state-suffix' : ')', 20 | 'states' : ( 21 | 'hover' : 'hv', 22 | 'focus' : 'fc', 23 | 'active' : 'ac' 24 | ), 25 | 'directions' : ( 26 | 'horizontal' : 'x', 27 | 'vertical' : 'y', 28 | 'top' : 't', 29 | 'right' : 'r', 30 | 'bottom' : 'b', 31 | 'left' : 'l' 32 | ) 33 | ) 34 | ) 35 | ) !global; 36 | 37 | 38 | @include assert-equal( 39 | option(throw-errors), 40 | true 41 | ); 42 | 43 | @include assert-equal( 44 | option(namescheme, states), 45 | ( 46 | 'hover' : 'hv', 47 | 'focus' : 'fc', 48 | 'active' : 'ac' 49 | ) 50 | ); 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /test/test_sass.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var sassTrue = require('sass-true'); 3 | 4 | var sassFile = path.join(__dirname, '/tests.scss'); 5 | sassTrue.runSass({ 6 | file: sassFile, 7 | includePaths: ['node_modules'], 8 | }, describe, it); 9 | -------------------------------------------------------------------------------- /test/tests.scss: -------------------------------------------------------------------------------- 1 | // Import the True Sass unit-testing tool 2 | @import 'sass-true/sass/true'; 3 | 4 | // Import Scarab 5 | @import '../lib/_'; 6 | 7 | // Import tests 8 | @import 'functions/_'; 9 | @import 'mixins/_'; 10 | @import 'options/_'; 11 | @import 'constants/_'; 12 | @import 'tokens/_'; 13 | 14 | @include report(); 15 | -------------------------------------------------------------------------------- /test/tokens/_.scss: -------------------------------------------------------------------------------- 1 | @import 'get'; 2 | @import 'set'; 3 | @import 'set-default'; 4 | @import 'unset'; 5 | @import 'helpers/_'; 6 | 7 | // Reset $__SCARAB 8 | @import '../../lib/options/_init'; 9 | @import '../../lib/constants/_init'; 10 | @import '../../lib/tokens/_init'; 11 | 12 | -------------------------------------------------------------------------------- /test/tokens/get.scss: -------------------------------------------------------------------------------- 1 | @include describe('get [func]') { 2 | 3 | @include it('Returns a value from the `TOKENS` map') { 4 | $__SCARAB: ( 5 | 'TOKENS': ( 6 | 'baseline': 1rem, 7 | 'palettes': ( 8 | 'blue': ( 9 | 'light' : #9999ff, 10 | 'base' : #6666cc, 11 | 'dark' : #000099 12 | ) 13 | ) 14 | ), 15 | 'CONSTANTS': () 16 | ) !global; 17 | 18 | 19 | @include assert-equal( 20 | get(baseline), 21 | 1rem 22 | ); 23 | 24 | @include assert-equal( 25 | get(palettes, blue), 26 | ( 27 | 'light' : #9999ff, 28 | 'base' : #6666cc, 29 | 'dark' : #000099 30 | ), 31 | 'Supports keys that are color names' 32 | ); 33 | 34 | @include assert-equal( 35 | get(palettes, blue, dark), 36 | #000099, 37 | 'Returns nested values' 38 | ); 39 | 40 | @include assert-equal( 41 | get('palettes', 'blue', 'dark'), 42 | #000099, 43 | 'Supports single quoted keys' 44 | ); 45 | 46 | @include assert-equal( 47 | get("palettes", "blue", "dark"), 48 | #000099, 49 | 'Supports double quoted keys' 50 | ); 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /test/tokens/helpers/_.scss: -------------------------------------------------------------------------------- 1 | @import 'baseline'; 2 | @import 'breakpoint'; 3 | @import 'color'; 4 | @import 'gradient'; 5 | @import 'opacity'; 6 | @import 'background-image'; 7 | @import 'letter-spacing'; 8 | @import 'line-height'; 9 | @import 'font-family'; 10 | @import 'font-size'; 11 | @import 'font-weight'; 12 | @import 'line-style'; 13 | @import 'line-width'; 14 | @import 'text-measure'; 15 | @import 'wrapper-width'; 16 | @import 'flex-grid'; 17 | @import 'spacing'; 18 | @import 'coordinate'; 19 | @import 'ratio'; 20 | @import 'angle'; 21 | @import 'duration'; 22 | @import 'easing'; 23 | @import 'border-radius'; 24 | @import 'box-shadow'; 25 | @import 'text-shadow'; 26 | @import 'keyframe'; 27 | @import 'module'; 28 | -------------------------------------------------------------------------------- /test/tokens/helpers/angle.scss: -------------------------------------------------------------------------------- 1 | @include describe('angle [func]') { 2 | 3 | @include it('Returns a `angle` value from the `TOKENS` map') { 4 | $__SCARAB: ( 5 | 'TOKENS': ( 6 | 'angle': ( 7 | '0': 0, 8 | 'slant': 15deg, 9 | 'right': 90deg 10 | ) 11 | ) 12 | ) !global; 13 | 14 | @include assert-equal( 15 | angle(slant), 16 | 15deg 17 | ); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /test/tokens/helpers/background-image.scss: -------------------------------------------------------------------------------- 1 | @include describe('background-image [func]') { 2 | 3 | @include it('Returns a `background-image` value from the `TOKENS` map') { 4 | $__SCARAB: ( 5 | 'TOKENS': ( 6 | 'background-image': ( 7 | '0': none, 8 | 'tiles': url(../images/tiles.png) 9 | ) 10 | ) 11 | ) !global; 12 | 13 | @include assert-equal( 14 | background-image(tiles), 15 | 'url(../images/tiles.png)' 16 | ); 17 | } 18 | 19 | } 20 | 21 | @include describe('bgi [func]') { 22 | 23 | @include it('Returns a `background-image` value from the `TOKENS` map') { 24 | $__SCARAB: ( 25 | 'TOKENS': ( 26 | 'background-image': ( 27 | '0': none, 28 | 'tiles': url(../images/tiles.png) 29 | ) 30 | ) 31 | ) !global; 32 | 33 | @include assert-equal( 34 | bgi(tiles), 35 | 'url(../images/tiles.png)' 36 | ); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /test/tokens/helpers/baseline.scss: -------------------------------------------------------------------------------- 1 | @include describe('baseline [func]') { 2 | 3 | @include it('Returns a multiple of `get(baseline)`') { 4 | $__SCARAB: ( 5 | 'TOKENS': ( 6 | 'baseline': 20px 7 | ) 8 | ) !global; 9 | 10 | @include assert-equal( 11 | baseline(3), 12 | 60px, 13 | 'Positive integer' 14 | ); 15 | 16 | @include assert-equal( 17 | baseline(1.5), 18 | 30px, 19 | 'Positive float' 20 | ); 21 | 22 | @include assert-equal( 23 | baseline(-2), 24 | -40px, 25 | 'Negative integer' 26 | ); 27 | 28 | @include assert-equal( 29 | baseline(-0.468), 30 | -9.36px, 31 | 'Negative float' 32 | ); 33 | } 34 | 35 | @include it('Defaults to the baseline value if no $multiplier is defined') { 36 | $__SCARAB: ( 37 | 'TOKENS': ( 38 | 'baseline': 1rem 39 | ) 40 | ) !global; 41 | 42 | @include assert-equal( 43 | baseline(), 44 | 1rem 45 | ); 46 | } 47 | 48 | } 49 | 50 | @include describe('bl [func]') { 51 | 52 | @include it('Returns a multiple of `get(baseline)`') { 53 | $__SCARAB: ( 54 | 'TOKENS': ( 55 | 'baseline': 20px 56 | ) 57 | ) !global; 58 | 59 | @include assert-equal( 60 | bl(3), 61 | 60px, 62 | 'Positive integer' 63 | ); 64 | 65 | @include assert-equal( 66 | bl(1.5), 67 | 30px, 68 | 'Positive float' 69 | ); 70 | 71 | @include assert-equal( 72 | bl(-2), 73 | -40px, 74 | 'Negative integer' 75 | ); 76 | 77 | @include assert-equal( 78 | bl(-0.468), 79 | -9.36px, 80 | 'Negative float' 81 | ); 82 | } 83 | 84 | @include it('Defaults to the baseline value if no $multiplier is defined') { 85 | $__SCARAB: ( 86 | 'TOKENS': ( 87 | 'baseline': 1rem 88 | ) 89 | ) !global; 90 | 91 | @include assert-equal( 92 | bl(), 93 | 1rem 94 | ); 95 | } 96 | 97 | } 98 | 99 | -------------------------------------------------------------------------------- /test/tokens/helpers/border-radius.scss: -------------------------------------------------------------------------------- 1 | @include describe('border-radius [func]') { 2 | 3 | @include it('Returns a `border-radius` value from the `TOKENS` map') { 4 | $__SCARAB: ( 5 | 'TOKENS': ( 6 | 'border-radius': ( 7 | '0': linear, 8 | 'pill': 9999px, 9 | 'round': 100% 10 | ) 11 | ) 12 | ) !global; 13 | 14 | @include assert-equal( 15 | border-radius(pill), 16 | 9999px 17 | ); 18 | } 19 | 20 | } 21 | 22 | @include describe('radius [func]') { 23 | 24 | @include it('Returns a `border-radius` value from the `TOKENS` map') { 25 | $__SCARAB: ( 26 | 'TOKENS': ( 27 | 'border-radius': ( 28 | '0': linear, 29 | 'pill': 9999px, 30 | 'round': 100% 31 | ) 32 | ) 33 | ) !global; 34 | 35 | @include assert-equal( 36 | radius(pill), 37 | 9999px 38 | ); 39 | } 40 | 41 | } 42 | 43 | @include describe('bdr [func]') { 44 | 45 | @include it('Returns a `border-radius` value from the `TOKENS` map') { 46 | $__SCARAB: ( 47 | 'TOKENS': ( 48 | 'border-radius': ( 49 | '0': linear, 50 | 'pill': 9999px, 51 | 'round': 100% 52 | ) 53 | ) 54 | ) !global; 55 | 56 | @include assert-equal( 57 | bdr(pill), 58 | 9999px 59 | ); 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /test/tokens/helpers/box-shadow.scss: -------------------------------------------------------------------------------- 1 | @include describe('box-shadow [func]') { 2 | 3 | @include it('Returns a `box-shadow` value from the `TOKENS` map') { 4 | $__SCARAB: ( 5 | 'TOKENS': ( 6 | 'box-shadow': ( 7 | '0': linear, 8 | 's': 0 2px 4px rgba(0,0,0,0.2), 9 | 'm': 0 3px 6px rgba(0,0,0,0.2), 10 | 'l': 0 4px 6px rgba(0,0,0,0.2) 11 | ) 12 | ) 13 | ) !global; 14 | 15 | @include assert-equal( 16 | box-shadow(m), 17 | 0 3px 6px rgba(0,0,0,0.2) 18 | ); 19 | } 20 | 21 | } 22 | 23 | @include describe('bsh [func]') { 24 | 25 | @include it('Returns a `box-shadow` value from the `TOKENS` map') { 26 | $__SCARAB: ( 27 | 'TOKENS': ( 28 | 'box-shadow': ( 29 | '0': linear, 30 | 's': 0 2px 4px rgba(0,0,0,0.2), 31 | 'm': 0 3px 6px rgba(0,0,0,0.2), 32 | 'l': 0 4px 6px rgba(0,0,0,0.2) 33 | ) 34 | ) 35 | ) !global; 36 | 37 | @include assert-equal( 38 | bsh(m), 39 | 0 3px 6px rgba(0,0,0,0.2) 40 | ); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /test/tokens/helpers/breakpoint.scss: -------------------------------------------------------------------------------- 1 | @include describe('breakpoint [func]') { 2 | 3 | @include it('Returns a `breakpoint` value from the `TOKENS` map') { 4 | $__SCARAB: ( 5 | 'TOKENS': ( 6 | 'breakpoint': ( 7 | 's': 25em, 8 | 'm': 40em, 9 | 'l': 65em 10 | ) 11 | ) 12 | ) !global; 13 | 14 | @include assert-equal( 15 | breakpoint(m), 16 | 40em 17 | ); 18 | } 19 | 20 | } 21 | 22 | @include describe('bp [func]') { 23 | 24 | @include it('Returns a `breakpoint` value from the `TOKENS` map') { 25 | $__SCARAB: ( 26 | 'TOKENS': ( 27 | 'breakpoint': ( 28 | 's': 25em, 29 | 'm': 40em, 30 | 'l': 65em 31 | ) 32 | ) 33 | ) !global; 34 | 35 | @include assert-equal( 36 | bp(m), 37 | 40em 38 | ); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /test/tokens/helpers/color.scss: -------------------------------------------------------------------------------- 1 | @include describe('color [func]') { 2 | 3 | @include it('Returns a `color` value from the `TOKENS` map') { 4 | $__SCARAB: ( 5 | 'OPTIONS': ( 6 | 'namescheme': ( 7 | 'default-key': '_' 8 | ) 9 | ), 10 | 'TOKENS': ( 11 | 'color': ( 12 | 'transparent': transparent, 13 | 'red': #ff0000, 14 | 'blue': ( 15 | '_' : blue, 16 | '1' : #0000ff, 17 | '2' : #000099, 18 | '3' : #000033, 19 | ) 20 | ) 21 | ), 22 | ) !global; 23 | 24 | @include assert-equal( 25 | color(transparent), 26 | transparent, 27 | 'Single-level color' 28 | ); 29 | 30 | @include assert-equal( 31 | color(red), 32 | #ff0000, 33 | 'Single-level color' 34 | ); 35 | 36 | @include assert-equal( 37 | color(blue), 38 | blue, 39 | 'Default color' 40 | ); 41 | 42 | @include assert-equal( 43 | color(blue, 2), 44 | #000099, 45 | 'Nested color' 46 | ); 47 | } 48 | 49 | } 50 | 51 | @include describe('c [func]') { 52 | 53 | @include it('Returns a `color` value from the `TOKENS` map') { 54 | $__SCARAB: ( 55 | 'OPTIONS': ( 56 | 'namescheme': ( 57 | 'default-key': '_' 58 | ) 59 | ), 60 | 'TOKENS': ( 61 | 'color': ( 62 | 'transparent': transparent, 63 | 'red': #ff0000, 64 | 'blue': ( 65 | '_': blue, 66 | '1': #0000ff, 67 | '2': #000099, 68 | '3': #000033, 69 | ) 70 | ) 71 | ) 72 | ) !global; 73 | 74 | @include assert-equal( 75 | c(transparent), 76 | transparent, 77 | 'Single-level color' 78 | ); 79 | 80 | @include assert-equal( 81 | c(red), 82 | #ff0000, 83 | 'Single-level color' 84 | ); 85 | 86 | @include assert-equal( 87 | color(blue), 88 | blue, 89 | 'Default color' 90 | ); 91 | 92 | @include assert-equal( 93 | c(blue, 2), 94 | #000099, 95 | 'Nested color' 96 | ); 97 | } 98 | 99 | } 100 | -------------------------------------------------------------------------------- /test/tokens/helpers/coordinate.scss: -------------------------------------------------------------------------------- 1 | @include describe('coordinate [func]') { 2 | 3 | @include it('Returns a `coordinate` value from the `TOKENS` map') { 4 | $__SCARAB: ( 5 | 'TOKENS': ( 6 | 'coordinate': ( 7 | '0': none, 8 | 's': 2rem, 9 | 'm': 4rem, 10 | 'l': 8rem 11 | ) 12 | ) 13 | ) !global; 14 | 15 | @include assert-equal( 16 | coordinate(l), 17 | 8rem 18 | ); 19 | } 20 | 21 | } 22 | 23 | @include describe('coord [func]') { 24 | 25 | @include it('Returns a `coordinate` value from the `TOKENS` map') { 26 | $__SCARAB: ( 27 | 'TOKENS': ( 28 | 'coordinate': ( 29 | '0': none, 30 | 's': 2rem, 31 | 'm': 4rem, 32 | 'l': 8rem 33 | ) 34 | ) 35 | ) !global; 36 | 37 | @include assert-equal( 38 | coord(l), 39 | 8rem 40 | ); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /test/tokens/helpers/duration.scss: -------------------------------------------------------------------------------- 1 | @include describe('duration [func]') { 2 | 3 | @include it('Returns a `duration` value from the `TOKENS` map') { 4 | $__SCARAB: ( 5 | 'TOKENS': ( 6 | 'duration': ( 7 | '0': 0, 8 | 's': 0.2s, 9 | 'm': 0.5s, 10 | 'l': 1s 11 | ) 12 | ) 13 | ) !global; 14 | 15 | @include assert-equal( 16 | duration(m), 17 | 0.5s 18 | ); 19 | } 20 | 21 | } 22 | 23 | @include describe('dur [func]') { 24 | 25 | @include it('Returns a `duration` value from the `TOKENS` map') { 26 | $__SCARAB: ( 27 | 'TOKENS': ( 28 | 'duration': ( 29 | '0': 0, 30 | 's': 0.2s, 31 | 'm': 0.5s, 32 | 'l': 1s 33 | ) 34 | ) 35 | ) !global; 36 | 37 | @include assert-equal( 38 | dur(m), 39 | 0.5s 40 | ); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /test/tokens/helpers/easing.scss: -------------------------------------------------------------------------------- 1 | @include describe('easing [func]') { 2 | 3 | @include it('Returns a `easing` value from the `TOKENS` map') { 4 | $__SCARAB: ( 5 | 'TOKENS': ( 6 | 'easing': ( 7 | '0': linear, 8 | 'out': ease-out, 9 | 'in': ease-in, 10 | 'out-quart': cubic-bezier(0.165, 0.84, 0.44, 1) 11 | ) 12 | ) 13 | ) !global; 14 | 15 | @include assert-equal( 16 | easing(out-quart), 17 | cubic-bezier(0.165, 0.84, 0.44, 1) 18 | ); 19 | } 20 | 21 | } 22 | 23 | @include describe('ease [func]') { 24 | 25 | @include it('Returns a `easing` value from the `TOKENS` map') { 26 | $__SCARAB: ( 27 | 'TOKENS': ( 28 | 'easing': ( 29 | '0': linear, 30 | 'out': ease-out, 31 | 'in': ease-in, 32 | 'out-quart': cubic-bezier(0.165, 0.84, 0.44, 1) 33 | ) 34 | ) 35 | ) !global; 36 | 37 | @include assert-equal( 38 | ease(out-quart), 39 | cubic-bezier(0.165, 0.84, 0.44, 1) 40 | ); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /test/tokens/helpers/flex-grid.scss: -------------------------------------------------------------------------------- 1 | @include describe('flex-grid [func]') { 2 | 3 | @include it('Returns a `flex-grid` value from the `TOKENS` map') { 4 | $__SCARAB: ( 5 | 'TOKENS': ( 6 | 'flex-grid': ( 7 | 'standard': 12, 8 | 'mini': 5 9 | ) 10 | ) 11 | ) !global; 12 | 13 | @include assert-equal( 14 | flex-grid(standard), 15 | 12 16 | ); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /test/tokens/helpers/font-family.scss: -------------------------------------------------------------------------------- 1 | @include describe('font-family [func]') { 2 | 3 | @include it('Returns a `font-family` value from the `TOKENS` map') { 4 | $__SCARAB: ( 5 | 'TOKENS': ( 6 | 'font-family': ( 7 | 'sans': ('Helvetica', sans-serif), 8 | 'serif': ('Georgia', serif) 9 | ) 10 | ) 11 | ) !global; 12 | 13 | @include assert-equal( 14 | font-family(sans), 15 | ('Helvetica', sans-serif) 16 | ); 17 | } 18 | 19 | } 20 | 21 | @include describe('ff [func]') { 22 | 23 | @include it('Returns a `font-family` value from the `TOKENS` map') { 24 | $__SCARAB: ( 25 | 'TOKENS': ( 26 | 'font-family': ( 27 | 'sans': ('Helvetica', sans-serif), 28 | 'serif': ('Georgia', serif) 29 | ) 30 | ) 31 | ) !global; 32 | 33 | @include assert-equal( 34 | ff(sans), 35 | ('Helvetica', sans-serif) 36 | ); 37 | } 38 | 39 | } 40 | 41 | @include describe('typeface [func]') { 42 | 43 | @include it('Returns a `font-family` value from the `TOKENS` map') { 44 | $__SCARAB: ( 45 | 'TOKENS': ( 46 | 'font-family': ( 47 | 'sans': ('Helvetica', sans-serif), 48 | 'serif': ('Georgia', serif) 49 | ) 50 | ) 51 | ) !global; 52 | 53 | @include assert-equal( 54 | typeface(sans), 55 | ('Helvetica', sans-serif) 56 | ); 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /test/tokens/helpers/font-size.scss: -------------------------------------------------------------------------------- 1 | @include describe('font-size [func]') { 2 | 3 | @include it('Returns a `font-size` value from the `TOKENS` map') { 4 | $__SCARAB: ( 5 | 'TOKENS': ( 6 | 'font-size': ( 7 | '0': 0, 8 | 'xs': 10px, 9 | 's': 13px, 10 | 'm': 16px, 11 | 'l': 19px, 12 | 'xl': 24px 13 | ) 14 | ) 15 | ) !global; 16 | 17 | @include assert-equal( 18 | font-size(l), 19 | 19px 20 | ); 21 | } 22 | 23 | } 24 | 25 | @include describe('fz [func]') { 26 | 27 | @include it('Returns a `font-size` value from the `TOKENS` map') { 28 | $__SCARAB: ( 29 | 'TOKENS': ( 30 | 'font-size': ( 31 | '0': 0, 32 | 'xs': 10px, 33 | 's': 13px, 34 | 'm': 16px, 35 | 'l': 19px, 36 | 'xl': 24px 37 | ) 38 | ) 39 | ) !global; 40 | 41 | @include assert-equal( 42 | fz(l), 43 | 19px 44 | ); 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /test/tokens/helpers/font-weight.scss: -------------------------------------------------------------------------------- 1 | @include describe('font-weight [func]') { 2 | 3 | @include it('Returns a `font-weight` value from the `TOKENS` map') { 4 | $__SCARAB: ( 5 | 'TOKENS': ( 6 | 'font-weight': ( 7 | '0': normal, 8 | 'bold': bold, 9 | 'extrabold': 800 10 | ) 11 | ) 12 | ) !global; 13 | 14 | @include assert-equal( 15 | font-weight(extrabold), 16 | 800 17 | ); 18 | } 19 | 20 | } 21 | 22 | @include describe('fw [func]') { 23 | 24 | @include it('Returns a `font-weight` value from the `TOKENS` map') { 25 | $__SCARAB: ( 26 | 'TOKENS': ( 27 | 'font-weight': ( 28 | '0': normal, 29 | 'bold': bold, 30 | 'extrabold': 800 31 | ) 32 | ) 33 | ) !global; 34 | 35 | @include assert-equal( 36 | fw(extrabold), 37 | 800 38 | ); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /test/tokens/helpers/gradient.scss: -------------------------------------------------------------------------------- 1 | @include describe('gradient [func]') { 2 | 3 | @include it('Returns a `gradient` value from the `TOKENS` map') { 4 | $__SCARAB: ( 5 | 'TOKENS': ( 6 | 'gradient': ( 7 | '0': none, 8 | 'hz-white-black': linear-gradient(to right, white 0%, black 100%) 9 | ) 10 | ) 11 | ) !global; 12 | 13 | @include assert-equal( 14 | gradient(hz-white-black), 15 | linear-gradient(to right, white 0%, black 100%) 16 | ); 17 | } 18 | 19 | } 20 | 21 | @include describe('g [func]') { 22 | 23 | @include it('Returns a `gradient` value from the `TOKENS` map') { 24 | $__SCARAB: ( 25 | 'TOKENS': ( 26 | 'gradient': ( 27 | '0': none, 28 | 'hz-white-black': linear-gradient(to right, white 0%, black 100%) 29 | ) 30 | ) 31 | ) !global; 32 | 33 | @include assert-equal( 34 | g(hz-white-black), 35 | linear-gradient(to right, white 0%, black 100%) 36 | ); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /test/tokens/helpers/keyframe.scss: -------------------------------------------------------------------------------- 1 | @include describe('keyframe [func]') { 2 | 3 | @include it('Returns a `keyframe` value from the `TOKENS` map') { 4 | $__SCARAB: ( 5 | 'TOKENS': ( 6 | 'keyframe': ( 7 | 'fade' : ( 8 | '0%': ( 9 | opacity: 0 10 | ), 11 | '100%': ( 12 | opacity: 1 13 | ) 14 | ) 15 | ) 16 | ) 17 | ) !global; 18 | 19 | @include assert-equal( 20 | keyframe(fade), 21 | ( 22 | '0%': ( 23 | opacity: 0 24 | ), 25 | '100%': ( 26 | opacity: 1 27 | ) 28 | ) 29 | ); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /test/tokens/helpers/letter-spacing.scss: -------------------------------------------------------------------------------- 1 | @include describe('letter-spacing [func]') { 2 | 3 | @include it('Returns a `letter-spacing` value from the `TOKENS` map') { 4 | $__SCARAB: ( 5 | 'TOKENS': ( 6 | 'letter-spacing': ( 7 | '0': 0, 8 | 'loose-1': 0.2em, 9 | 'tight-1': -0.2em 10 | ) 11 | ) 12 | ) !global; 13 | 14 | @include assert-equal( 15 | letter-spacing(loose-1), 16 | 0.2em 17 | ); 18 | } 19 | 20 | } 21 | 22 | @include describe('ls [func]') { 23 | 24 | @include it('Returns a `letter-spacing` value from the `TOKENS` map') { 25 | $__SCARAB: ( 26 | 'TOKENS': ( 27 | 'letter-spacing': ( 28 | '0': 0, 29 | 'loose-1': 0.2em, 30 | 'tight-1': -0.2em 31 | ) 32 | ) 33 | ) !global; 34 | 35 | @include assert-equal( 36 | ls(loose-1), 37 | 0.2em 38 | ); 39 | } 40 | 41 | } 42 | 43 | @include describe('tracking [func]') { 44 | 45 | @include it('Returns a `letter-spacing` value from the `TOKENS` map') { 46 | $__SCARAB: ( 47 | 'TOKENS': ( 48 | 'letter-spacing': ( 49 | '0': 0, 50 | 'loose-1': 0.2em, 51 | 'tight-1': -0.2em 52 | ) 53 | ) 54 | ) !global; 55 | 56 | @include assert-equal( 57 | tracking(loose-1), 58 | 0.2em 59 | ); 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /test/tokens/helpers/line-height.scss: -------------------------------------------------------------------------------- 1 | @include describe('line-height [func]') { 2 | 3 | @include it('Returns a `line-height` value from the `TOKENS` map') { 4 | $__SCARAB: ( 5 | 'TOKENS': ( 6 | 'line-height': ( 7 | '0': none, 8 | '1': 18px 9 | ) 10 | ) 11 | ) !global; 12 | 13 | @include assert-equal( 14 | line-height(1), 15 | 18px 16 | ); 17 | } 18 | 19 | } 20 | 21 | @include describe('lh [func]') { 22 | 23 | @include it('Returns a `line-height` value from the `TOKENS` map') { 24 | $__SCARAB: ( 25 | 'TOKENS': ( 26 | 'line-height': ( 27 | '0': none, 28 | '1': 18px 29 | ) 30 | ) 31 | ) !global; 32 | 33 | @include assert-equal( 34 | lh(1), 35 | 18px 36 | ); 37 | } 38 | 39 | } 40 | 41 | @include describe('leading [func]') { 42 | 43 | @include it('Returns a `line-height` value from the `TOKENS` map') { 44 | $__SCARAB: ( 45 | 'TOKENS': ( 46 | 'line-height': ( 47 | '0': none, 48 | '1': 18px 49 | ) 50 | ) 51 | ) !global; 52 | 53 | @include assert-equal( 54 | leading(1), 55 | 18px 56 | ); 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /test/tokens/helpers/line-style.scss: -------------------------------------------------------------------------------- 1 | @include describe('line-style [func]') { 2 | 3 | @include it('Returns a `line-style` value from the `TOKENS` map') { 4 | $__SCARAB: ( 5 | 'TOKENS': ( 6 | 'line-style': ( 7 | '0': none, 8 | 'dot': dotted 9 | ) 10 | ) 11 | ) !global; 12 | 13 | @include assert-equal( 14 | line-style(dot), 15 | dotted 16 | ); 17 | } 18 | 19 | } 20 | 21 | @include describe('lns [func]') { 22 | 23 | @include it('Returns a `line-style` value from the `TOKENS` map') { 24 | $__SCARAB: ( 25 | 'TOKENS': ( 26 | 'line-style': ( 27 | '0': none, 28 | 'dot': dotted 29 | ) 30 | ) 31 | ) !global; 32 | 33 | @include assert-equal( 34 | lns(dot), 35 | dotted 36 | ); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /test/tokens/helpers/line-width.scss: -------------------------------------------------------------------------------- 1 | @include describe('line-width [func]') { 2 | 3 | @include it('Returns a `line-width` value from the `TOKENS` map') { 4 | $__SCARAB: ( 5 | 'TOKENS': ( 6 | 'line-width': ( 7 | '0': none, 8 | 's': 1px, 9 | 'm': 3px, 10 | 'l': 5px 11 | ) 12 | ) 13 | ) !global; 14 | 15 | @include assert-equal( 16 | line-width(m), 17 | 3px 18 | ); 19 | } 20 | 21 | } 22 | 23 | @include describe('lnw [func]') { 24 | 25 | @include it('Returns a `line-width` value from the `TOKENS` map') { 26 | $__SCARAB: ( 27 | 'TOKENS': ( 28 | 'line-width': ( 29 | '0': none, 30 | 's': 1px, 31 | 'm': 3px, 32 | 'l': 5px 33 | ) 34 | ) 35 | ) !global; 36 | 37 | @include assert-equal( 38 | lnw(m), 39 | 3px 40 | ); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /test/tokens/helpers/module.scss: -------------------------------------------------------------------------------- 1 | @include describe('module [func]') { 2 | 3 | @include it('Returns a `module` value from the `TOKENS` map') { 4 | $__SCARAB: ( 5 | 'TOKENS': ( 6 | 'module': ( 7 | 'margin': ( 8 | root : 'm', 9 | values : get(spacing), 10 | breakpoints : get(breakpoint) 11 | ) 12 | ) 13 | ) 14 | ) !global; 15 | 16 | @include assert-equal( 17 | module(margin), 18 | ( 19 | root : 'm', 20 | values : get(spacing), 21 | breakpoints : get(breakpoint) 22 | ) 23 | ); 24 | 25 | @include assert-equal( 26 | module(margin, root), 27 | 'm' 28 | ); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /test/tokens/helpers/opacity.scss: -------------------------------------------------------------------------------- 1 | @include describe('opacity [func]') { 2 | 3 | @include it('Returns a `opacity` value from the `TOKENS` map') { 4 | $__SCARAB: ( 5 | 'TOKENS': ( 6 | 'opacity': ( 7 | '0' : 0, 8 | '50': 0.5 9 | ) 10 | ) 11 | ) !global; 12 | 13 | @include assert-equal( 14 | opacity(50), 15 | 0.5 16 | ); 17 | } 18 | 19 | } 20 | 21 | @include describe('o [func]') { 22 | 23 | @include it('Returns a `opacity` value from the `TOKENS` map') { 24 | $__SCARAB: ( 25 | 'TOKENS': ( 26 | 'opacity': ( 27 | '0' : 0, 28 | '50': 0.5 29 | ) 30 | ) 31 | ) !global; 32 | 33 | @include assert-equal( 34 | o(50), 35 | 0.5 36 | ); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /test/tokens/helpers/ratio.scss: -------------------------------------------------------------------------------- 1 | @include describe('ratio [func]') { 2 | 3 | @include it('Returns a `ratio` value from the `TOKENS` map') { 4 | $__SCARAB: ( 5 | 'TOKENS': ( 6 | 'ratio': ( 7 | '0': 0, 8 | '1by2': (1/2)*100%, 9 | '3by4': (3/4)*100%, 10 | '16by9': (16/9)*100% 11 | ) 12 | ) 13 | ) !global; 14 | 15 | @include assert-equal( 16 | ratio(16by9), 17 | (16/9)*100% 18 | ); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /test/tokens/helpers/spacing.scss: -------------------------------------------------------------------------------- 1 | @include describe('spacing [func]') { 2 | 3 | @include it('Returns a `spacing` value from the `TOKENS` map') { 4 | $__SCARAB: ( 5 | 'TOKENS': ( 6 | 'spacing': ( 7 | '0': none, 8 | 's': 2rem, 9 | 'm': 4rem, 10 | 'l': 8rem 11 | ) 12 | ) 13 | ) !global; 14 | 15 | @include assert-equal( 16 | spacing(l), 17 | 8rem 18 | ); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /test/tokens/helpers/text-measure.scss: -------------------------------------------------------------------------------- 1 | @include describe('text-measure [func]') { 2 | 3 | @include it('Returns a `measure` value from the `TOKENS` map') { 4 | $__SCARAB: ( 5 | 'TOKENS': ( 6 | 'text-measure': ( 7 | '0': none, 8 | 's': 12em, 9 | 'm': 20em, 10 | 'l': 30em 11 | ) 12 | ) 13 | ) !global; 14 | 15 | @include assert-equal( 16 | text-measure(m), 17 | 20em 18 | ); 19 | } 20 | 21 | } 22 | 23 | @include describe('measure [func]') { 24 | 25 | @include it('Returns a `measure` value from the `TOKENS` map') { 26 | $__SCARAB: ( 27 | 'TOKENS': ( 28 | 'text-measure': ( 29 | '0': none, 30 | 's': 12em, 31 | 'm': 20em, 32 | 'l': 30em 33 | ) 34 | ) 35 | ) !global; 36 | 37 | @include assert-equal( 38 | measure(m), 39 | 20em 40 | ); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /test/tokens/helpers/text-shadow.scss: -------------------------------------------------------------------------------- 1 | @include describe('text-shadow [func]') { 2 | 3 | @include it('Returns a `text-shadow` value from the `TOKENS` map') { 4 | $__SCARAB: ( 5 | 'TOKENS': ( 6 | 'text-shadow': ( 7 | '0': linear, 8 | 's': 0 2px 4px rgba(0,0,0,0.2), 9 | 'm': 0 3px 6px rgba(0,0,0,0.2), 10 | 'l': 0 4px 6px rgba(0,0,0,0.2) 11 | ) 12 | ) 13 | ) !global; 14 | 15 | @include assert-equal( 16 | text-shadow(m), 17 | 0 3px 6px rgba(0,0,0,0.2) 18 | ); 19 | } 20 | 21 | } 22 | 23 | @include describe('tsh [func]') { 24 | 25 | @include it('Returns a `text-shadow` value from the `TOKENS` map') { 26 | $__SCARAB: ( 27 | 'TOKENS': ( 28 | 'text-shadow': ( 29 | '0': linear, 30 | 's': 0 2px 4px rgba(0,0,0,0.2), 31 | 'm': 0 3px 6px rgba(0,0,0,0.2), 32 | 'l': 0 4px 6px rgba(0,0,0,0.2) 33 | ) 34 | ) 35 | ) !global; 36 | 37 | @include assert-equal( 38 | tsh(m), 39 | 0 3px 6px rgba(0,0,0,0.2) 40 | ); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /test/tokens/helpers/wrapper-width.scss: -------------------------------------------------------------------------------- 1 | @include describe('wrapper-width [func]') { 2 | 3 | @include it('Returns a `wrap` value from the `TOKENS` map') { 4 | $__SCARAB: ( 5 | 'TOKENS': ( 6 | 'wrapper-width': ( 7 | '0': none, 8 | 's': 15rem, 9 | 'm': 22.5rem, 10 | 'l': 35rem 11 | ) 12 | ) 13 | ) !global; 14 | 15 | @include assert-equal( 16 | wrapper-width(l), 17 | 35rem 18 | ); 19 | } 20 | 21 | } 22 | 23 | @include describe('wrap [func]') { 24 | 25 | @include it('Returns a `wrap` value from the `TOKENS` map') { 26 | $__SCARAB: ( 27 | 'TOKENS': ( 28 | 'wrapper-width': ( 29 | '0': none, 30 | 's': 15rem, 31 | 'm': 22.5rem, 32 | 'l': 35rem 33 | ) 34 | ) 35 | ) !global; 36 | 37 | @include assert-equal( 38 | wrap(l), 39 | 35rem 40 | ); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /test/tokens/set-default.scss: -------------------------------------------------------------------------------- 1 | @include describe('set-default [func]') { 2 | 3 | @include it('Sets a new value in the `TOKENS` map') { 4 | $__SCARAB: ( 5 | 'TOKENS': () 6 | ) !global; 7 | 8 | $_: set-default(baseline, 2rem); 9 | 10 | @include assert-equal( 11 | inspect($__SCARAB), 12 | inspect(( 13 | 'TOKENS': ( 14 | 'baseline': 2rem 15 | ) 16 | )), 17 | 'Register value for a key does not exist' 18 | ); 19 | 20 | 21 | 22 | $__SCARAB: ( 23 | 'TOKENS': ( 24 | 'baseline': 1rem 25 | ) 26 | ) !global; 27 | 28 | $_: set-default(baseline, 2rem); 29 | 30 | @include assert-equal( 31 | inspect($__SCARAB), 32 | inspect(( 33 | 'TOKENS': ( 34 | 'baseline': 1rem 35 | ) 36 | )), 37 | 'Fails to register value for existing keys' 38 | ); 39 | 40 | 41 | 42 | $__SCARAB: ( 43 | 'TOKENS': ( 44 | 'palettes': ( 45 | 'blue': ( 46 | 'light': lightblue, 47 | 'base': blue 48 | ) 49 | ) 50 | ) 51 | ) !global; 52 | 53 | $_: set-default(palettes, blue, dark, darkblue); 54 | 55 | @include assert-equal( 56 | inspect($__SCARAB), 57 | inspect(( 58 | 'TOKENS': ( 59 | 'palettes': ( 60 | 'blue': ( 61 | 'light': lightblue, 62 | 'base': blue, 63 | 'dark': darkblue 64 | ) 65 | ) 66 | ) 67 | )), 68 | 'Register value for a nested key does not exist' 69 | ); 70 | 71 | 72 | 73 | $__SCARAB: ( 74 | 'TOKENS': ( 75 | 'palettes': ( 76 | 'blue': ( 77 | 'light': lightblue, 78 | 'base': blue 79 | ) 80 | ) 81 | ) 82 | ) !global; 83 | 84 | $_: set-default(palettes, blue, light, skyblue); 85 | 86 | @include assert-equal( 87 | inspect($__SCARAB), 88 | inspect(( 89 | 'TOKENS': ( 90 | 'palettes': ( 91 | 'blue': ( 92 | 'light': lightblue, 93 | 'base': blue 94 | ) 95 | ) 96 | ) 97 | )), 98 | 'Fails to register a value for existing nested keys' 99 | ); 100 | } 101 | 102 | } 103 | 104 | 105 | 106 | @include describe('set-default [mixin]') { 107 | 108 | @include it('Sets a new value in the `TOKENS` map') { 109 | $__SCARAB: ( 110 | 'TOKENS': () 111 | ) !global; 112 | 113 | @include set-default(baseline, 2rem); 114 | 115 | @include assert-equal( 116 | inspect($__SCARAB), 117 | inspect(( 118 | 'TOKENS': ( 119 | 'baseline': 2rem 120 | ) 121 | )), 122 | 'Register value for a key does not exist' 123 | ); 124 | 125 | 126 | 127 | $__SCARAB: ( 128 | 'TOKENS': ( 129 | 'baseline': 1rem 130 | ) 131 | ) !global; 132 | 133 | @include set-default(baseline, 2rem); 134 | 135 | @include assert-equal( 136 | inspect($__SCARAB), 137 | inspect(( 138 | 'TOKENS': ( 139 | 'baseline': 1rem 140 | ) 141 | )), 142 | 'Fails to register value for existing keys' 143 | ); 144 | 145 | 146 | 147 | $__SCARAB: ( 148 | 'TOKENS': ( 149 | 'palettes': ( 150 | 'blue': ( 151 | 'light': lightblue, 152 | 'base': blue 153 | ) 154 | ) 155 | ) 156 | ) !global; 157 | 158 | @include set-default(palettes, blue, dark, darkblue); 159 | 160 | @include assert-equal( 161 | inspect($__SCARAB), 162 | inspect(( 163 | 'TOKENS': ( 164 | 'palettes': ( 165 | 'blue': ( 166 | 'light': lightblue, 167 | 'base': blue, 168 | 'dark': darkblue 169 | ) 170 | ) 171 | ) 172 | )), 173 | 'Register value for a nested key does not exist' 174 | ); 175 | 176 | 177 | 178 | $__SCARAB: ( 179 | 'TOKENS': ( 180 | 'palettes': ( 181 | 'blue': ( 182 | 'light': lightblue, 183 | 'base': blue 184 | ) 185 | ) 186 | ) 187 | ) !global; 188 | 189 | @include set-default(palettes, blue, light, skyblue); 190 | 191 | @include assert-equal( 192 | inspect($__SCARAB), 193 | inspect(( 194 | 'TOKENS': ( 195 | 'palettes': ( 196 | 'blue': ( 197 | 'light': lightblue, 198 | 'base': blue 199 | ) 200 | ) 201 | ) 202 | )), 203 | 'Fails to register a value for existing nested keys' 204 | ); 205 | } 206 | 207 | } 208 | -------------------------------------------------------------------------------- /test/tokens/set.scss: -------------------------------------------------------------------------------- 1 | @include describe('set [func]') { 2 | 3 | @include it('Sets a new value in the `TOKENS` map') { 4 | $__SCARAB: ( 5 | 'TOKENS': () 6 | ) !global; 7 | 8 | $_: set(baseline, 2rem); 9 | 10 | @include assert-equal( 11 | inspect($__SCARAB), 12 | inspect(( 13 | 'TOKENS': ( 14 | 'baseline': 2rem 15 | ) 16 | )), 17 | 'Register value for new key' 18 | ); 19 | 20 | 21 | 22 | $__SCARAB: ( 23 | 'TOKENS': () 24 | ) !global; 25 | 26 | $_: set(breakpoints, custom, 777px); 27 | 28 | @include assert-equal( 29 | inspect($__SCARAB), 30 | inspect(( 31 | 'TOKENS': ( 32 | 'breakpoints': ( 33 | 'custom': 777px 34 | ) 35 | ) 36 | )), 37 | 'Register value for new nested key' 38 | ); 39 | 40 | 41 | 42 | 43 | $__SCARAB: ( 44 | 'TOKENS': ( 45 | 'baseline': 2rem 46 | ) 47 | ) !global; 48 | 49 | $_: set(baseline, 0.5rem); 50 | 51 | @include assert-equal( 52 | inspect($__SCARAB), 53 | inspect(( 54 | 'TOKENS': ( 55 | 'baseline': 0.5rem 56 | ) 57 | )), 58 | 'Update value for existing key' 59 | ); 60 | 61 | 62 | 63 | $__SCARAB: ( 64 | 'TOKENS': () 65 | ) !global; 66 | 67 | $_: set(palettes, ( 68 | blue: ( 69 | light: skyblue, 70 | base: blue, 71 | dark: darkblue 72 | ) 73 | )); 74 | 75 | @include assert-equal( 76 | inspect($__SCARAB), 77 | inspect(( 78 | 'TOKENS': ( 79 | 'palettes': ( 80 | 'blue': ( 81 | 'light': skyblue, 82 | 'base': blue, 83 | 'dark': darkblue 84 | ) 85 | ) 86 | ) 87 | )), 88 | 'Set a map-based value' 89 | ); 90 | 91 | 92 | 93 | $__SCARAB: ( 94 | 'TOKENS': () 95 | ) !global; 96 | 97 | $_: set(palettes, blue, ( 98 | light: skyblue, 99 | base: blue, 100 | dark: darkblue 101 | )); 102 | 103 | @include assert-equal( 104 | inspect($__SCARAB), 105 | inspect(( 106 | 'TOKENS': ( 107 | 'palettes': ( 108 | 'blue': ( 109 | 'light': skyblue, 110 | 'base': blue, 111 | 'dark': darkblue 112 | ) 113 | ) 114 | ) 115 | )), 116 | 'Set a nested map-based value' 117 | ); 118 | } 119 | 120 | } 121 | 122 | 123 | 124 | @include describe('set [mixin]') { 125 | 126 | @include it('Sets a new value in the `TOKENS` map') { 127 | $__SCARAB: ( 128 | 'TOKENS': () 129 | ) !global; 130 | 131 | @include set(baseline, 2rem); 132 | 133 | @include assert-equal( 134 | inspect($__SCARAB), 135 | inspect(( 136 | 'TOKENS': ( 137 | 'baseline': 2rem 138 | ) 139 | )), 140 | 'Register value for new key' 141 | ); 142 | 143 | 144 | 145 | $__SCARAB: ( 146 | 'TOKENS': () 147 | ) !global; 148 | 149 | @include set(breakpoints, custom, 777px); 150 | 151 | @include assert-equal( 152 | inspect($__SCARAB), 153 | inspect(( 154 | 'TOKENS': ( 155 | 'breakpoints': ( 156 | 'custom': 777px 157 | ) 158 | ) 159 | )), 160 | 'Register value for new nested key' 161 | ); 162 | 163 | 164 | 165 | 166 | $__SCARAB: ( 167 | 'TOKENS': ( 168 | 'baseline': 2rem 169 | ) 170 | ) !global; 171 | 172 | @include set(baseline, 0.5rem); 173 | 174 | @include assert-equal( 175 | inspect($__SCARAB), 176 | inspect(( 177 | 'TOKENS': ( 178 | 'baseline': 0.5rem 179 | ) 180 | )), 181 | 'Update value for existing key' 182 | ); 183 | 184 | 185 | 186 | $__SCARAB: ( 187 | 'TOKENS': () 188 | ) !global; 189 | 190 | @include set(palettes, ( 191 | blue: ( 192 | light: skyblue, 193 | base: blue, 194 | dark: darkblue 195 | ) 196 | )); 197 | 198 | @include assert-equal( 199 | inspect($__SCARAB), 200 | inspect(( 201 | 'TOKENS': ( 202 | 'palettes': ( 203 | 'blue': ( 204 | 'light': skyblue, 205 | 'base': blue, 206 | 'dark': darkblue 207 | ) 208 | ) 209 | ) 210 | )), 211 | 'Set a map-based value' 212 | ); 213 | 214 | 215 | 216 | $__SCARAB: ( 217 | 'TOKENS': () 218 | ) !global; 219 | 220 | @include set(palettes, blue, ( 221 | light: skyblue, 222 | base: blue, 223 | dark: darkblue 224 | )); 225 | 226 | @include assert-equal( 227 | inspect($__SCARAB), 228 | inspect(( 229 | 'TOKENS': ( 230 | 'palettes': ( 231 | 'blue': ( 232 | 'light': skyblue, 233 | 'base': blue, 234 | 'dark': darkblue 235 | ) 236 | ) 237 | ) 238 | )), 239 | 'Set a nested map-based value' 240 | ); 241 | } 242 | 243 | } 244 | -------------------------------------------------------------------------------- /test/tokens/unset.scss: -------------------------------------------------------------------------------- 1 | @include describe('unset [func]') { 2 | 3 | @include it('Removes a key-value pair from the `TOKENS` map') { 4 | $__SCARAB: ( 5 | 'TOKENS': ( 6 | 'baseline': 1rem, 7 | 'breakpoints': ( 8 | 's': 100px, 9 | 'm': 200px, 10 | 'l': 300px 11 | ) 12 | ) 13 | ) !global; 14 | 15 | $_: unset(baseline); 16 | 17 | @include assert-equal( 18 | inspect($__SCARAB), 19 | inspect(( 20 | 'TOKENS': ( 21 | 'breakpoints': ( 22 | 's': 100px, 23 | 'm': 200px, 24 | 'l': 300px 25 | ) 26 | ) 27 | )) 28 | ); 29 | 30 | 31 | 32 | $__SCARAB: ( 33 | 'TOKENS': ( 34 | 'baseline': 1rem, 35 | 'palettes': ( 36 | 'blue': ( 37 | 'light': skyblue, 38 | 'base': blue, 39 | 'dark': darkblue 40 | ) 41 | ) 42 | ) 43 | ) !global; 44 | 45 | $_: unset(palettes, blue, base); 46 | 47 | @include assert-equal( 48 | inspect($__SCARAB), 49 | inspect(( 50 | 'TOKENS': ( 51 | 'baseline': 1rem, 52 | 'palettes': ( 53 | 'blue': ( 54 | 'light': skyblue, 55 | 'dark': darkblue 56 | ) 57 | ) 58 | ) 59 | )), 60 | 'Removes a nested key' 61 | ); 62 | 63 | 64 | 65 | $__SCARAB: ( 66 | 'TOKENS': ( 67 | 'baseline': 1rem, 68 | 'palettes': ( 69 | 'blue': ( 70 | 'light': skyblue, 71 | 'base': blue, 72 | 'dark': darkblue 73 | ) 74 | ) 75 | ) 76 | ) !global; 77 | 78 | $_: unset(palettes, blue); 79 | 80 | @include assert-equal( 81 | inspect($__SCARAB), 82 | inspect(( 83 | 'TOKENS': ( 84 | 'baseline': 1rem, 85 | 'palettes': ( 86 | ) 87 | ) 88 | )), 89 | 'Removes a nested key that is a color name' 90 | ); 91 | } 92 | 93 | } 94 | 95 | 96 | 97 | @include describe('unset [mixin]') { 98 | 99 | @include it('Removes a key-value pair from the `TOKENS` map') { 100 | $__SCARAB: ( 101 | 'TOKENS': ( 102 | 'baseline': 1rem, 103 | 'breakpoints': ( 104 | 's': 100px, 105 | 'm': 200px, 106 | 'l': 300px 107 | ) 108 | ) 109 | ) !global; 110 | 111 | @include unset(baseline); 112 | 113 | @include assert-equal( 114 | inspect($__SCARAB), 115 | inspect(( 116 | 'TOKENS': ( 117 | 'breakpoints': ( 118 | 's': 100px, 119 | 'm': 200px, 120 | 'l': 300px 121 | ) 122 | ) 123 | )) 124 | ); 125 | 126 | 127 | 128 | $__SCARAB: ( 129 | 'TOKENS': ( 130 | 'baseline': 1rem, 131 | 'palettes': ( 132 | 'blue': ( 133 | 'light': skyblue, 134 | 'base': blue, 135 | 'dark': darkblue 136 | ) 137 | ) 138 | ) 139 | ) !global; 140 | 141 | @include unset(palettes, blue, base); 142 | 143 | @include assert-equal( 144 | inspect($__SCARAB), 145 | inspect(( 146 | 'TOKENS': ( 147 | 'baseline': 1rem, 148 | 'palettes': ( 149 | 'blue': ( 150 | 'light': skyblue, 151 | 'dark': darkblue 152 | ) 153 | ) 154 | ) 155 | )), 156 | 'Removes a nested key' 157 | ); 158 | 159 | 160 | 161 | $__SCARAB: ( 162 | 'TOKENS': ( 163 | 'baseline': 1rem, 164 | 'palettes': ( 165 | 'blue': ( 166 | 'light': skyblue, 167 | 'base': blue, 168 | 'dark': darkblue 169 | ) 170 | ) 171 | ) 172 | ) !global; 173 | 174 | @include unset(palettes, blue); 175 | 176 | @include assert-equal( 177 | inspect($__SCARAB), 178 | inspect(( 179 | 'TOKENS': ( 180 | 'baseline': 1rem, 181 | 'palettes': ( 182 | ) 183 | ) 184 | )), 185 | 'Removes a nested key that is a color name' 186 | ); 187 | } 188 | 189 | } 190 | --------------------------------------------------------------------------------