├── lib ├── flint │ ├── version.rb │ └── functions.rb ├── flint-gs.rb └── flint.rb ├── .gitignore ├── .gitmodules ├── .travis.yml ├── stylesheets ├── _flint.scss └── flint │ ├── mixins │ ├── _mixins.scss │ └── lib │ │ ├── _box-sizing.scss │ │ ├── _clearfix.scss │ │ ├── _new-instance.scss │ │ ├── _print-instance.scss │ │ ├── _container.scss │ │ ├── _grid-overlay.scss │ │ ├── _calculate.scss │ │ └── _main.scss │ ├── functions │ ├── lib │ │ ├── _last.scss │ │ ├── _get-value.scss │ │ ├── _fluid-width.scss │ │ ├── _next-index.scss │ │ ├── _remove.scss │ │ ├── _steal-values.scss │ │ ├── _get-index.scss │ │ ├── _get-instance-value.scss │ │ ├── _purge.scss │ │ ├── _use-syntax.scss │ │ ├── _replace.scss │ │ ├── _map-fetch.scss │ │ ├── _steal-key.scss │ │ ├── _list-to-str.scss │ │ ├── _support-syntax.scss │ │ ├── _str-replace.scss │ │ ├── _support-syntax-bem.scss │ │ ├── _calc-breakpoint.scss │ │ ├── _html-encode.scss │ │ ├── _instance.scss │ │ ├── _types-in-list.scss │ │ ├── _calc-width.scss │ │ ├── _has-family-instance.scss │ │ └── _str-to-list.scss │ ├── _functions.scss │ └── helpers │ │ └── _helpers.scss │ ├── config │ └── _config.scss │ └── globals │ └── _globals.scss ├── Gemfile ├── .editorconfig ├── sache.json ├── tests ├── input │ ├── functions │ │ ├── lib │ │ │ ├── _remove.scss │ │ │ ├── _purge.scss │ │ │ ├── _str-replace.scss │ │ │ ├── _use-syntax.scss │ │ │ ├── _last.scss │ │ │ ├── _replace.scss │ │ │ ├── _steal-values.scss │ │ │ ├── _steal-key.scss │ │ │ ├── _support-syntax-bem.scss │ │ │ ├── _next-index.scss │ │ │ ├── _support-syntax.scss │ │ │ ├── _get-value.scss │ │ │ ├── _list-to-str.scss │ │ │ ├── _map-fetch.scss │ │ │ ├── _fluid-width.scss │ │ │ ├── _get-index.scss │ │ │ ├── _has-family-instance.scss │ │ │ ├── _str-to-list.scss │ │ │ ├── _types-in-list.scss │ │ │ ├── _get-instance-value.scss │ │ │ ├── _calc-breakpoint.scss │ │ │ ├── _instance.scss │ │ │ └── _calc-width.scss │ │ ├── _functions.scss │ │ └── helpers │ │ │ └── _helpers.scss │ └── output.scss ├── config.rb └── tests.html ├── bower.json ├── Rakefile ├── package.json ├── flint.gemspec ├── LICENSE ├── CONTRIBUTING.md ├── README.md └── CHANGELOG.md /lib/flint/version.rb: -------------------------------------------------------------------------------- 1 | module Flint 2 | VERSION = "2.3.7" 3 | end 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.log 2 | *.gem 3 | Gemfile.lock 4 | .DS_Store 5 | .sass-cache/ 6 | sassdoc/ 7 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "tests/bootcamp"] 2 | path = tests/bootcamp 3 | url = git://github.com/thejameskyle/bootcamp.git 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: ruby 2 | install: 3 | - git submodule update --init --recursive 4 | - bundle install 5 | sudo: false 6 | -------------------------------------------------------------------------------- /stylesheets/_flint.scss: -------------------------------------------------------------------------------- 1 | // 2 | // Flint 3 | // 4 | @import "flint/config/config"; 5 | @import "flint/functions/functions"; 6 | @import "flint/globals/globals"; 7 | @import "flint/mixins/mixins"; 8 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | gem "sass", "~> 3.4" 4 | 5 | group :test do 6 | gem "bundler", "~> 1.7" 7 | gem "rake", "~> 10.0" 8 | gem "compass", "~> 1.0" 9 | gem "sass-prof", :require => false 10 | end 11 | -------------------------------------------------------------------------------- /lib/flint-gs.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | 3 | lib = File.expand_path "../../lib/", __FILE__ 4 | $:.unshift lib unless $:.include? lib 5 | 6 | # FIXME: Fixes an issue with Rails integration due to the gem being named 7 | # `flint-gs`, but the lib being named `flint` (issue #37) 8 | require "flint" 9 | -------------------------------------------------------------------------------- /stylesheets/flint/mixins/_mixins.scss: -------------------------------------------------------------------------------- 1 | // 2 | // Mixins 3 | // 4 | @import "lib/clearfix"; 5 | @import "lib/box-sizing"; 6 | @import "lib/grid-overlay"; 7 | @import "lib/container"; 8 | @import "lib/new-instance"; 9 | @import "lib/print-instance"; 10 | @import "lib/calculate"; 11 | @import "lib/main"; 12 | -------------------------------------------------------------------------------- /stylesheets/flint/functions/lib/_last.scss: -------------------------------------------------------------------------------- 1 | /// 2 | /// Get last item in list 3 | /// 4 | /// @access private 5 | /// 6 | /// @param {List} $list 7 | /// 8 | /// @return {List} 9 | /// 10 | /// @group Internal Functions 11 | /// 12 | @function flint-last($list) { 13 | @return nth($list, length($list)); 14 | } 15 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | 3 | root = true 4 | 5 | # 6 | # Global 7 | # 8 | [*] 9 | indent_style = space 10 | indent_size = 2 11 | end_of_line = lf 12 | charset = utf-8 13 | trim_trailing_whitespace = true 14 | insert_final_newline = true 15 | 16 | # 17 | # Markdown 18 | # 19 | [*.{md,markdown}] 20 | trim_trailing_whitespace = false 21 | -------------------------------------------------------------------------------- /sache.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Flint", 3 | "description": "Flint is a highly advanced Sass grid framework designed for rapid responsive development. Only one mixin. No bloat. Completely semantic.", 4 | "tags": ["grid-system", "grid-framework", "framework", "ui", "grid", "layout", "flint", "breakpoint", "breakpoints", "semantic", "responsive-web-design"] 5 | } 6 | -------------------------------------------------------------------------------- /tests/input/functions/lib/_remove.scss: -------------------------------------------------------------------------------- 1 | // 2 | // Remove value from list 3 | // 4 | @include describe("[function] remove") { 5 | 6 | $list: ("one", "two", "three"); 7 | 8 | @include it("should expect value to be removed from list") { 9 | @include should(expect( 10 | flint-remove($list, "two")), 11 | to(be(("one", "three"))) 12 | ); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /stylesheets/flint/functions/lib/_get-value.scss: -------------------------------------------------------------------------------- 1 | /// 2 | /// Get single value from configuration map 3 | /// 4 | /// @access private 5 | /// 6 | /// @param {ArgList} $keys - list of keys to fetch value from 7 | /// 8 | /// @return {*} 9 | /// 10 | /// @group Internal Functions 11 | /// 12 | @function flint-get-value($keys...) { 13 | @return flint-map-fetch($flint, $keys...); 14 | } 15 | -------------------------------------------------------------------------------- /stylesheets/flint/functions/lib/_fluid-width.scss: -------------------------------------------------------------------------------- 1 | /// 2 | /// Convert fixed to fluid width 3 | /// 4 | /// @access private 5 | /// 6 | /// @param {Number} $target 7 | /// @param {Number} $context 8 | /// 9 | /// @return {Number} 10 | /// 11 | /// @group Internal Functions 12 | /// 13 | @function flint-fluid-width($target, $context) { 14 | @return ($target / $context) * 100%; 15 | } 16 | -------------------------------------------------------------------------------- /tests/input/functions/lib/_purge.scss: -------------------------------------------------------------------------------- 1 | // 2 | // Removes all false and null values from $list 3 | // 4 | @include describe("[function] purge") { 5 | 6 | $list: (true, false, "string", "", null, 1); 7 | 8 | @include it("should expect all falsey values to be removed") { 9 | @include should(expect( 10 | flint-purge($list)), 11 | to(be((true, "string", 1))) 12 | ); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /tests/input/functions/lib/_str-replace.scss: -------------------------------------------------------------------------------- 1 | // 2 | // Replace substring 3 | // 4 | @include describe("[function] str-replace") { 5 | 6 | $string: "this is a string"; 7 | 8 | @include it("should expect the substring to be updated inside of string") { 9 | @include should(expect( 10 | flint-str-replace($string, "a", "an awesome")), 11 | to(be("this is an awesome string")) 12 | ); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /tests/input/functions/lib/_use-syntax.scss: -------------------------------------------------------------------------------- 1 | // 2 | // Use global syntax 3 | // 4 | @include describe("[function] use-syntax") { 5 | 6 | $selectors: ".block__element--modifier"; 7 | 8 | @include it("should expect to return false unless syntax is set") { 9 | @include should(expect( 10 | flint-use-syntax($selectors)), 11 | to(be(false)) 12 | ); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /stylesheets/flint/functions/lib/_next-index.scss: -------------------------------------------------------------------------------- 1 | /// 2 | /// Returns next indexed key based on passed index 3 | /// 4 | /// @access private 5 | /// 6 | /// @param {Number} $index - index of breakpoint 7 | /// 8 | /// @return {String} 9 | /// 10 | /// @group Internal Functions 11 | /// 12 | @function flint-next-index($index) { 13 | @return if(flint-is-number($index) and $index != 0, flint-steal-key($index + 1), false); 14 | } 15 | -------------------------------------------------------------------------------- /tests/input/functions/lib/_last.scss: -------------------------------------------------------------------------------- 1 | // 2 | // Get last item in list 3 | // 4 | @include describe("[function] last") { 5 | 6 | $list: ("one", "two", "three"); 7 | 8 | @include it("should expect to return the last item in list") { 9 | @include should(expect( 10 | flint-last($list)), 11 | to(be("three")) 12 | ); 13 | @include should(expect( 14 | flint-last($list)), 15 | not-to(be("two")) 16 | ); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /tests/input/functions/lib/_replace.scss: -------------------------------------------------------------------------------- 1 | // 2 | // Replaces old by new in $list 3 | // 4 | @include describe("[function] replace") { 5 | 6 | $list: ("one", "two", "three"); 7 | 8 | @include it("should expect value to be replaced in list") { 9 | @include should(expect( 10 | flint-replace($list, "three", "two, again")), 11 | to(be(("one", "two", "two, again"))) 12 | ); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /tests/input/functions/lib/_steal-values.scss: -------------------------------------------------------------------------------- 1 | // 2 | // Steal breakpoint value by index 3 | // 4 | @include describe("[function] steal-values") { 5 | 6 | @include it("should expect steal value from breakpoint key based on its index") { 7 | @include should(expect( 8 | flint-steal-values(1, "breakpoint")), 9 | to(be(80em)) 10 | ); 11 | @include should(expect( 12 | flint-steal-values(1, "columns")), 13 | to(be(16)) 14 | ); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /stylesheets/flint/functions/lib/_remove.scss: -------------------------------------------------------------------------------- 1 | /// 2 | /// Remove value from list 3 | /// 4 | /// @access private 5 | /// 6 | /// @link http://sassylists.com/documentation/#remove 7 | /// 8 | /// @param {List} $list 9 | /// @param {*} $value 10 | /// @param {Bool} $recursive 11 | /// 12 | /// @return {List} 13 | /// 14 | /// @group Internal Functions 15 | /// 16 | @function flint-remove($list, $value) { 17 | @return flint-replace($list, $value, null); 18 | } 19 | -------------------------------------------------------------------------------- /stylesheets/flint/mixins/lib/_box-sizing.scss: -------------------------------------------------------------------------------- 1 | /// 2 | /// Box sizing 3 | /// 4 | /// @access private 5 | /// 6 | /// @param {String} $type ["border-box"] - border-box type 7 | /// 8 | /// @requires {Mixin} box-sizing - local mixin if available 9 | /// 10 | /// @group Internal Mixins 11 | /// 12 | @mixin flint-box-sizing($type: "border-box") { 13 | @if mixin-exists("box-sizing") { 14 | @include box-sizing($type); 15 | } @else { 16 | box-sizing: #{$type}; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /stylesheets/flint/functions/lib/_steal-values.scss: -------------------------------------------------------------------------------- 1 | /// 2 | /// Steal breakpoint value by index 3 | /// 4 | /// @access private 5 | /// 6 | /// @param {Number} $index - index of key 7 | /// @param {String} $value - value to get from breakpoint 8 | /// 9 | /// @return {String} 10 | /// 11 | /// @group Internal Functions 12 | /// 13 | @function flint-steal-values($index, $value) { 14 | @return if(flint-is-number($index), flint-get-value("breakpoints", flint-steal-key($index), $value), false); 15 | } 16 | -------------------------------------------------------------------------------- /tests/input/functions/lib/_steal-key.scss: -------------------------------------------------------------------------------- 1 | // 2 | // Steal breakpoint key by index 3 | // 4 | @include describe("[function] steal-key") { 5 | 6 | @include it("should expect breakpoint alias of passed index from configuration map") { 7 | @include should(expect( 8 | flint-steal-key(1)), 9 | to(be("desktop")) 10 | ); 11 | } 12 | 13 | @include it("should expect invalid type to return false") { 14 | @include should(expect( 15 | flint-steal-key("string")), 16 | to(be(false)) 17 | ); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /stylesheets/flint/functions/lib/_get-index.scss: -------------------------------------------------------------------------------- 1 | /// 2 | /// Gets the index of the passed key 3 | /// 4 | /// @access private 5 | /// 6 | /// @param {String} $key - breakpoint key 7 | /// 8 | /// @return {Number} 9 | /// 10 | /// @group Internal Functions 11 | /// 12 | @function flint-get-index($key) { 13 | 14 | @for $i from 1 through length(map-keys(flint-get-value("breakpoints"))) { 15 | @if flint-steal-key($i) == $key { 16 | @return $i; 17 | } 18 | } 19 | 20 | @return false; 21 | } 22 | -------------------------------------------------------------------------------- /tests/input/functions/lib/_support-syntax-bem.scss: -------------------------------------------------------------------------------- 1 | // 2 | // Parser to support BEM syntax 3 | // 4 | @include describe("[function] support-syntax-bem") { 5 | 6 | $selectors: ".block__element__element--modifier"; 7 | 8 | @include it("should expect selector string to be parsed to valid list of BEM selectors") { 9 | @include should(expect( 10 | flint-support-syntax-bem($selectors)), 11 | to(be((".block", ".block__element", ".block__element__element--modifier"))) 12 | ); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /stylesheets/flint/functions/lib/_get-instance-value.scss: -------------------------------------------------------------------------------- 1 | /// 2 | /// Get single value from key in instance map based on $selector::$key 3 | /// 4 | /// @access private 5 | /// 6 | /// @param {String} $key - breakpoint key to pass to instance method 7 | /// @param {ArgList} $values - list of keys to fetch value from 8 | /// 9 | /// @return {*} 10 | /// 11 | /// @group Internal Functions 12 | /// 13 | @function flint-get-instance-value($key, $values...) { 14 | @return flint-map-fetch($flint-instances, flint-has-family-instance($key), $values...); 15 | } 16 | -------------------------------------------------------------------------------- /stylesheets/flint/functions/lib/_purge.scss: -------------------------------------------------------------------------------- 1 | /// 2 | /// Removes all false and null values from $list 3 | /// 4 | /// @access private 5 | /// 6 | /// @link http://sassylists.com/documentation.html#purge 7 | /// 8 | /// @param {List} $list 9 | /// 10 | /// @return {List} 11 | /// 12 | /// @group Internal Functions 13 | /// 14 | @function flint-purge($list) { 15 | $result: (); 16 | 17 | @each $item in $list { 18 | @if flint-is-true($item) { 19 | $result: append($result, $item, list-separator($list)); 20 | } 21 | } 22 | 23 | @return $result; 24 | } 25 | -------------------------------------------------------------------------------- /tests/config.rb: -------------------------------------------------------------------------------- 1 | require "../lib/flint.rb" 2 | require "rubygems" 3 | require "bundler" 4 | 5 | Bundler.require(:default, :test) if defined?(Bundler) 6 | 7 | # require "sass-prof" 8 | # prof = SassProf::Config 9 | # prof.output_file = "sass-prof.log" 10 | # prof.quiet = false 11 | # prof.max_width = 40 12 | # prof.color = true 13 | # prof.t_max = 90000 14 | # prof.ignore = [:var] 15 | 16 | css_dir = "output" 17 | sass_dir = "input" 18 | output_style = :expanded 19 | line_comments = false 20 | sass_options = { 21 | :unix_newlines => true 22 | } 23 | -------------------------------------------------------------------------------- /tests/input/functions/lib/_next-index.scss: -------------------------------------------------------------------------------- 1 | // 2 | // Returns next indexed key based on passed index 3 | // 4 | @include describe("[function] next-index") { 5 | 6 | @include it("should expect alias of next indexed breakpoint") { 7 | @include should(expect( 8 | flint-next-index(1)), 9 | to(be("laptop")) 10 | ); 11 | @include should(expect( 12 | flint-next-index(2)), 13 | to(be("tablet")) 14 | ); 15 | @include should(expect( 16 | flint-next-index(3)), 17 | to(be("mobile")) 18 | ); 19 | @include should(expect( 20 | flint-next-index(4)), 21 | to(be(false)) 22 | ); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "flint", 3 | "version": "2.3.7", 4 | "main": "stylesheets/_flint.scss", 5 | "description": "Flint is a highly advanced Sass grid framework designed for rapid responsive development.", 6 | "authors": ["Ezekiel Gabrielse "], 7 | "homepage": "http://flint.gs", 8 | "keywords": [ 9 | "grid-system", "grid-framework", "framework", "ui", "grid", "layout", "flint", "breakpoint", "breakpoints", "semantic", "responsive-web-design" 10 | ], 11 | "license": "MIT", 12 | "ignore": [ 13 | "**/.*", 14 | "*.json", 15 | "*.gemspec", 16 | "*.gem" 17 | ], 18 | "devDependencies": { 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /lib/flint.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | 3 | lib = File.expand_path "../../lib/", __FILE__ 4 | $:.unshift lib unless $:.include? lib 5 | 6 | require "sass" 7 | 8 | require "flint/version" 9 | require "flint/functions" 10 | 11 | base_directory = File.expand_path(File.join(File.dirname(__FILE__), '..')) 12 | flint_stylesheets_path = File.join(base_directory, 'stylesheets') 13 | 14 | if (defined? Compass) 15 | Compass::Frameworks.register('flint', :path => base_directory) 16 | else 17 | ENV["SASS_PATH"] = [ENV["SASS_PATH"], flint_stylesheets_path].compact.join(File::PATH_SEPARATOR) 18 | end 19 | 20 | module Flint 21 | Sass::Script::Functions.send(:include, Flint) 22 | end 23 | -------------------------------------------------------------------------------- /tests/input/functions/lib/_support-syntax.scss: -------------------------------------------------------------------------------- 1 | // 2 | // Support syntax 3 | // 4 | @include describe("[function] support-syntax") { 5 | 6 | $selectors: ".block__element--modifier"; 7 | 8 | @include it("should expect truthy value to return from supported syntax") { 9 | @include should(expect( 10 | flint-support-syntax("BEM", $selectors)), 11 | to(be-truthy()) 12 | ); 13 | } 14 | 15 | @include it("should expect to return null if invalid syntax is passed") { 16 | @include should(expect( 17 | flint-support-syntax("OOCSS", $selectors)), 18 | to(be((false))) 19 | ); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /stylesheets/flint/functions/lib/_use-syntax.scss: -------------------------------------------------------------------------------- 1 | /// 2 | /// Use global syntax 3 | /// 4 | /// @access private 5 | /// 6 | /// @param {List} $selectors - string of selectors to parse 7 | /// 8 | /// @return {List} - parsed list of selectors 9 | /// 10 | /// @group Internal Functions 11 | /// 12 | @function flint-use-syntax($selectors) { 13 | @if $flint-support-syntax { 14 | @return flint-support-syntax($flint-support-syntax, $selectors); 15 | } @else { 16 | @if not $flint-development-mode { 17 | @error "Support syntax is set to #{$flint-support-syntax}. Aborting mission."; 18 | } @else { 19 | @return false; 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /stylesheets/flint/mixins/lib/_clearfix.scss: -------------------------------------------------------------------------------- 1 | /// 2 | /// Micro flint-clearfix 3 | /// 4 | /// @access private 5 | /// 6 | /// @link http://nicolasgallagher.com/micro-clearfix-hack/ 7 | /// 8 | /// @requires {Mixin} clearfix - local mixin if available 9 | /// 10 | /// @group Internal Mixins 11 | /// 12 | @mixin flint-clearfix { 13 | @if mixin-exists("clearfix") { 14 | @include clearfix; 15 | } @else { 16 | zoom: 1; 17 | 18 | &:before, &:after { 19 | content: "\0020"; 20 | display: block; 21 | height: 0; 22 | overflow: hidden; 23 | } 24 | 25 | &:after { 26 | clear: both; 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /stylesheets/flint/functions/lib/_replace.scss: -------------------------------------------------------------------------------- 1 | /// 2 | /// Replaces old by new in $list 3 | /// 4 | /// @access private 5 | /// 6 | /// @link http://sassylists.com/documentation.html#replace 7 | /// 8 | /// @param {List} $list 9 | /// @param {*} $old 10 | /// @param {*} $value 11 | /// 12 | /// @return {List} 13 | /// 14 | /// @group Internal Functions 15 | /// 16 | @function flint-replace($list, $old, $value) { 17 | $running: true; 18 | 19 | @while $running { 20 | $index: index($list, $old); 21 | 22 | @if not $index { 23 | $running: false; 24 | } @else { 25 | $list: set-nth($list, $index, $value); 26 | } 27 | } 28 | 29 | @return if(not flint-is-true($value), flint-purge($list), $list); 30 | } 31 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | desc "Run test suite" 2 | task :test, [:watch] do |t, args| 3 | if args[:watch] 4 | system "cd tests && bundle exec compass watch --time" 5 | else 6 | system "cd tests && bundle exec compass compile --time" 7 | end 8 | end 9 | 10 | desc "Clear cache" 11 | task :clean do 12 | system "cd tests && bundle exec compass clean" 13 | end 14 | 15 | desc "Output test status" 16 | task :status do 17 | output = File.read "tests/output/output.css" 18 | results = /Test\sResults\s{(.*?)}/m.match output 19 | failed = /Failed:\s(\d+)/m.match results[0] 20 | 21 | if failed[0].to_i > 0 22 | puts "Tests failed" 23 | exit 1 24 | else 25 | puts "Tests passed" 26 | exit 0 27 | end 28 | end 29 | 30 | task :default => [:clean, :test, :status] 31 | -------------------------------------------------------------------------------- /stylesheets/flint/functions/lib/_map-fetch.scss: -------------------------------------------------------------------------------- 1 | /// 2 | /// Fetch value from map 3 | /// 4 | /// @access private 5 | /// 6 | /// @param {Map} $map - map to fetch value from 7 | /// @param {ArgList} $keys - list of keys to traverse 8 | /// 9 | /// @return {*} 10 | /// 11 | /// @group Internal Functions 12 | /// 13 | @function flint-map-fetch($map, $keys...) { 14 | 15 | // Use Ruby function if available 16 | @if $flint-use-ruby-functions { 17 | @return flint_ruby_map_fetch($map, $keys...); 18 | } 19 | 20 | $result: $map; 21 | 22 | @each $key in $keys { 23 | @if $result { 24 | $result: flint-is-map($result) and map-has-key($result, $key) and map-get($result, $key) or false; 25 | } @else { 26 | @return false; 27 | } 28 | } 29 | 30 | @return $result; 31 | } 32 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "flint-gs", 3 | "version": "2.3.7", 4 | "description": "Flint is a highly advanced Sass grid framework designed for rapid responsive development.", 5 | "authors": ["Ezekiel Gabrielse "], 6 | "main": "stylesheets/_flint.scss", 7 | "license": "MIT", 8 | "repository": { 9 | "type": "git", 10 | "url": "git://github.com/ezekg/flint.git" 11 | }, 12 | "keywords": [ 13 | "grid-system", "grid-framework", "framework", "ui", "grid", "layout", "flint", "breakpoint", "breakpoints", "semantic", "responsive-web-design" 14 | ], 15 | "bugs": { 16 | "url": "https://github.com/ezekg/flint/issues" 17 | }, 18 | "ignore": [ 19 | "**/.*", 20 | "*.json", 21 | "*.gemspec", 22 | "*.gem" 23 | ], 24 | "devDependencies": { 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tests/input/functions/lib/_get-value.scss: -------------------------------------------------------------------------------- 1 | // 2 | // Get single value from configuration map 3 | // 4 | @include describe("[function] get-value") { 5 | 6 | @include it("should expect value to be fetched from configuration map") { 7 | @include should(expect( 8 | flint-get-value("breakpoints", "desktop", "breakpoint")), 9 | to(be(80em)) 10 | ); 11 | @include should(expect( 12 | flint-get-value("breakpoints", "laptop", "columns")), 13 | to(be(12)) 14 | ); 15 | @include should(expect( 16 | flint-get-value("settings", "grid")), 17 | to(be("fluid")) 18 | ); 19 | @include should(expect( 20 | flint-get-value("settings", "gutter")), 21 | to(be(0.625em)) 22 | ); 23 | @include should(expect( 24 | flint-get-value("settings", "float-direction")), 25 | to(be("left")) 26 | ); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /tests/input/functions/lib/_list-to-str.scss: -------------------------------------------------------------------------------- 1 | // 2 | // Joins all elements of list with passed glue 3 | // 4 | @include describe("[function] list-to-str") { 5 | 6 | $list: ("one", "two", "three"); 7 | 8 | @include it("should expect the list to be converted into a string without spaces") { 9 | @include should(expect( 10 | flint-list-to-str($list)), 11 | to(be("onetwothree")) 12 | ); 13 | } 14 | 15 | @include it("should expect the list to be converted into a string with spaces") { 16 | @include should(expect( 17 | flint-list-to-str($list, " ")), 18 | to(be("one two three")) 19 | ); 20 | } 21 | 22 | @include it("should expect the list to be converted into a string with commas") { 23 | @include should(expect( 24 | flint-list-to-str($list, ", ")), 25 | to(be("one, two, three")) 26 | ); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /stylesheets/flint/mixins/lib/_new-instance.scss: -------------------------------------------------------------------------------- 1 | /// 2 | /// Creates a new instance, adds to global instance map 3 | /// 4 | /// @access private 5 | /// 6 | /// @param {String} $calc-key 7 | /// @param {Number} $calc-span 8 | /// @param {Number} $calc-context 9 | /// @param {Number} $calc-gutter 10 | /// @param {Number} $output-width 11 | /// @param {Number} $output-margin-right 12 | /// @param {Number} $output-margin-left 13 | /// 14 | /// @group Internal Mixins 15 | /// 16 | @mixin flint-new-instance($calc-key, $calc-span, $calc-context, $calc-gutter, $output-width, $output-margin-right, $output-margin-left) { 17 | $flint-instances: 18 | flint-instance( 19 | $calc-key, 20 | $calc-span, 21 | $calc-context, 22 | $calc-gutter, 23 | $output-width, 24 | $output-margin-right, 25 | $output-margin-left 26 | ) 27 | !global; 28 | } 29 | -------------------------------------------------------------------------------- /tests/input/functions/lib/_map-fetch.scss: -------------------------------------------------------------------------------- 1 | // 2 | // Fetch value from map 3 | // 4 | @include describe("[function] map-fetch") { 5 | 6 | $map: ( 7 | "key": "value", 8 | "deep-map": ( 9 | "deep-key": "deep-value" 10 | ) 11 | ); 12 | 13 | @include it("should expect values to be fetched from map") { 14 | @include should(expect( 15 | flint-map-fetch($map, "key")), 16 | to(be("value")) 17 | ); 18 | @include should(expect( 19 | flint-map-fetch($map, "deep-map", "deep-key")), 20 | to(be("deep-value")) 21 | ); 22 | } 23 | 24 | @include it("should expect non-existent values to return false") { 25 | @include should(expect( 26 | flint-map-fetch($map, "unknown")), 27 | to(be(false)) 28 | ); 29 | @include should(expect( 30 | flint-map-fetch($map, "deep-map", "unknown")), 31 | to(be(false)) 32 | ); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /tests/input/functions/lib/_fluid-width.scss: -------------------------------------------------------------------------------- 1 | // 2 | // Convert fixed to fluid width 3 | // 4 | @include describe("[function] fluid-width") { 5 | 6 | @include it("should expect result to be equal to manual calculation") { 7 | @include should(expect( 8 | flint-fluid-width(80em / 16, 80em)), 9 | to(be(100% / 16)) 10 | ); 11 | @include should(expect( 12 | flint-fluid-width(80em / 8, 80em)), 13 | to(be(100% / 8)) 14 | ); 15 | @include should(expect( 16 | flint-fluid-width(80em / 4, 80em)), 17 | to(be(100% / 4)) 18 | ); 19 | @include should(expect( 20 | flint-fluid-width(80em / 3, 80em)), 21 | to(be(100% / 3)) 22 | ); 23 | @include should(expect( 24 | flint-fluid-width(80em / 2, 80em)), 25 | to(be(100% / 2)) 26 | ); 27 | @include should(expect( 28 | flint-fluid-width(80em / 1, 80em)), 29 | to(be(100% / 1)) 30 | ); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /stylesheets/flint/functions/lib/_steal-key.scss: -------------------------------------------------------------------------------- 1 | /// 2 | /// Steal breakpoint key by index 3 | /// 4 | /// @access private 5 | /// 6 | /// @param {Number} $index - index of key 7 | /// 8 | /// @return {String} 9 | /// 10 | /// @group Internal Functions 11 | /// 12 | @function flint-steal-key($index) { 13 | $length: length(map-keys(flint-get-value("breakpoints"))); 14 | 15 | @if not flint-is-number($index) { 16 | @if not $flint-development-mode { 17 | @error "Passed $index (#{$index}) is not a number. Function takes index number of breakpoint key."; 18 | } @else { 19 | @return false; 20 | } 21 | } 22 | 23 | @if $index > $length { 24 | @if not $flint-development-mode { 25 | @error "Passed $index (#{$index}) is greater than the length of the config map."; 26 | } @else { 27 | @return false; 28 | } 29 | } 30 | 31 | @return if($index != 0, nth(map-keys(flint-get-value("breakpoints")), $index), false); 32 | } 33 | -------------------------------------------------------------------------------- /tests/input/functions/lib/_get-index.scss: -------------------------------------------------------------------------------- 1 | // 2 | // Gets the index of the passed key 3 | // 4 | @include describe("[function] get-index") { 5 | 6 | @include it("should expect index to match index of key in configuration map") { 7 | @include should(expect( 8 | flint-get-index("desktop")), 9 | to(be(1)) 10 | ); 11 | @include should(expect( 12 | flint-get-index("laptop")), 13 | to(be(2)) 14 | ); 15 | @include should(expect( 16 | flint-get-index("tablet")), 17 | to(be(3)) 18 | ); 19 | @include should(expect( 20 | flint-get-index("mobile")), 21 | to(be(4)) 22 | ); 23 | } 24 | 25 | @include it("should expect index to not be found") { 26 | @include should(expect( 27 | flint-get-index("unknown")), 28 | to(be(false)) 29 | ); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /stylesheets/flint/functions/lib/_list-to-str.scss: -------------------------------------------------------------------------------- 1 | /// 2 | /// Joins all elements of list with passed glue 3 | /// 4 | /// @access private 5 | /// 6 | /// @param {List} $list 7 | /// @param {String} $glue 8 | /// @param {Bool} $is-nested 9 | /// 10 | /// @return {String} 11 | /// 12 | /// @group Internal Functions 13 | /// 14 | @function flint-list-to-str($list, $glue: "", $is-nested: false) { 15 | @if flint-is-string($list) { 16 | $list: ($list,); 17 | } 18 | 19 | // Use Ruby function if available 20 | @if $flint-use-ruby-functions { 21 | @return flint_ruby_list_to_str($list, $glue); 22 | } 23 | 24 | $result: ""; 25 | $length: length($list); 26 | 27 | @for $i from 1 through $length { 28 | $item: nth($list, $i); 29 | 30 | @if flint-is-list($item) { 31 | $result: $result + flint-list-to-str($item, $glue, true); 32 | } @else { 33 | $result: if($i != length($list) or $is-nested, $result + $item + $glue, $result + $item); 34 | } 35 | } 36 | 37 | @return quote($result); 38 | } 39 | -------------------------------------------------------------------------------- /tests/input/functions/lib/_has-family-instance.scss: -------------------------------------------------------------------------------- 1 | // 2 | // Checks if instance exists in selector familiy tree, falls back from current selector 3 | // 4 | @include describe("[function] has-family-instance") { 5 | 6 | @include it("should expect to return false unless inside of a parent instance") { 7 | @include should(expect( 8 | flint-has-family-instance("desktop")), 9 | to(be(false)) 10 | ); 11 | } 12 | 13 | .parent-instance { 14 | @include _("laptop", 4); 15 | 16 | .child-instance { 17 | @include _("laptop", 2) { 18 | 19 | @include it("should expect to return true unless instance doesnt exist") { 20 | @include should(expect( 21 | flint-has-family-instance("desktop")), 22 | to(be(false)) 23 | ); 24 | @include should(expect( 25 | flint-has-family-instance("laptop")), 26 | to(be(".parent-instance::laptop")) 27 | ); 28 | } 29 | } 30 | } 31 | } 32 | 33 | $flint-instances: () !global; 34 | $flint-instance-count: 0 !global; 35 | } 36 | -------------------------------------------------------------------------------- /tests/input/functions/_functions.scss: -------------------------------------------------------------------------------- 1 | /// 2 | /// Helpers 3 | /// 4 | @import "helpers/helpers"; 5 | 6 | /// 7 | /// Functions 8 | /// 9 | 10 | // Getters 11 | @import "lib/map-fetch"; 12 | @import "lib/get-value"; 13 | @import "lib/get-index"; 14 | @import "lib/steal-key"; 15 | @import "lib/steal-values"; 16 | 17 | // Calculations 18 | @import "lib/fluid-width"; 19 | @import "lib/calc-width"; 20 | @import "lib/calc-breakpoint"; 21 | 22 | // Instance functions 23 | @import "lib/instance"; 24 | @import "lib/has-family-instance"; 25 | @import "lib/get-instance-value"; 26 | 27 | // List functions 28 | @import "lib/list-to-str"; 29 | @import "lib/types-in-list"; 30 | @import "lib/next-index"; 31 | @import "lib/purge"; 32 | @import "lib/replace"; 33 | @import "lib/remove"; 34 | @import "lib/last"; 35 | 36 | // String functions 37 | @import "lib/str-replace"; 38 | @import "lib/str-to-list"; 39 | 40 | /// 41 | /// Support syntax 42 | /// 43 | @import "lib/use-syntax"; 44 | @import "lib/support-syntax"; 45 | 46 | // Syntaxes 47 | @import "lib/support-syntax-bem" 48 | -------------------------------------------------------------------------------- /flint.gemspec: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | 3 | lib = File.expand_path "../lib/", __FILE__ 4 | $:.unshift lib unless $:.include? lib 5 | 6 | require "flint" 7 | 8 | Gem::Specification.new do |spec| 9 | 10 | # Info 11 | spec.version = Flint::VERSION 12 | 13 | # Details 14 | spec.name = "flint-gs" 15 | spec.rubyforge_project = "flint" 16 | spec.licenses = "MIT" 17 | spec.authors = ["Ezekiel Gabrielse"] 18 | spec.email = ["ezekg@yahoo.com"] 19 | spec.homepage = "http://flint.gs" 20 | 21 | # Description 22 | spec.summary = %q{A highly advanced Sass grid framework designed for rapid responsive development.} 23 | spec.description = %q{Flint is a highly advanced Sass grid framework designed for rapid responsive development.} 24 | 25 | # Library 26 | spec.files += Dir.glob("lib/**/*.*") 27 | 28 | # Sass 29 | spec.files += Dir.glob("stylesheets/**/*.*") 30 | 31 | # Other 32 | spec.files += ["LICENSE", "README.md"] 33 | 34 | # Test 35 | spec.test_files += Dir.glob("tests/**/*.*") 36 | 37 | # Dependencies 38 | spec.add_dependency "sass", "~> 3.4" 39 | end 40 | -------------------------------------------------------------------------------- /stylesheets/flint/functions/_functions.scss: -------------------------------------------------------------------------------- 1 | // 2 | // Helpers 3 | // 4 | @import "helpers/helpers"; 5 | 6 | // 7 | // Functions 8 | // 9 | @import "lib/html-encode"; 10 | 11 | // Getters 12 | @import "lib/map-fetch"; 13 | @import "lib/get-value"; 14 | @import "lib/get-index"; 15 | @import "lib/steal-key"; 16 | @import "lib/steal-values"; 17 | 18 | // Calculations 19 | @import "lib/fluid-width"; 20 | @import "lib/calc-width"; 21 | @import "lib/calc-breakpoint"; 22 | 23 | // Instance functions 24 | @import "lib/instance"; 25 | @import "lib/has-family-instance"; 26 | @import "lib/get-instance-value"; 27 | 28 | // List functions 29 | @import "lib/list-to-str"; 30 | @import "lib/types-in-list"; 31 | @import "lib/next-index"; 32 | @import "lib/purge"; 33 | @import "lib/replace"; 34 | @import "lib/remove"; 35 | @import "lib/last"; 36 | 37 | // String functions 38 | @import "lib/str-replace"; 39 | @import "lib/str-to-list"; 40 | 41 | // 42 | // Support syntax 43 | // 44 | @import "lib/use-syntax"; 45 | @import "lib/support-syntax"; 46 | 47 | // Syntaxes 48 | @import "lib/support-syntax-bem"; 49 | -------------------------------------------------------------------------------- /tests/input/functions/lib/_str-to-list.scss: -------------------------------------------------------------------------------- 1 | // 2 | // Turns string into a flat list 3 | // 4 | @include describe("[function] str-to-list") { 5 | 6 | $string: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."; 7 | 8 | @include it("should expect string to be converted into a list") { 9 | @include should(expect( 10 | flint-str-to-list($string, " ", "")), 11 | to(be(("Lorem", "ipsum", "dolor", "sit", "amet,", "consectetur", "adipiscing", "elit,", "sed", "do", "eiusmod", "tempor", "incididunt", "ut", "labore", "et", "dolore", "magna", "aliqua."))) 12 | ); 13 | } 14 | 15 | @include it("should expect string to be converted into a list") { 16 | @include should(expect( 17 | flint-str-to-list($string, " ", "d")), 18 | to(be(("Lorem", "ipsum"))) 19 | ); 20 | } 21 | 22 | @include it("should expect string up to comma to be converted into a list") { 23 | @include should(expect( 24 | flint-str-to-list($string)), 25 | to(be(("Lorem", "ipsum", "dolor", "sit", "amet"))) 26 | ); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Ezekiel Gabrielse 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /stylesheets/flint/mixins/lib/_print-instance.scss: -------------------------------------------------------------------------------- 1 | //// 2 | /// @group Internal Mixins 3 | //// 4 | 5 | /// 6 | /// Prints debug properties 7 | /// 8 | /// @access private 9 | /// 10 | /// @param {String} $calc-key - breakpoint key to search for instance 11 | /// 12 | @mixin flint-debug-instance($calc-key) { 13 | @if flint-get-value("settings", "debug-mode") { 14 | // Lets clean up the selector a bit... 15 | $selector: nth(&, 1); 16 | // Append key to selector 17 | $print-selector: "#{$selector}" + "::" + "#{$calc-key}"; 18 | @include flint-print-instance(map-get($flint-instances, unquote($print-selector))); 19 | } 20 | } 21 | 22 | /// 23 | /// Prints all contents of instance map 24 | /// 25 | /// @access private 26 | /// 27 | /// @param {Map} $instance - instance map 28 | /// 29 | @mixin flint-print-instance($instance) { 30 | 31 | // Loop through each property in passed instance 32 | @each $property, $value in $instance { 33 | 34 | // Check if value is output map 35 | @if flint-is-map($value) { 36 | @each $prop, $val in $value { 37 | -flint-output-#{$prop}: #{$val}; 38 | } 39 | // Else, print values as flagged comments 40 | } @else { 41 | -flint-#{$property}: #{$value}; 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /stylesheets/flint/functions/lib/_support-syntax.scss: -------------------------------------------------------------------------------- 1 | /// 2 | /// Support syntax 3 | /// 4 | /// @access private 5 | /// 6 | /// @param {String} $syntax - alias of syntax to support 7 | /// @param {List} $selectors - string of selectors to parse 8 | /// 9 | /// @return {List} - list of parsed selectors according to syntax 10 | /// 11 | /// @group Internal Functions 12 | /// 13 | @function flint-support-syntax($syntax, $selectors) { 14 | $syntax: to-lower-case($syntax); 15 | 16 | // Make sure syntax is supported 17 | @if function-exists("flint-support-syntax-#{$syntax}") { 18 | 19 | // Support syntax 20 | // 21 | // WARNING: Be sure you have created a custom function to support an unknown syntax 22 | @return call("flint-support-syntax-#{$syntax}", $selectors); 23 | } 24 | 25 | @if not $flint-development-mode { 26 | // Throw error if the syntax does not exist and a function to call cannot be found 27 | @error "You did not pass a valid syntax to `flint-support-syntax`: #{$syntax}. Either specify a custom `flint-support-syntax-` function to call, or use one of the offically supported syntaxes. For more info, please visit the docs."; 28 | } @else { 29 | @return false; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /stylesheets/flint/functions/lib/_str-replace.scss: -------------------------------------------------------------------------------- 1 | /// 2 | /// Replace substring 3 | /// 4 | /// @access private 5 | /// 6 | /// @param {String} $string - string that contains substring 7 | /// @param {String} $substring - substring to replace 8 | /// @param {String} $new-substring [" "] - new string to replace sub with 9 | /// 10 | /// @return {String} 11 | /// 12 | /// @group Internal Functions 13 | /// 14 | @function flint-str-replace($string, $substring, $new-substring: " ") { 15 | 16 | // Use Ruby function if available 17 | @if $flint-use-ruby-functions { 18 | @return flint_ruby_str_replace($string, $substring, $new-substring); 19 | } 20 | 21 | // Loop through length of string 22 | @for $i from 1 through str-length($string) { 23 | // Get index and length of substring 24 | $sub-index: str-index($string, $substring); 25 | $sub-length: str-length($substring); 26 | 27 | // If count is index of substring 28 | @if $i == $sub-index { 29 | // Slice string to exclude substring 30 | $string-before: str-slice($string, 1, $i - 1); 31 | $string-after: str-slice($string, $i + $sub-length, str-length($string)); 32 | // Create new string 33 | $string: $string-before + $new-substring + $string-after; 34 | } 35 | 36 | } 37 | 38 | @return $string; 39 | } 40 | -------------------------------------------------------------------------------- /stylesheets/flint/mixins/lib/_container.scss: -------------------------------------------------------------------------------- 1 | /// 2 | /// Container 3 | /// 4 | /// @access private 5 | /// 6 | /// @param {String} $key [null] - alias of individual breakpoint 7 | /// @param {Number} $i [null] - index number if called from loop 8 | /// 9 | /// @group Internal Mixins 10 | /// 11 | @mixin flint-container($key: null, $i: null) { 12 | 13 | // Check if inside of loop, and if so only output for default 14 | @if $i == null or flint-is-default(flint-steal-key($i)) { 15 | float: none; 16 | 17 | @if $key { 18 | width: flint-calc-width($key, "container"); 19 | } 20 | 21 | @if flint-get-value("settings", "max-width") { 22 | @if flint-is-number(flint-get-value("settings", "max-width")) { 23 | max-width: flint-get-value("settings", "max-width"); 24 | } @else { 25 | max-width: max(flint-get-all-breakpoints()...); 26 | } 27 | } 28 | 29 | @if flint-get-value("settings", "center-container") { 30 | margin-right: auto; 31 | margin-left: auto; 32 | } @else { 33 | margin-right: 0; 34 | margin-left: 0; 35 | } 36 | 37 | // Inside of loop, so only output width 38 | } @else { 39 | @if $key { 40 | width: flint-calc-width($key, "container"); 41 | } 42 | } 43 | 44 | @content; 45 | } 46 | -------------------------------------------------------------------------------- /stylesheets/flint/functions/lib/_support-syntax-bem.scss: -------------------------------------------------------------------------------- 1 | /// 2 | /// Parser to support BEM syntax 3 | /// 4 | /// @access private 5 | /// 6 | /// @param {List} $selectors - string of selectors to parse 7 | /// 8 | /// @return {List} - parsed list of selectors according to syntax 9 | /// 10 | /// @group Internal Functions 11 | /// 12 | @function flint-support-syntax-bem($selectors) { 13 | $selectors: flint-list-to-str($selectors, " "); 14 | // Clean up selector, remove double underscores for spaces 15 | // add pseudo character to differentiate selectors 16 | $selectors: flint-str-replace($selectors, "__", "/"); 17 | // Parse string back to list without pseudo character 18 | $selectors: flint-str-to-list($selectors, "/"); 19 | // Define top-most parent of selector 20 | $parent: nth($selectors, 1); 21 | // Create new list of parsed selectors 22 | $selector-list: ($parent,); 23 | 24 | // Loop over each selector and build list of selectors 25 | @each $selector in $selectors { 26 | // Make sure current selector is not the parent 27 | @if $selector != $parent { 28 | // Save to selector list 29 | $selector-list: append($selector-list, "#{$parent}__#{$selector}", "comma"); 30 | // Define new parent 31 | $parent: "#{$parent}__#{$selector}"; 32 | } 33 | } 34 | 35 | // Return the list of parsed selectors 36 | @return $selector-list; 37 | } 38 | -------------------------------------------------------------------------------- /stylesheets/flint/functions/lib/_calc-breakpoint.scss: -------------------------------------------------------------------------------- 1 | /// 2 | /// Calculate breakpoint query 3 | /// 4 | /// @access private 5 | /// 6 | /// @param {String} $type - type of query to get 7 | /// @param {String} $key - key of breakpoint 8 | /// @param {Number} $i - index of current breakpoint 9 | /// 10 | /// @return {Number} - breakpoint value 11 | /// 12 | /// @group Internal Functions 13 | /// 14 | @function flint-calc-breakpoint($type, $key, $i) { 15 | 16 | @if $type == "alias" { 17 | 18 | @if flint-get-value("settings", "grid") == "fixed" { 19 | @if flint-is-lowest-breakpoint($key) { 20 | @return 0; 21 | } @else { 22 | @return flint-get-value("breakpoints", $key, "breakpoint"); 23 | } 24 | } @else if flint-get-value("settings", "grid") == "fluid" { 25 | @return flint-get-value("breakpoints", $key, "breakpoint"); 26 | } 27 | 28 | } @else if $type == "next" { 29 | 30 | @if flint-is-lowest-breakpoint($key) { 31 | @return 0; 32 | } @else { 33 | @return flint-get-value("breakpoints", flint-steal-key(($i + 1)), "breakpoint"); 34 | } 35 | 36 | } @else if $type == "prev" { 37 | 38 | @if flint-is-highest-breakpoint($key) { 39 | @return flint-get-value("breakpoints", $key, "breakpoint"); 40 | } @else { 41 | @return flint-get-value("breakpoints", flint-steal-key(($i - 1)), "breakpoint"); 42 | } 43 | 44 | } 45 | 46 | @return false; 47 | } 48 | -------------------------------------------------------------------------------- /stylesheets/flint/functions/lib/_html-encode.scss: -------------------------------------------------------------------------------- 1 | /// 2 | /// HTML encode string 3 | /// 4 | /// @group Internal Functions 5 | /// 6 | @function flint-html-encode($string) { 7 | $encode-map: ("%": "%25", " ": "%20", "!": "%21", '"': "%22", "#": "%23", "$": "%24", "&": "%26", "'": "%27", "(": "%28", ")": "%29", "*": "%2A", "+": "%2B", ",": "%2C", "-": "%2D", ".": "%2E", "/": "%2F", ":": "%3A", ";": "%3B", "<": "%3C", "=": "%3D", ">": "%3E", "?": "%3F", "@": "%40", "[": "%5B", "\\": "%5C", "]": "%5D", "^": "%5E", "_": "%5F", "`": "%60", "{": "%7B", "|": "%7C", "}": "%7D", "~": "%7E", "¢": "%A2", "£": "%A3", "¥": "%A5", "§": "%A7", "«": "%AB", "¬": "%AC", "¯": "%AD", "º": "%B0", "±": "%B1", "ª": "%B2", "µ": "%B5", "»": "%BB", "¼": "%BC", "½": "%BD", "¿": "%BF", "À": "%C0", "Á": "%C1", "Â": "%C2", "Ã": "%C3", "Ä": "%C4", "Å": "%C5", "Æ": "%C6", "Ç": "%C7", "È": "%C8", "É": "%C9", "Ê": "%CA", "Ë": "%CB", "Ì": "%CC", "Í": "%CD", "Î": "%CE", "Ï": "%CF", "Ð": "%D0", "Ñ": "%D1", "Ò": "%D2", "Ó": "%D3", "Ô": "%D4", "Õ": "%D5", "Ö": "%D6", "Ø": "%D8", "Ù": "%D9", "Ú": "%DA", "Û": "%DB", "Ü": "%DC", "Ý": "%DD", "Þ": "%DE", "ß": "%DF", "à": "%E0", "á": "%E1", "â": "%E2", "ã": "%E3", "ä": "%E4", "å": "%E5", "æ": "%E6", "ç": "%E7", "è": "%E8", "é": "%E9", "ê": "%EA", "ë": "%EB", "ì": "%EC", "í": "%ED", "î": "%EE", "ï": "%EF", "ð": "%F0", "ñ": "%F1", "ò": "%F2", "ó": "%F3", "ô": "%F4", "õ": "%F5", "ö": "%F6", "÷": "%F7", "ø": "%F8", "ù": "%F9", "ú": "%FA", "û": "%FB", "ü": "%FC", "ý": "%FD", "þ": "%FE", "ÿ": "%FF"); 8 | 9 | @each $search, $replace in $encode-map { 10 | $string: flint-str-replace($string, $search, $replace); 11 | } 12 | 13 | @return $string; 14 | } 15 | -------------------------------------------------------------------------------- /tests/input/functions/lib/_types-in-list.scss: -------------------------------------------------------------------------------- 1 | // 2 | // Checks type of each item in list 3 | // 4 | @include describe("[function] types-in-list") { 5 | 6 | $list-of-numbers: 1, 2, 3, 4, 5; 7 | $list-of-strings: "one", "two", "three"; 8 | $mixed-list: 1, "two", 3, "four"; 9 | $string: "string"; 10 | 11 | @include it("should expect to return false if list is not passed") { 12 | @include should(expect( 13 | flint-types-in-list($string)), 14 | to(be(false)) 15 | ); 16 | } 17 | 18 | @include it("should expect types to be asserted in list") { 19 | @include should(expect( 20 | flint-types-in-list($list-of-numbers)), 21 | to(be(true)) 22 | ); 23 | @include should(expect( 24 | flint-types-in-list($list-of-numbers, "number")), 25 | to(be((true))) 26 | ); 27 | @include should(expect( 28 | flint-types-in-list($list-of-strings, "string", 3)), 29 | to(be((true))) 30 | ); 31 | @include should(expect( 32 | flint-types-in-list($mixed-list, "number" "string" "number" "string", 4)), 33 | to(be((true))) 34 | ); 35 | } 36 | 37 | @include it("should expect auto asserted types to return false") { 38 | @include should(expect( 39 | flint-types-in-list($mixed-list)), 40 | to(be((false))) 41 | ); 42 | } 43 | 44 | @include it("should expect asserted length to return false") { 45 | @include should(expect( 46 | flint-types-in-list($list-of-strings, "string", 1)), 47 | to(be((false))) 48 | ); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /stylesheets/flint/functions/lib/_instance.scss: -------------------------------------------------------------------------------- 1 | /// 2 | /// Keeps count of all instances with arguments, stores in global var 3 | /// 4 | /// @access private 5 | /// 6 | /// @param {String} $key - computed breakpoint of instance 7 | /// @param {Number} $span - computed span of instance 8 | /// @param {Number} $context - computed context of instance 9 | /// @param {Number} $gutter - computed gutter of instance 10 | /// @param {Number} $output-width - computed width of instance 11 | /// @param {Number} $output-margin-right - computed right margin of instance 12 | /// @param {Number} $output-margin-left - computed left margin of instance 13 | /// 14 | /// @return {Map} merged instance map 15 | /// 16 | /// @group Internal Functions 17 | /// 18 | @function flint-instance($key, $span, $context, $gutter, $output-width, $output-margin-right, $output-margin-left) { 19 | 20 | // Increase the instance count 21 | $flint-instance-count: $flint-instance-count + 1 !global; 22 | 23 | // Lets clean up the selector a bit... 24 | $selector: nth(&, 1); 25 | 26 | // Get the selector family instance 27 | $family-instance: flint-has-family-instance($key); 28 | 29 | $flint-instance: ( 30 | "#{$selector}::#{$key}": ( 31 | "instance-count": $flint-instance-count, 32 | "parent-selector": if($family-instance != false, $family-instance, none), 33 | "key": $key, 34 | "breakpoint": flint-get-value("breakpoints", $key, "breakpoint"), 35 | "columns": flint-get-value("breakpoints", $key, "columns"), 36 | "span": $span, 37 | "context": if($context == "auto", flint-get-instance-value($key, "span"), $context), 38 | "gutter": $gutter, 39 | "internal": ( 40 | "width": $output-width, 41 | "margin-right": $output-margin-right, 42 | "margin-left": $output-margin-left 43 | ) 44 | ) 45 | ); 46 | 47 | @return map-merge($flint-instance, $flint-instances); 48 | } 49 | -------------------------------------------------------------------------------- /stylesheets/flint/functions/lib/_types-in-list.scss: -------------------------------------------------------------------------------- 1 | /// 2 | /// Checks type of each item in list 3 | /// 4 | /// @access private 5 | /// 6 | /// @param {List} $list - list of items 7 | /// @param {String|List} $assert-types [null] - single or list of types to assert 8 | /// @param {Number} $assert-length [null] - assert length of list 9 | /// 10 | /// @return {Bool} 11 | /// 12 | /// @group Internal Functions 13 | /// 14 | @function flint-types-in-list($list, $assert-types: null, $assert-length: null) { 15 | @if not flint-is-list($list) { 16 | @return false; 17 | } 18 | 19 | @if not $assert-types { 20 | $type: type-of(nth($list, 1)); 21 | 22 | @each $item in $list { 23 | @if type-of($item) != $type { 24 | @return false; 25 | } 26 | } 27 | 28 | @return true; 29 | } 30 | 31 | @if not $assert-length { 32 | $type: $assert-types; 33 | 34 | @each $item in $list { 35 | @if type-of($item) != $type { 36 | @return false; 37 | } 38 | } 39 | 40 | @return true; 41 | } 42 | 43 | $length: length($list); 44 | 45 | @if $length != $assert-length { 46 | @return false; 47 | } 48 | 49 | @if flint-is-list($assert-types) { 50 | @if length($assert-types) != $length { 51 | @return false; 52 | } 53 | 54 | @for $i from 1 through $assert-length { 55 | $item: nth($list, $i); 56 | $type: nth($assert-types, $i); 57 | 58 | @if type-of($item) != $type { 59 | @return false; 60 | } 61 | } 62 | 63 | } @else { 64 | $type: nth($assert-types, 1); 65 | 66 | @for $i from 1 through $assert-length { 67 | $item: nth($list, $i); 68 | 69 | @if type-of($item) != $type { 70 | @return false; 71 | } 72 | } 73 | } 74 | 75 | @return true; 76 | } 77 | -------------------------------------------------------------------------------- /tests/input/functions/lib/_get-instance-value.scss: -------------------------------------------------------------------------------- 1 | // 2 | // Get single value from key in instance map based on $selector::$key 3 | // 4 | @include describe("[function] get-instance-value") { 5 | 6 | // $flint-instances: ( 7 | // ".instance::desktop": ( 8 | // "instance-count": 1, 9 | // "parent-selector": none, 10 | // "key": "desktop", 11 | // "breakpoint": 80em, 12 | // "columns": 16, 13 | // "span": 4, 14 | // "context": null, 15 | // "gutter": null, 16 | // "internal": ( 17 | // "width": 18.75em, 18 | // "margin-right": 0.625em, 19 | // "margin-left": 0.625em 20 | // ) 21 | // ) 22 | // ); 23 | 24 | @include it("should expect to return false unless inside of a parent instance") { 25 | @include should(expect( 26 | flint-get-instance-value("desktop", "breakpoint")), 27 | to(be(false)) 28 | ); 29 | } 30 | 31 | .parent-instance { 32 | @include _("desktop", 4); 33 | 34 | .child-instance { 35 | @include _("desktop", 2) { 36 | 37 | @include it("should expect correct value from parent selector to be fetched from instance map") { 38 | @include should(expect( 39 | flint-get-instance-value("desktop", "breakpoint")), 40 | to(be(80em)) 41 | ); 42 | @include should(expect( 43 | flint-get-instance-value("desktop", "columns")), 44 | to(be(16)) 45 | ); 46 | @include should(expect( 47 | flint-get-instance-value("desktop", "span")), 48 | to(be(4)) 49 | ); 50 | @include should(expect( 51 | flint-get-instance-value("desktop", "internal", "width")), 52 | to(be(18.75em)) 53 | ); 54 | } 55 | 56 | @include it("should expect non-existent values to return false") { 57 | @include should(expect( 58 | flint-get-instance-value("mobile", "breakpoint")), 59 | to(be(false)) 60 | ); 61 | @include should(expect( 62 | flint-get-instance-value("laptop", "columns")), 63 | to(be(false)) 64 | ); 65 | } 66 | } 67 | } 68 | } 69 | 70 | $flint-instances: () !global; 71 | $flint-instance-count: 0 !global; 72 | } 73 | -------------------------------------------------------------------------------- /tests/input/functions/lib/_calc-breakpoint.scss: -------------------------------------------------------------------------------- 1 | // 2 | // Calculate breakpoint query 3 | // 4 | @include describe("[function] calc-breakpoint") { 5 | 6 | @include it("should expect breakpoint of passed key") { 7 | @include should(expect( 8 | flint-calc-breakpoint("alias", "desktop", 1)), 9 | to(be(80em)) 10 | ); 11 | @include should(expect( 12 | flint-calc-breakpoint("alias", "laptop", 2)), 13 | to(be(60em)) 14 | ); 15 | @include should(expect( 16 | flint-calc-breakpoint("alias", "tablet", 3)), 17 | to(be(40em)) 18 | ); 19 | @include should(expect( 20 | flint-calc-breakpoint("alias", "mobile", 4)), 21 | to(be(20em)) 22 | ); 23 | } 24 | 25 | @include it("should expect next breakpoint down from passed key") { 26 | @include should(expect( 27 | flint-calc-breakpoint("next", "desktop", 1)), 28 | to(be(60em)) 29 | ); 30 | @include should(expect( 31 | flint-calc-breakpoint("next", "laptop", 2)), 32 | to(be(40em)) 33 | ); 34 | @include should(expect( 35 | flint-calc-breakpoint("next", "tablet", 3)), 36 | to(be(20em)) 37 | ); 38 | @include should(expect( 39 | flint-calc-breakpoint("next", "mobile", 4)), 40 | to(be(0)) 41 | ); 42 | } 43 | 44 | @include it("should expect previous breakpoint up from passed key") { 45 | @include should(expect( 46 | flint-calc-breakpoint("prev", "desktop", 1)), 47 | to(be(80em)) 48 | ); 49 | @include should(expect( 50 | flint-calc-breakpoint("prev", "laptop", 2)), 51 | to(be(80em)) 52 | ); 53 | @include should(expect( 54 | flint-calc-breakpoint("prev", "tablet", 3)), 55 | to(be(60em)) 56 | ); 57 | @include should(expect( 58 | flint-calc-breakpoint("prev", "mobile", 4)), 59 | to(be(40em)) 60 | ); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Contributing to Flint 2 | 3 | We love contributors! If you would like to contribute to Flint, please adhere the following guidelines: 4 | 5 | * **Please, do not issue a pull request without a related issue.** _All_ pull requests must reference an issue in the [issue queue](https://github.com/ezekg/flint/issues) and will only be looked at after discussion has taken place about the given issue. _Any pull request created that does not reference an issue will be closed._ 6 | * **All pull requests should be tested against our [standard test suite](#testing).** If any of the tests fail, we will ask you to fix your code so that the tests no longer fail. Any new features that are added must have accompanying passing tests before being considered. During a pull request, we may ask for additional tests to be written in order to ensure that what is being changed does not have negative effects elsewhere. 7 | * **Create a new pull request for each individual feature added or bug fixed, unless they are related.** Contributions that _are not_ in the form of a pull request will not be considered. If we make changes or suggest that you make changes to your code, don't take it personally, as we are sticklers for a consistent coding standard throughout Flint. _If you submit a pull request that contains more than one feature or bug fix that are not related, we might ask you to rewrite your commits._ 8 | * **Before filing an issue** ensure that the issue is reproducible either by using [SassMeister](http://sassmeister.com/) or under Bundler control. Post the versions of all gems being used and the smallest set of example code of how to reproduce the error. _Issues that are not reproducible will be closed._ 9 | 10 | ### Testing 11 | 12 | We have automated tests set up to ensure our build is working. To test, you must install [Bundler](http://bundler.io/), which will allow you to install all needed gem versions. Once you have Bundler up and running, run `bundler install` to install all of Flint's dependencies. After that, you can run the test suite once with `rake test`, or you can also watch the directory while you work with `rake test[watch]`. 13 | -------------------------------------------------------------------------------- /stylesheets/flint/config/_config.scss: -------------------------------------------------------------------------------- 1 | /// 2 | /// Configuration map 3 | /// 4 | /// @type Map 5 | /// 6 | /// @prop {Map} breakpoints - map of breakpoints, follow DSC order 7 | /// @prop {Map} breakpoints.alias - named map of breakpoint settings 8 | /// @prop {Number} breakpoints.alias.columns - column count for breakpoint 9 | /// @prop {Number} breakpoints.alias.breakpoint - breakpoint value for breakpoint 10 | /// 11 | /// @prop {Map} settings - map of settings for grid 12 | /// @prop {String} settings.default - alias of breakpoint to be grid default 13 | /// @prop {String} settings.grid - type of grid 14 | /// @prop {Number} settings.gutter - value for gutter 15 | /// @prop {String} settings.float-direction - direction of float 16 | /// @prop {Bool} settings.max-width - maximum width value 17 | /// @prop {Bool} settings.center-container - center containers 18 | /// @prop {Bool} settings.border-box-sizing - use `box-sizing: border-box` 19 | /// @prop {Bool} settings.instance-maps - use instance maps for added features 20 | /// @prop {Bool} settings.support-syntax - support syntax within instance functions 21 | /// @prop {Bool} settings.debug-mode - enable debug mode 22 | /// 23 | /// @group Configuration 24 | /// 25 | $flint: ( 26 | "breakpoints": ( 27 | "desktop": ( 28 | "columns": 16, 29 | "breakpoint": 80em 30 | ), 31 | "laptop": ( 32 | "columns": 12, 33 | "breakpoint": 60em 34 | ), 35 | "tablet": ( 36 | "columns": 8, 37 | "breakpoint": 40em 38 | ), 39 | "mobile": ( 40 | "columns": 4, 41 | "breakpoint": 20em 42 | ) 43 | ), 44 | "settings": ( 45 | "default": "mobile", 46 | "grid": "fluid", 47 | "gutter": 0.625em, 48 | "float-direction": "left", 49 | "max-width": true, 50 | "center-container": true, 51 | "border-box-sizing": true, 52 | "instance-maps": true, 53 | "support-syntax": false, 54 | "debug-mode": false 55 | ) 56 | ) !default; 57 | -------------------------------------------------------------------------------- /stylesheets/flint/mixins/lib/_grid-overlay.scss: -------------------------------------------------------------------------------- 1 | /// 2 | /// Create encoded SVG grid overlay 3 | /// 4 | /// @access private 5 | /// 6 | /// @param {String} $key - breakpoint alias 7 | /// @param {Number} $breakpoint - breakpoint value 8 | /// @param {Number} $columns - breakpoint column count 9 | /// @param {Number} $gutter - gutter value 10 | /// 11 | /// @group Internal Mixins 12 | /// 13 | @mixin flint-svg-grid($key, $breakpoint, $columns, $gutter) { 14 | $svg: ""; 15 | $svg: $svg + ""; 16 | $svg: $svg + ""; 17 | $svg: $svg + ""; 18 | $svg: $svg + ""; 19 | $svg: $svg + ""; 20 | $svg: $svg + ""; 21 | 22 | @for $i from 1 through $columns { 23 | $x: flint-fluid-width(((($breakpoint / $columns) * ($i - 1)) + $gutter), $breakpoint); 24 | $span: flint-fluid-width(((($breakpoint) / $columns)) - ($gutter * 2), $breakpoint); 25 | $svg: $svg + ""; 26 | } 27 | 28 | $svg: $svg + ""; 29 | 30 | @include _($key) { 31 | max-width: $breakpoint; 32 | background: { 33 | image: url("data:image/svg+xml," + flint-html-encode($svg)); 34 | size: 100% 100%; 35 | position: 0 0; 36 | } 37 | } 38 | } 39 | 40 | /// 41 | /// Apply SVG grid overlay 42 | /// 43 | /// @access private 44 | /// 45 | /// @group Internal Mixins 46 | /// 47 | @mixin flint-overlay-grid { 48 | @at-root html { 49 | position: relative; 50 | 51 | &:after { 52 | transform: translateX(-50%); 53 | content: " "; 54 | position: absolute; 55 | display: block; 56 | top: 0; 57 | left: 50%; 58 | bottom: 0; 59 | right: 0; 60 | width: 100%; 61 | height: 100%; 62 | opacity: 0.25; 63 | z-index: 9999; 64 | pointer: { 65 | events: none; 66 | } 67 | 68 | @each $key, $settings in flint-get-value("breakpoints") { 69 | @include flint-svg-grid($key, map-get($settings, "breakpoint"), map-get($settings, "columns"), flint-get-gutter()); 70 | } 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /stylesheets/flint/globals/_globals.scss: -------------------------------------------------------------------------------- 1 | //// 2 | /// @group Internal Variables 3 | //// 4 | 5 | /// 6 | /// Use development mode to silence fatal errors 7 | /// 8 | /// @access private 9 | /// 10 | /// @type Bool 11 | /// 12 | $flint-development-mode: false !global; 13 | 14 | /// 15 | /// Set global variable to check if foundation has been set 16 | /// 17 | /// @access private 18 | /// 19 | /// @type Bool 20 | /// 21 | $flint-foundation: false !global; 22 | 23 | /// 24 | /// Keep count of all instances 25 | /// 26 | /// @access private 27 | /// 28 | /// @type Number 29 | /// 30 | $flint-instance-count: 0 !global; 31 | 32 | /// 33 | /// Keep map of all instances 34 | /// 35 | /// @access private 36 | /// 37 | /// @type Map 38 | /// 39 | $flint-instances: () !global; 40 | 41 | /// 42 | /// Font size for em calculation 43 | /// 44 | /// @access private 45 | /// 46 | /// @type Number 47 | /// 48 | $flint-base-font-size: 16px !global; 49 | 50 | /// 51 | /// Detect if Ruby functions are available 52 | /// 53 | /// @access private 54 | /// 55 | /// @type Bool 56 | /// 57 | $flint-use-ruby-functions: if(flint-use-ruby-functions() == true, true, false) !global; 58 | 59 | /// 60 | /// Global syntax support 61 | /// 62 | /// @access private 63 | /// 64 | /// @type String 65 | /// 66 | $flint-support-syntax: flint-get-value("settings", "support-syntax") !global; 67 | 68 | /// 69 | /// Gather all keys, breakpoints and column counts 70 | /// 71 | /// @access private 72 | /// 73 | /// @type List 74 | /// 75 | $flint-all-keys: flint-get-all-keys() !global; 76 | $flint-all-breakpoints: flint-get-all-breakpoints() !global; 77 | $flint-all-columns: flint-get-all-columns() !global; 78 | 79 | /// 80 | /// Cache selector instance lists 81 | /// 82 | /// @access private 83 | /// 84 | /// @type Map 85 | /// 86 | $flint-cached-instances: () !global; 87 | 88 | /// 89 | /// Cache calculated values 90 | /// 91 | /// @access private 92 | /// 93 | /// @type Map 94 | /// 95 | $flint-cached-values: () !global; 96 | 97 | /// 98 | /// Cache calculation results 99 | /// 100 | /// @access private 101 | /// 102 | /// @type Map 103 | /// 104 | $flint-cached-results: () !global; 105 | 106 | /// 107 | /// Bool check for overlay 108 | /// 109 | /// @access private 110 | /// 111 | /// @type Bool 112 | /// 113 | $flint-overlay: false !global; 114 | 115 | /// 116 | /// Color for grid overlay 117 | /// 118 | /// @access private 119 | /// 120 | /// @type Color 121 | /// 122 | $flint-overlay-color: #f33 !global; 123 | -------------------------------------------------------------------------------- /stylesheets/flint/functions/lib/_calc-width.scss: -------------------------------------------------------------------------------- 1 | /// 2 | /// Calculate width 3 | /// 4 | /// @access private 5 | /// 6 | /// @param {String} $key - key of breakpoint 7 | /// @param {Number} $span - span value of element 8 | /// @param {Number|String} $context [null] - context value of element 9 | /// @param {Number} $deduct [null] - subtract value out of final width 10 | /// 11 | /// @return {Map} - map of target and context result 12 | /// 13 | /// @group Internal Functions 14 | /// 15 | @function flint-calc-width($key, $span, $context: null, $deduct: null) { 16 | $result: (); 17 | 18 | // Check to see if value has been cached 19 | @if map-has-key($flint-cached-values, "#{$key, $span, $context, $deduct}::width") and $context != "auto" { 20 | @return map-get($flint-cached-values, "#{$key, $span, $context, $deduct}::width"); 21 | } 22 | 23 | @if $span == "container" { 24 | 25 | $result: flint-get-value("breakpoints", $key, "breakpoint"); 26 | 27 | } @else if $context == "auto" { 28 | 29 | // 30 | // Check if instance maps are enabled 31 | // 32 | @if not flint-get-value("settings", "instance-maps") { 33 | @if not $flint-development-mode { 34 | @error "Instance maps are disabled. Automatic context is not available. Enable `instance-maps` in the config to continue."; 35 | } @else { 36 | @warn "Instance maps are disabled. Automatic context is not available. Enable `instance-maps` in the config to continue."; 37 | } 38 | } 39 | 40 | @if flint-has-family-instance($key) { 41 | $result: map-merge($result, ("target": ((flint-get-instance-value($key, "internal", "width") / flint-get-instance-value($key, "span") * $span) - if($deduct, $deduct, 0)))); 42 | $result: map-merge($result, ("context": flint-get-instance-value($key, "internal", "width"))); 43 | } @else { 44 | @if not $flint-development-mode { 45 | @error "You set context to `#{$context}`, but a parent instance could not be found for `#{nth(&, 1) + '::' + $key}`"; 46 | } @else { 47 | @return false; 48 | } 49 | } 50 | 51 | } @else { 52 | 53 | $result: map-merge($result, ("target": ((flint-get-value("breakpoints", $key, "breakpoint") / flint-get-value("breakpoints", $key, "columns") * $span) - if($deduct, $deduct, 0)))); 54 | 55 | @if $context { 56 | $result: map-merge($result, ("context": flint-get-value("breakpoints", $key, "breakpoint") / flint-get-value("breakpoints", $key, "columns") * $context)); 57 | } @else { 58 | $result: map-merge($result, ("context": flint-get-value("breakpoints", $key, "breakpoint"))); 59 | } 60 | 61 | } 62 | 63 | // Save result to cache 64 | @if $context != "auto" { 65 | $flint-cached-values: map-merge($flint-cached-values, ("#{$key, $span, $context, $deduct}::width": $result)) !global; 66 | } 67 | 68 | // Return result 69 | @return $result; 70 | } 71 | -------------------------------------------------------------------------------- /stylesheets/flint/functions/lib/_has-family-instance.scss: -------------------------------------------------------------------------------- 1 | /// 2 | /// Checks if instance exists in selector familiy tree, falls back from current selector 3 | /// 4 | /// @access private 5 | /// 6 | /// @param {String} $key - breakpoint key to search for matching instance 7 | /// @param {String} $syntax - searches for instance using passed syntax parser 8 | /// 9 | /// @return {String|False} instance selector 10 | /// 11 | /// @group Internal Functions 12 | /// 13 | @function flint-has-family-instance($key: flint-get-value("settings", "default"), $syntax: $flint-support-syntax) { 14 | $selector: nth(&, 1); 15 | 16 | @if not $key or not $selector { 17 | @return false; 18 | } 19 | 20 | // Check if instance result had been cached 21 | @if map-has-key($flint-cached-instances, "#{$selector}") { 22 | // Get cached instance 23 | $cached-instance: map-get($flint-cached-instances, "#{$selector}"); 24 | // Return with current key 25 | @return "#{$cached-instance}::#{$key}"; 26 | } 27 | 28 | // Check for syntax support, try to find instance using it 29 | @if $syntax { 30 | 31 | $parsed-selector: flint-use-syntax($selector); 32 | $length: length($parsed-selector); 33 | 34 | // Loop through transformed selectors 35 | @for $i from 1 through $length { 36 | 37 | // Check last selector in list 38 | @if map-has-key($flint-instances, "#{flint-last($parsed-selector)}::#{$key}") { 39 | 40 | // Cache result 41 | $flint-cached-instances: map-merge($flint-cached-instances, ("#{$selector}": "#{flint-last($parsed-selector)}")) !global; 42 | 43 | // Return the matching instance key 44 | @return "#{flint-last($parsed-selector)}::#{$key}"; 45 | 46 | } @else { 47 | 48 | // Else, remove the last selector and loop again 49 | $parsed-selector: flint-remove($parsed-selector, flint-last($parsed-selector)); 50 | 51 | } 52 | } 53 | 54 | // Search for a parent instance normally 55 | @return flint-has-family-instance($key, null); 56 | 57 | } @else { 58 | $selector-list: $selector; 59 | $length: length($selector-list); 60 | 61 | // Loop through length of list of selectors 62 | @for $i from 1 through $length { 63 | $selector-string: flint-list-to-str($selector-list, " "); 64 | 65 | // Make sure that we're not counting the current selector set 66 | @if map-has-key($flint-instances, "#{$selector-string}::#{$key}") and $selector != $selector-list { 67 | 68 | // Cache result 69 | $flint-cached-instances: map-merge($flint-cached-instances, ("#{$selector}": "#{$selector-string}")) !global; 70 | 71 | // Return the matching instance key 72 | @return "#{$selector-string}::#{$key}"; 73 | 74 | } @else { 75 | 76 | // Else, remove the last selector and loop again 77 | $selector-list: flint-remove($selector-list, flint-last($selector-list)); 78 | 79 | } 80 | } 81 | 82 | @return false; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /stylesheets/flint/functions/lib/_str-to-list.scss: -------------------------------------------------------------------------------- 1 | /// 2 | /// Turns string into a flat list 3 | /// 4 | /// @access private 5 | /// 6 | /// @param {String} $string - string to perform on 7 | /// @param {String} $find [" "] - item to find which separates substrings 8 | /// @param {String} $ignore [","] - removes remaining string beyond item 9 | /// 10 | /// @return {List} 11 | /// 12 | /// @group Internal Functions 13 | /// 14 | @function flint-str-to-list($string, $find: " ", $ignore: ",") { 15 | @if not flint-is-string($string) { 16 | @return false; 17 | } 18 | 19 | // Use Ruby function if available 20 | @if $flint-use-ruby-functions { 21 | @return flint_ruby_str_to_list($string, $find, $ignore); 22 | } 23 | 24 | $string-list: (); 25 | $space-indexes: (); 26 | $ignore-remainder: (); 27 | $length: str-length($string); 28 | 29 | // Find ignore separator, and flint-remove remainder of string beyond that point 30 | @for $i from 1 through $length { 31 | $slice: str-slice($string, $i, $i); 32 | @if $slice == $ignore { 33 | $ignore-remainder: append($ignore-remainder, $i - 1, "comma"); 34 | } 35 | } 36 | 37 | // Redefine string and length 38 | @if length($ignore-remainder) >= 1 { 39 | $string: str-slice($string, 1, nth($ignore-remainder, 1)); 40 | $length: str-length($string); 41 | } 42 | 43 | // Find all spaces and their indices by looking over each character in string 44 | @for $i from 1 through $length { 45 | $slice: str-slice($string, $i, $i); 46 | @if $slice == $find { 47 | $space-indexes: append($space-indexes, $i, "comma"); 48 | } 49 | } 50 | 51 | // Check if there are any spaces 52 | @if length($space-indexes) < 1 { 53 | @return flint-purge(append($string-list, $string)); 54 | } 55 | 56 | // Keep a count of number of spaces 57 | $count: 1; 58 | 59 | // Loop through each space 60 | @each $space in $space-indexes { 61 | 62 | // If is initial count, grab first substring and store in list 63 | @if $count == 1 { 64 | $matched-string: str-slice($string, 0, ($space - 1)); 65 | 66 | @if $matched-string != "" { 67 | $string-list: append($string-list, $matched-string, "comma"); 68 | } 69 | // Else, add a little math to make up for the spaces to do the same 70 | } @else { 71 | $matched-string: str-slice($string, (nth($space-indexes, ($count - 1)) + 1), ($space - 1)); 72 | 73 | @if $matched-string != "" { 74 | $string-list: append($string-list, $matched-string, "comma"); 75 | } 76 | } 77 | 78 | // Increase count 79 | $count: $count + 1; 80 | } 81 | 82 | // Now grab that last selector 83 | $flint-last-space: nth($space-indexes, length($space-indexes)); 84 | $matched-string: str-slice($string, ($flint-last-space + 1), $length); 85 | $string-list: append($string-list, $matched-string, "comma"); 86 | 87 | // Finally, return comma separated list of selectors 88 | @return flint-purge($string-list); 89 | } 90 | -------------------------------------------------------------------------------- /lib/flint/functions.rb: -------------------------------------------------------------------------------- 1 | module Flint 2 | 3 | def self.declare(*args) 4 | Sass::Script::Functions.declare(*args) 5 | end 6 | 7 | # 8 | # Use ruby functions 9 | # 10 | # @return {Bool} 11 | # 12 | def flint_use_ruby() 13 | Sass::Script::Bool.new(true) 14 | end 15 | 16 | # 17 | # Fetch value from map 18 | # 19 | # @param {Map} map - map to fetch value from 20 | # @param {ArgList} keys - list of keys to traverse 21 | # 22 | # @return {*} 23 | # 24 | def flint_ruby_map_fetch(map, *keys) 25 | assert_type map, :Map, :map 26 | 27 | result = map 28 | keys.each { |key| result.nil? ? break : result = result.to_h.fetch(key, nil) } 29 | 30 | unless result.nil? 31 | result 32 | else 33 | Sass::Script::Bool.new(false) 34 | end 35 | end 36 | declare :flint_ruby_map_fetch, :args => [:map, :keys], :var_args => true 37 | 38 | # 39 | # Joins all elements of list with passed glue 40 | # 41 | # @param {List} list 42 | # @param {String} glue 43 | # 44 | # @return {String} 45 | # 46 | def flint_ruby_list_to_str(list, glue) 47 | assert_type list, :List, :list 48 | assert_type glue, :String, :glue 49 | 50 | arr = list.to_a.flatten.map { |item| item.value } 51 | 52 | Sass::Script::String.new(arr.join(glue.value)) 53 | end 54 | declare :flint_ruby_list_to_str, :args => [:list, :glue] 55 | 56 | # 57 | # Turn string into a flat list 58 | # 59 | # @param {String} string - string to operate on 60 | # @param {String} separator - item to find which separates substrings 61 | # @param {String} ignore - removes remaining string beyond item 62 | # 63 | # @return {List} 64 | # 65 | def flint_ruby_str_to_list(string, separator, ignore) 66 | assert_type string, :String, :string 67 | assert_type separator, :String, :separator 68 | assert_type ignore, :String, :ignore 69 | 70 | # Remove everything after ignore, split with separator 71 | items = string.value[/[^#{ignore}]+/].split(separator.value) 72 | 73 | if items.count == 1 74 | Sass::Script::String.new(items[0], :comma) 75 | else 76 | Sass::Script::List.new(items.map { |i| Sass::Script::String.new(i) }, :comma) 77 | end 78 | end 79 | declare :flint_ruby_str_to_list, :args => [:string, :separator, :ignore] 80 | 81 | # 82 | # Replace substring with string 83 | # 84 | # @param {String} string - string that contains substring 85 | # @param {String} find - substring to replace 86 | # @param {String} replace - new string to replace sub with 87 | # 88 | # @return {String} 89 | # 90 | def flint_ruby_str_replace(string, find, replace) 91 | assert_type string, :String, :string 92 | assert_type find, :String, :find 93 | assert_type replace, :String, :replace 94 | 95 | Sass::Script::String.new(string.value.gsub(find.value, replace.value)) 96 | end 97 | declare :flint_ruby_str_replace, :args => [:string, :find, :replace] 98 | 99 | end 100 | -------------------------------------------------------------------------------- /tests/tests.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | 110 | 111 | -------------------------------------------------------------------------------- /stylesheets/flint/functions/helpers/_helpers.scss: -------------------------------------------------------------------------------- 1 | //// 2 | /// @group Internal Helper Functions 3 | //// 4 | 5 | /// 6 | /// Returns truthiness of a value 7 | /// 8 | /// @access private 9 | /// 10 | /// @param {*} $value 11 | /// 12 | /// @return {Bool} 13 | /// 14 | @function flint-is-true($value) { 15 | @return if($value == null, false, $value and $value != null and $value != "" and $value != ()); 16 | } 17 | 18 | /// 19 | /// Checks if item is map 20 | /// 21 | /// @access private 22 | /// 23 | /// @param {Map} $n 24 | /// 25 | /// @return {Bool} 26 | /// 27 | @function flint-is-map($n) { 28 | @return type-of($n) == "map"; 29 | } 30 | 31 | /// 32 | /// Checks if item is list 33 | /// 34 | /// @access private 35 | /// 36 | /// @param {List} $n 37 | /// 38 | /// @return {Bool} 39 | /// 40 | @function flint-is-list($n) { 41 | @return type-of($n) == "list"; 42 | } 43 | 44 | /// 45 | /// Checks if item is number 46 | /// 47 | /// @access private 48 | /// 49 | /// @param {Number} $n 50 | /// 51 | /// @return {Bool} 52 | /// 53 | @function flint-is-number($n) { 54 | @return type-of($n) == "number"; 55 | } 56 | 57 | /// 58 | /// Checks if item is string 59 | /// 60 | /// @access private 61 | /// 62 | /// @param {String} $n 63 | /// 64 | /// @return {Bool} 65 | /// 66 | @function flint-is-string($n) { 67 | @return type-of($n) == "string"; 68 | } 69 | 70 | /// 71 | /// Checks if item is not string 72 | /// 73 | /// @access private 74 | /// 75 | /// @param {String} $n 76 | /// 77 | /// @return {Bool} 78 | /// 79 | @function flint-is-not-string($n) { 80 | @return type-of($n) != "string"; 81 | } 82 | 83 | /// 84 | /// Get gutter value from config map 85 | /// 86 | /// @access private 87 | /// 88 | /// @return {Number} 89 | /// 90 | @function flint-get-gutter() { 91 | @return flint-get-value("settings", "gutter"); 92 | } 93 | 94 | /// 95 | /// Gets list of each breakpoint's key 96 | /// 97 | /// @access private 98 | /// 99 | /// @return {List} 100 | /// 101 | @function flint-get-all-keys() { 102 | @return map-keys(flint-get-value("breakpoints")); 103 | } 104 | 105 | /// 106 | /// Gets list of all breakpoints 107 | /// 108 | /// @access private 109 | /// 110 | /// @return {List} 111 | /// 112 | @function flint-get-all-breakpoints() { 113 | $all-keys: flint-get-all-keys(); 114 | $all-breakpoints: (); 115 | 116 | @each $key in $all-keys { 117 | $all-breakpoints: append($all-breakpoints, flint-get-value("breakpoints", $key, "breakpoint"), "comma"); 118 | } 119 | 120 | @return $all-breakpoints; 121 | } 122 | 123 | /// 124 | /// Checks if passed $key is the highest breakpoint 125 | /// 126 | /// @access private 127 | /// 128 | /// @param {String} $key - alias of breakpoint 129 | /// 130 | /// @return {Bool} 131 | /// 132 | @function flint-is-highest-breakpoint($key) { 133 | @return flint-get-value("breakpoints", $key, "breakpoint") == max(flint-get-all-breakpoints()...); 134 | } 135 | 136 | /// 137 | /// Checks if passed $key is the lowest breakpoint 138 | /// 139 | /// @access private 140 | /// 141 | /// @param {String} $key - alias of breakpoint 142 | /// 143 | /// @return {Bool} 144 | /// 145 | @function flint-is-lowest-breakpoint($key) { 146 | @return flint-get-value("breakpoints", $key, "breakpoint") == min(flint-get-all-breakpoints()...); 147 | } 148 | 149 | /// 150 | /// Checks if $key is grid default 151 | /// 152 | /// @access private 153 | /// 154 | /// @param {String} $key - alias of breakpoint 155 | /// 156 | /// @return {Bool} 157 | /// 158 | @function flint-is-default($key) { 159 | @return $key == flint-get-value("settings", "default"); 160 | } 161 | 162 | /// 163 | /// Gets all breakpoint column values 164 | /// 165 | /// @access private 166 | /// 167 | /// @return {List} 168 | /// 169 | @function flint-get-all-columns() { 170 | $all-keys: flint-get-all-keys(); 171 | $all-columns: (); 172 | 173 | @each $key in $all-keys { 174 | $all-columns: append($all-columns, flint-get-value("breakpoints", $key, "columns"), "comma"); 175 | } 176 | 177 | @return $all-columns; 178 | } 179 | 180 | /// 181 | /// Returns the unit used in config 182 | /// 183 | /// @access private 184 | /// 185 | /// @return {*} 186 | /// 187 | @function flint-get-config-unit() { 188 | @return unit(flint-get-value("settings", "gutter")); 189 | } 190 | 191 | /// 192 | /// Convert pixel value to em 193 | /// 194 | /// @access private 195 | /// 196 | /// @param {Number} $target - pixel value 197 | /// @param {Number} $context - context to divide by 198 | /// 199 | /// @return {Number} em value of target relative to context 200 | /// 201 | @function flint-to-em($target, $context: $flint-base-font-size) { 202 | @return ($target / $context) * 1em; 203 | } 204 | 205 | // 206 | /// Convert pixel value to rem 207 | /// 208 | /// @access private 209 | /// 210 | /// @param {Number} $target - pixel value 211 | /// @param {Number} $context - context to divide by 212 | /// 213 | /// @return {Number} rem value of target relative to context 214 | /// 215 | @function flint-to-rem($target, $context: $flint-base-font-size) { 216 | @return ($target / $context) * 1rem; 217 | } 218 | 219 | /// 220 | /// Use Ruby functions in place of Sass functions where possible 221 | /// to speed up performance, especially with string functions 222 | /// 223 | /// @access private 224 | /// 225 | /// @return {Bool} 226 | /// 227 | @function flint-use-ruby-functions() { 228 | @return flint_use_ruby() == true; 229 | } 230 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Gem](https://img.shields.io/gem/v/flint-gs.svg?style=flat-square)](https://rubygems.org/gems/flint-gs) 2 | [![Bower](https://img.shields.io/bower/v/flint.svg?style=flat-square)](http://bower.io/search/?q=flint) 3 | [![NPM](https://img.shields.io/npm/v/flint-gs.svg?style=flat-square)](https://www.npmjs.com/package/flint-gs) 4 | [![Travis](https://img.shields.io/travis/ezekg/flint.svg?style=flat-square)](https://travis-ci.org/ezekg/flint) 5 | [![GitHub license](https://img.shields.io/github/license/ezekg/flint.svg?style=flat-square)](https://github.com/ezekg/flint/blob/master/LICENSE) 6 | 7 | ## What is Flint? 8 | Flint is a responsive grid framework written in Sass, created to allow developers to rapidly produce responsive layouts that are built on a sophisticated foundation. 9 | 10 | ## What sets Flint apart? 11 | Most notably? The syntax. Being a designer myself, a large amount of time was spent on this aspect. Flint is very unique in the fact that it uses only a single mixin for all output: `_(...)`. 12 | 13 | Yes, it really is just an underscore. Easy to remember, huh? It shoves the function mumbo-jumbo out of the way and allows you to focus on the aspect that matters most: the actual layout. It also allows you to type your intentions in human terms. 14 | 15 | ```scss 16 | @include _(from tablet to desktop) { ... } 17 | @include _(16 12 8 4, $gutter: no-left); 18 | ``` 19 | 20 | In addition to that, as you can tell from the snippet above, Flint also handles your breakpoints for you. Long gone are the days that you need to download a separate plugin just so that you're able to create a truly responsive layout. 21 | 22 | Flint allows you create an unlimited number of breakpoints, all of which have their own alias, column count and breakpoint. Want to name your 10 breakpoints after James Bond villians? By all means, go ahead. 23 | 24 | One more cool thing? Flint is the only self-aware Sass grid system on the planet.* What does that mean? It means that every instance of Flint is logged into an 'instance map', so child elements can know their parent element's width; meaning we can have perfectly consistent gutters, no matter how odd your layout may be. Think of it as a self-correcting grid. 25 | 26 | [Check out this short introduction over at Sitepoint.com](http://www.sitepoint.com/rapid-responsive-development-sass-flint/), and take it for a spin on [SassMeister.com](http://sassmeister.com/gist/228449011362bcdfe38c)! 27 | 28 | Enjoy. 29 | 30 | ## Requirements 31 | 32 | * Sass ~> `3.4.0` 33 | 34 | ## Installation 35 | 36 | 1. Install via Ruby `gem install flint-gs`, or Bower `bower install flint --save-dev` 37 | 2. If you're using Compass, add `require "flint"` to your `config.rb` 38 | 3. Import it into your stylesheet with `@import "flint"` 39 | 40 | If you're not using Compass, you can require Flint and compile via cli: 41 | ``` 42 | scss --require ./lib/flint.rb example.scss > example.css 43 | ``` 44 | 45 | ## Documentation 46 | 47 | Documentation is located [here](https://github.com/ezekg/flint/blob/master/stylesheets/flint/mixins/lib/_main.scss). 48 | 49 | _Tip: For simple projects, disable `instance-maps`, as it is has a large overhead and will increase your compile times._ 50 | 51 | ## Syntax support 52 | 53 | As of `1.6.0`, you can add syntax support for your preferred syntax. I built the system for BEM, but it should be easily extendable to 54 | support your preferred syntax. Simply create a function which parses a string of selectors into a valid list. For example, the BEM syntax 55 | function parses the selector string (for example, `.block__element__element`) like so, 56 | 57 | ```scss 58 | /// 59 | /// Parser to support BEM syntax 60 | /// 61 | /// @access private 62 | /// 63 | /// @param {List} $selectors - string of selectors to parse 64 | /// 65 | /// @return {List} - parsed list of selectors according to syntax 66 | /// 67 | /// @group Internal Functions 68 | /// 69 | @function flint-support-syntax-bem($selectors) { ... } 70 | ``` 71 | [View Source](https://github.com/ezekg/flint/blob/master/stylesheets/flint/functions/lib/_support-syntax-bem.scss) 72 | 73 | This will be parsed into a list of selectors: `.block, .block__element, .block__element__element`. The list of selectors can then be used by the 74 | instance system to look up a selectors parent, etc. To support your own preferred syntax: create a `flint-support-syntax-` function 75 | and hook into it through the config `"support-syntax": ""` option -- the system will attempt to use the `call()` function in 76 | order to parse the selector string. 77 | 78 | #### Officially supported syntaxes 79 | * [BEM](http://bem.info/) 80 | 81 | If you use one that isn't here, let me know and I'll look into officially supporting it. 82 | 83 | ## Support 84 | 85 | You can tweet [@FlintGrid](https://twitter.com/FlintGrid) with any questions or issues and I'll look into it. Be sure to include a [Gist](https://gist.github.com) or a [SassMeister](http://sassmeister.com) link. 86 | 87 | ## Authors 88 | 89 | [Ezekiel Gabrielse](http://ezekielg.com) 90 | 91 | ## Contributing 92 | 93 | As an open-source project, contributions are more than welcome, they're extremely helpful and actively encouraged. If you see any room for improvement, open an [issue](https://github.com/ezekg/flint/issues) or submit a [pull request](https://github.com/ezekg/flint/pulls). Also, make sure to take a look at the [contributing doc](CONTRIBUTING.md). 94 | 95 | ## License 96 | 97 | Flint is available under the [MIT](http://opensource.org/licenses/MIT) license. 98 | 99 | _\* According to Wikipedia, not really. But, all jokes aside, it's pretty awesome._ 100 | -------------------------------------------------------------------------------- /tests/input/functions/lib/_instance.scss: -------------------------------------------------------------------------------- 1 | // 2 | // Keeps count of all instances with arguments, stores in global var 3 | // 4 | @include describe("[function] instance") { 5 | 6 | $pseudo-instance: ( 7 | ".instance::desktop": ( 8 | "instance-count": 1, 9 | "parent-selector": none, 10 | "key": "desktop", 11 | "breakpoint": 80em, 12 | "columns": 16, 13 | "span": 4, 14 | "context": null, 15 | "gutter": null, 16 | "internal": ( 17 | "width": 18.75em, 18 | "margin-right": 0.625em, 19 | "margin-left": 0.625em 20 | ) 21 | ) 22 | ); 23 | 24 | .instance { 25 | @include _("desktop", 4); 26 | 27 | @at-root { 28 | @include it("should expect instance map to match pseudo instance") { 29 | @include should(expect(inspect($flint-instances)), to(be(inspect($pseudo-instance)))); 30 | } 31 | } 32 | 33 | $flint-instances: () !global; 34 | $flint-instance-count: 0 !global; 35 | 36 | $flint-instances: flint-instance("desktop", 4, null, null, 18.75em, 0.625em, 0.625em) !global; 37 | 38 | @at-root { 39 | @include it("should expect instance map to match pseudo instance") { 40 | @include should(expect(inspect($flint-instances)), to(be(inspect($pseudo-instance)))); 41 | } 42 | } 43 | } 44 | 45 | $flint-instances: () !global; 46 | $flint-instance-count: 0 !global; 47 | 48 | $pseudo-instance: ( 49 | ".parent-instance .child-instance::mobile": ( 50 | "instance-count": 8, 51 | "parent-selector": ".parent-instance::mobile", 52 | "key": "mobile", 53 | "breakpoint": 20em, 54 | "columns": 4, 55 | "span": 2, 56 | "context": 4, 57 | "gutter": normal, 58 | "internal": ( 59 | "width": 8.125em, 60 | "margin-right": 0.625em, 61 | "margin-left": 0.625em 62 | ) 63 | ), 64 | ".parent-instance .child-instance::tablet": ( 65 | "instance-count": 7, 66 | "parent-selector": ".parent-instance::tablet", 67 | "key": "tablet", 68 | "breakpoint": 40em, 69 | "columns": 8, 70 | "span": 2, 71 | "context": 4, 72 | "gutter": normal, 73 | "internal": ( 74 | "width": 8.4375em, 75 | "margin-right": 0.625em, 76 | "margin-left": 0.625em 77 | ) 78 | ), 79 | ".parent-instance .child-instance::laptop": ( 80 | "instance-count": 6, 81 | "parent-selector": ".parent-instance::laptop", 82 | "key": "laptop", 83 | "breakpoint": 60em, 84 | "columns": 12, 85 | "span": 2, 86 | "context": 4, 87 | "gutter": inside, 88 | "internal": ( 89 | "width": 7.1875em, 90 | "margin-right": 0.625em, 91 | "margin-left": 0.625em 92 | ) 93 | ), 94 | ".parent-instance .child-instance::desktop": ( 95 | "instance-count": 5, 96 | "parent-selector": ".parent-instance::desktop", 97 | "key": "desktop", 98 | "breakpoint": 80em, 99 | "columns": 16, 100 | "span": 2, 101 | "context": 4, 102 | "gutter": row, 103 | "internal": ( 104 | "width": 9.375em, 105 | "margin-right": 0, 106 | "margin-left": 0 107 | ) 108 | ), 109 | ".parent-instance::mobile": ( 110 | "instance-count": 4, 111 | "parent-selector": none, 112 | "key": "mobile", 113 | "breakpoint": 20em, 114 | "columns": 4, 115 | "span": 4, 116 | "context": null, 117 | "gutter": center, 118 | "internal": ( 119 | "width": 18.75em, 120 | "margin-right": auto, 121 | "margin-left": auto 122 | ) 123 | ), 124 | ".parent-instance::tablet": ( 125 | "instance-count": 3, 126 | "parent-selector": none, 127 | "key": "tablet", 128 | "breakpoint": 40em, 129 | "columns": 8, 130 | "span": 4, 131 | "context": null, 132 | "gutter": omega, 133 | "internal": ( 134 | "width": 19.375em, 135 | "margin-right": 0, 136 | "margin-left": 0.625em 137 | ) 138 | ), 139 | ".parent-instance::laptop": ( 140 | "instance-count": 2, 141 | "parent-selector": none, 142 | "key": "laptop", 143 | "breakpoint": 60em, 144 | "columns": 12, 145 | "span": 4, 146 | "context": null, 147 | "gutter": alpha, 148 | "internal": ( 149 | "width": 19.375em, 150 | "margin-right": 0.625em, 151 | "margin-left": 0 152 | ) 153 | ), 154 | ".parent-instance::desktop": ( 155 | "instance-count": 1, 156 | "parent-selector": none, 157 | "key": "desktop", 158 | "breakpoint": 80em, 159 | "columns": 16, 160 | "span": 4, 161 | "context": null, 162 | "gutter": normal, 163 | "internal": ( 164 | "width": 18.75em, 165 | "margin-right": 0.625em, 166 | "margin-left": 0.625em 167 | ) 168 | ) 169 | ); 170 | 171 | .parent-instance { 172 | @include _(4, $gutter: normal alpha omega center); 173 | 174 | .child-instance { 175 | @include _(2, "auto", $gutter: row inside normal normal); 176 | 177 | @at-root { 178 | @include it("should expect instance map to match pseudo instance map") { 179 | @include should(expect(inspect($flint-instances)), to(be(inspect($pseudo-instance)))); 180 | } 181 | } 182 | } 183 | } 184 | 185 | $flint-instances: () !global; 186 | $flint-instance-count: 0 !global; 187 | } 188 | -------------------------------------------------------------------------------- /tests/input/output.scss: -------------------------------------------------------------------------------- 1 | /// 2 | /// Configuration map 3 | /// 4 | 5 | // Bootcamp 6 | @import "../bootcamp/dist/bootcamp"; 7 | 8 | // Flint 9 | @import "../../stylesheets/flint"; 10 | 11 | $flint: ( 12 | "breakpoints": ( 13 | "desktop": ( 14 | "columns": 16, 15 | "breakpoint": 80em, 16 | ), 17 | "laptop": ( 18 | "columns": 12, 19 | "breakpoint": 60em, 20 | ), 21 | "tablet": ( 22 | "columns": 8, 23 | "breakpoint": 40em, 24 | ), 25 | "mobile": ( 26 | "columns": 4, 27 | "breakpoint": 20em, 28 | ), 29 | ), 30 | "settings": ( 31 | "default": "mobile", 32 | "grid": "fluid", 33 | "gutter": 0.625em, 34 | "float-direction": "left", 35 | "max-width": true, 36 | "center-container": true, 37 | "border-box-sizing": true, 38 | "instance-maps": true, 39 | "support-syntax": false, 40 | "debug-mode": true, 41 | ) 42 | ) !global; 43 | 44 | // Quick reset 45 | body { 46 | margin: 0; 47 | padding: 0; 48 | } 49 | 50 | // Enable development mode 51 | $flint-development-mode: true !global; 52 | 53 | // Test speed improvements 54 | // $flint-use-ruby-functions: false !global; 55 | 56 | /// 57 | /// BEGIN TESTS 58 | /// ----------- 59 | /// 60 | @include runner-start; 61 | /// 62 | /// ----------- 63 | /// BEGIN TESTS 64 | /// 65 | 66 | @include it("should expect foundation to not be set") { 67 | @include should(expect($flint-foundation), 68 | to(be(false)) 69 | ); 70 | } 71 | 72 | @include _("foundation"); 73 | 74 | @include it("should expect foundation to be set") { 75 | @include should(expect($flint-foundation), 76 | to(be(true)) 77 | ); 78 | } 79 | 80 | @import "functions/functions"; 81 | 82 | /// 83 | /// END TESTS 84 | /// --------- 85 | /// 86 | @include runner-end; 87 | /// 88 | /// --------- 89 | /// END TESTS 90 | /// 91 | 92 | 93 | 94 | /// 95 | /// Visual HTML test 96 | /// 97 | $color__blue: #2C3F52; 98 | $color__blue--dark: #15202A; 99 | $color__blue--darkest: #0E181E; 100 | $color__yellow: #FFF87B; 101 | 102 | // Pseudo content 103 | @mixin col-num($i) { 104 | &:before { 105 | @include _(desktop) { 106 | content: "#{$i} of 16"; 107 | } 108 | @include _(laptop) { 109 | @if $i > 12 { $i: 12; } 110 | content: "#{$i} of 12"; 111 | } 112 | @include _(tablet) { 113 | @if $i > 8 { $i: 8; } 114 | content: "#{$i} of 8"; 115 | } 116 | @include _(mobile) { 117 | @if $i > 4 { $i: 4; } 118 | content: "#{$i} of 4"; 119 | } 120 | } 121 | } 122 | 123 | // Generate cols 124 | @for $i from 1 through 16 { 125 | .col-#{$i} { 126 | 127 | @if $i == 16 { 128 | 129 | @include _($i 12 8 4); 130 | @include col-num($i); 131 | 132 | .col-#{$i}-child { 133 | @include _($i/2 12/2 8/2 4/2, auto); 134 | @include col-num($i/2); 135 | 136 | .col-#{$i}-grandchild { 137 | @include _($i/4 12/4 8/4 4/4, auto); 138 | @include col-num($i/4); 139 | } 140 | } 141 | 142 | } @else if $i > 12 { 143 | 144 | @include _($i 12 8 4); 145 | @include col-num($i); 146 | 147 | .col-#{$i}-child { 148 | @include _($i/2 12/2 8/2 4/2, auto); 149 | @include col-num($i/2); 150 | } 151 | 152 | } @else if $i > 8 { 153 | 154 | @include _($i $i 8 4); 155 | @include col-num($i); 156 | 157 | .col-#{$i}-child { 158 | @include _($i/2 $i/2 8/2 4/2, auto); 159 | @include col-num($i/2); 160 | } 161 | 162 | } @else if $i > 4 { 163 | 164 | @include _($i $i $i 4); 165 | @include col-num($i); 166 | 167 | .col-#{$i}-child { 168 | @include _($i/2 $i/2 $i/2 4/2, auto); 169 | @include col-num($i/2); 170 | } 171 | 172 | } @else { 173 | 174 | @include _($i); 175 | @include col-num($i); 176 | 177 | .col-#{$i}-child { 178 | @include _($i, auto); 179 | @include col-num($i); 180 | } 181 | 182 | } 183 | 184 | // background: if($i > 10, darken($color__blue, ($i*0.25)), lighten($color__blue, (16/$i))); 185 | clear: both; 186 | 187 | div { 188 | // background: if($i > 10, lighten($color__blue, ($i*0.25)), darken($color__blue, (16/$i))); 189 | height: 100% !important; 190 | 191 | div { 192 | // background: if($i > 10, darken($color__blue, ($i*0.25)), lighten($color__blue, (16/$i))); 193 | } 194 | } 195 | } 196 | } 197 | 198 | .col-third { 199 | @include _(16/3 12/3 8/3 4/3); 200 | // background: $color__blue; 201 | 202 | &:before { content: "1/3"; } 203 | } 204 | 205 | .col-fourth { 206 | @include _(16/4 12/4 8/4 4/4); 207 | // background: $color__blue; 208 | 209 | &:before { content: "1/4"; } 210 | } 211 | 212 | .col-fifth { 213 | @include _(16/5 12/5 8/5 4/5); 214 | // background: $color__blue; 215 | 216 | &:before { content: "1/5"; } 217 | 218 | .col-fifth-child { 219 | @include _((16/5)/3 (12/5)/3 (8/5)/3 (4/5)/3, auto); 220 | height: 100% !important; 221 | } 222 | } 223 | 224 | div[class*="col"] { 225 | position: relative; 226 | font: 10px Consolas, "Andale Mono WT", "Andale Mono", "Lucida Console", "Lucida Sans Typewriter", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Liberation Mono", "Nimbus Mono L", Monaco, "Courier New", Courier, monospace; 227 | color: $color__yellow; 228 | height: 120px; 229 | margin-top: 10px; 230 | margin-bottom: 10px; 231 | padding: 2em 0; 232 | outline: lighten($color__blue, 10%) solid 2px; 233 | 234 | &:before { 235 | position: absolute; 236 | top: 1em; 237 | left: 1em; 238 | } 239 | } 240 | 241 | section { 242 | background: $color__blue--darkest; 243 | // & + & { background: darken($color__blue--darkest, 5%); } 244 | // & + & + & { background: darken($color__blue--darkest, 10%); } 245 | // & + & + & + & { background: darken($color__blue--darkest, 15%); } 246 | } 247 | 248 | .container { 249 | @include _(container, clear); 250 | } 251 | -------------------------------------------------------------------------------- /tests/input/functions/lib/_calc-width.scss: -------------------------------------------------------------------------------- 1 | // 2 | // Calculate width 3 | // 4 | @include describe("[function] calc-width") { 5 | 6 | @include it("should expect full width columns to be equal to manually calculated value") { 7 | @include should(expect( 8 | flint-calc-width("desktop", 16)), 9 | to(be(("target": 80em, "context": 80em))) 10 | ); 11 | @include should(expect( 12 | flint-calc-width("laptop", 12)), 13 | to(be(("target": 60em, "context": 60em))) 14 | ); 15 | @include should(expect( 16 | flint-calc-width("tablet", 8)), 17 | to(be(("target": 40em, "context": 40em))) 18 | ); 19 | @include should(expect( 20 | flint-calc-width("mobile", 4)), 21 | to(be(("target": 20em, "context": 20em))) 22 | ); 23 | } 24 | 25 | @include it("should expect three-quarter width columns to be equal to manually calculated value") { 26 | @include should(expect( 27 | flint-calc-width("desktop", 12)), 28 | to(be(("target": (80em / 4 * 3), "context": 80em))) 29 | ); 30 | @include should(expect( 31 | flint-calc-width("laptop", 9)), 32 | to(be(("target": (60em / 4 * 3), "context": 60em))) 33 | ); 34 | @include should(expect( 35 | flint-calc-width("tablet", 6)), 36 | to(be(("target": (40em / 4 * 3), "context": 40em))) 37 | ); 38 | @include should(expect( 39 | flint-calc-width("mobile", 3)), 40 | to(be(("target": (20em / 4 * 3), "context": 20em))) 41 | ); 42 | } 43 | 44 | @include it("should expect half width columns to be equal to manually calculated value") { 45 | @include should(expect( 46 | flint-calc-width("desktop", 8)), 47 | to(be(("target": (80em / 2), "context": 80em))) 48 | ); 49 | @include should(expect( 50 | flint-calc-width("laptop", 6)), 51 | to(be(("target": (60em / 2), "context": 60em))) 52 | ); 53 | @include should(expect( 54 | flint-calc-width("tablet", 4)), 55 | to(be(("target": (40em / 2), "context": 40em))) 56 | ); 57 | @include should(expect( 58 | flint-calc-width("mobile", 2)), 59 | to(be(("target": (20em / 2), "context": 20em))) 60 | ); 61 | } 62 | 63 | @include it("should expect quarter width columns to be equal to manually calculated value") { 64 | @include should(expect( 65 | flint-calc-width("desktop", 4, null, 1em)), 66 | to(be(("target": (80em / 4) - 1em, "context": 80em))) 67 | ); 68 | @include should(expect( 69 | flint-calc-width("laptop", 3, null, 1em)), 70 | to(be(("target": (60em / 4) - 1em, "context": 60em))) 71 | ); 72 | @include should(expect( 73 | flint-calc-width("tablet", 2, null, 1em)), 74 | to(be(("target": (40em / 4) - 1em, "context": 40em))) 75 | ); 76 | @include should(expect( 77 | flint-calc-width("mobile", 1, null, 1em)), 78 | to(be(("target": (20em / 4) - 1em, "context": 20em))) 79 | ); 80 | } 81 | 82 | @include it("should expect single width columns to be equal to manually calculated value") { 83 | @include should(expect( 84 | flint-calc-width("desktop", 1)), 85 | to(be(("target": (80em / 16), "context": 80em))) 86 | ); 87 | @include should(expect( 88 | flint-calc-width("laptop", 1)), 89 | to(be(("target": (60em / 12), "context": 60em))) 90 | ); 91 | @include should(expect( 92 | flint-calc-width("tablet", 1)), 93 | to(be(("target": (40em / 8), "context": 40em))) 94 | ); 95 | @include should(expect( 96 | flint-calc-width("mobile", 1)), 97 | to(be(("target": (20em / 4), "context": 20em))) 98 | ); 99 | } 100 | 101 | @include it("should expect full width columns with context to be equal to manually calculated value") { 102 | @include should(expect( 103 | flint-calc-width("desktop", 8, 8)), 104 | to(be(("target": 40em, "context": 40em))) 105 | ); 106 | @include should(expect( 107 | flint-calc-width("laptop", 6, 6)), 108 | to(be(("target": 30em, "context": 30em))) 109 | ); 110 | @include should(expect( 111 | flint-calc-width("tablet", 4, 4)), 112 | to(be(("target": 20em, "context": 20em))) 113 | ); 114 | @include should(expect( 115 | flint-calc-width("mobile", 2, 2)), 116 | to(be(("target": 10em, "context": 10em))) 117 | ); 118 | } 119 | 120 | @include it("should expect three-quarter width columns with context to be equal to manually calculated value") { 121 | @include should(expect( 122 | flint-calc-width("desktop", 6, 8)), 123 | to(be(("target": (40em / 4 * 3), "context": 40em))) 124 | ); 125 | @include should(expect( 126 | flint-calc-width("laptop", 4.5, 6)), 127 | to(be(("target": (30em / 4 * 3), "context": 30em))) 128 | ); 129 | @include should(expect( 130 | flint-calc-width("tablet", 6, 8)), 131 | to(be(("target": (40em / 4 * 3), "context": 40em))) 132 | ); 133 | @include should(expect( 134 | flint-calc-width("mobile", 3, 4)), 135 | to(be(("target": (20em / 4 * 3), "context": 20em))) 136 | ); 137 | } 138 | 139 | @include it("should expect half width columns with context to be equal to manually calculated value") { 140 | @include should(expect( 141 | flint-calc-width("desktop", 4, 8)), 142 | to(be(("target": (40em / 2), "context": 40em))) 143 | ); 144 | @include should(expect( 145 | flint-calc-width("laptop", 3, 6)), 146 | to(be(("target": (30em / 2), "context": 30em))) 147 | ); 148 | @include should(expect( 149 | flint-calc-width("tablet", 2, 4)), 150 | to(be(("target": (20em / 2), "context": 20em))) 151 | ); 152 | @include should(expect( 153 | flint-calc-width("mobile", 1, 2)), 154 | to(be(("target": (10em / 2), "context": 10em))) 155 | ); 156 | } 157 | 158 | @include it("should expect quarter width columns with context to be equal to manually calculated value") { 159 | @include should(expect( 160 | flint-calc-width("desktop", 1, 4)), 161 | to(be(("target": (20em / 4), "context": 20em))) 162 | ); 163 | @include should(expect( 164 | flint-calc-width("laptop", 1, 4)), 165 | to(be(("target": (20em / 4), "context": 20em))) 166 | ); 167 | @include should(expect( 168 | flint-calc-width("tablet", 1, 4)), 169 | to(be(("target": (20em / 4), "context": 20em))) 170 | ); 171 | @include should(expect( 172 | flint-calc-width("mobile", 0.5, 2)), 173 | to(be(("target": (10em / 4), "context": 10em))) 174 | ); 175 | } 176 | 177 | @include it("should expect single width columns with context to be equal to manually calculated value") { 178 | @include should(expect( 179 | flint-calc-width("desktop", 1, 16)), 180 | to(be(("target": (80em / 16), "context": 80em))) 181 | ); 182 | @include should(expect( 183 | flint-calc-width("laptop", 1, 12)), 184 | to(be(("target": (60em / 12), "context": 60em))) 185 | ); 186 | @include should(expect( 187 | flint-calc-width("tablet", 1, 8)), 188 | to(be(("target": (40em / 8), "context": 40em))) 189 | ); 190 | @include should(expect( 191 | flint-calc-width("mobile", 1, 4)), 192 | to(be(("target": (20em / 4), "context": 20em))) 193 | ); 194 | } 195 | } 196 | -------------------------------------------------------------------------------- /stylesheets/flint/mixins/lib/_calculate.scss: -------------------------------------------------------------------------------- 1 | //// 2 | /// @group Internal Mixins 3 | //// 4 | 5 | /// 6 | /// Outputs calculated styles 7 | /// 8 | /// @access private 9 | /// 10 | /// @param {Map} $width - map of target / context values 11 | /// @param {Number} $margin-right - right margin value 12 | /// @param {Number} $margin-left - left margin value 13 | /// 14 | @mixin flint-output($width, $margin-right, $margin-left) { 15 | 16 | @if not flint-is-map($width) { 17 | @if not $flint-development-mode { 18 | @error "Passed $width (#{$width}) was not a map; a map containing a target / context combination is required." 19 | } 20 | } 21 | 22 | @if flint-get-value("settings", "grid") == "fluid" { 23 | width: flint-fluid-width(map-get($width, "target"), map-get($width, "context")); 24 | margin-right: if(flint-is-number($margin-right) and $margin-right != 0, flint-fluid-width($margin-right, map-get($width, "context")), $margin-right); 25 | margin-left: if(flint-is-number($margin-left) and $margin-left != 0, flint-fluid-width($margin-left, map-get($width, "context")), $margin-left); 26 | } @else { 27 | width: map-get($width, "target"); 28 | margin-right: $margin-right; 29 | margin-left: $margin-left; 30 | } 31 | 32 | @content; 33 | } 34 | 35 | /// 36 | /// Calculate widths, save all variables to instance 37 | /// 38 | /// @access private 39 | /// 40 | /// @param {String} $calc-key - breakpoint key 41 | /// @param {Number} $calc-span - span value 42 | /// @param {Number} $calc-context - context value 43 | /// @param {String} $calc-gutter - gutter modifier 44 | /// @param {Number|Null} $i - index if variable length is > 1 45 | /// 46 | @mixin flint-calculate($key, $span, $context, $gutter, $i: null) { 47 | 48 | // Define local vars 49 | $calc-key: $key; 50 | $calc-span: $span; 51 | $calc-context: $context; 52 | $calc-gutter: $gutter; 53 | 54 | // Define default values 55 | $output-width-map: null; 56 | $output-margin-right: null; 57 | $output-margin-left: null; 58 | 59 | // Track errors 60 | $errors: false; 61 | 62 | // Default value for cache search result 63 | $cached: false; 64 | 65 | // 66 | // Check lengths, if invalid throw error 67 | // 68 | @if flint-types-in-list($calc-gutter, "string") and length($calc-gutter) != length($flint-all-keys) { 69 | @if not $flint-development-mode { 70 | @error "Invalid argument length of #{length($calc-gutter)} for gutter. If you're using a shorthand, please provide an argument for each breakpoint in your config (#{length($flint-all-keys)}). Your argument was: #{$calc-gutter}"; 71 | } 72 | } 73 | 74 | // 75 | // Check if any arguments are lists if called from loop 76 | // 77 | @if $i { 78 | 79 | @if flint-types-in-list($calc-key, "number") { 80 | $calc-key: nth($calc-key, $i); 81 | } 82 | @if flint-types-in-list($calc-span, "number") { 83 | $calc-span: nth($calc-span, $i); 84 | } 85 | @if flint-types-in-list($calc-context, "number") { 86 | $calc-context: nth($calc-context, $i); 87 | } 88 | @if flint-types-in-list($calc-gutter, "string") { 89 | $calc-gutter: nth($calc-gutter, $i); 90 | } 91 | 92 | } 93 | 94 | // 95 | // Check for cached results 96 | // 97 | @if $calc-context != "auto" and $calc-span != 0 { 98 | @if map-has-key($flint-cached-results, "#{$calc-key, $calc-span, $calc-context, $calc-gutter, $i}") { 99 | $result: map-get($flint-cached-results, "#{$calc-key, $calc-span, $calc-context, $calc-gutter, $i}"); 100 | 101 | // Get results 102 | $output-width-map: nth($result, 1); 103 | $output-margin-right: nth($result, 2); 104 | $output-margin-left: nth($result, 3); 105 | 106 | // Declare successful search 107 | $cached: true; 108 | } 109 | } 110 | 111 | // 112 | // Hide if span is zero 113 | // 114 | @if $calc-span == 0 { 115 | 116 | // First check if it's the default, so we don't hide the element on all breakpoints 117 | @if $calc-key == flint-get-value("settings", "default") { 118 | @include _($calc-key) { 119 | display: none; 120 | } 121 | // If we're hiding the default, but span is a list, define floats for other queries 122 | @if flint-is-list($span) { 123 | float: unquote(flint-get-value("settings", "float-direction")); 124 | } 125 | } @else { 126 | display: none; 127 | } 128 | 129 | @if flint-get-value("settings", "instance-maps") { 130 | @include flint-new-instance($calc-key, $calc-span, $calc-context, $calc-gutter, $output-width-map, $output-margin-right, $output-margin-left); 131 | @include flint-debug-instance($calc-key); 132 | } 133 | 134 | } @else { 135 | 136 | // 137 | // Define floats if key is default, or this is a single instance call 138 | // 139 | @if flint-is-default($calc-key) and $gutter != "center" or $i == null and $gutter != "center" { 140 | float: unquote(flint-get-value("settings", "float-direction")); 141 | } 142 | 143 | // 144 | // Disable floats if gutter is set to center 145 | // 146 | $recursive-center: false; 147 | 148 | @if $gutter == "center" { 149 | $recursive-center: true; 150 | } 151 | 152 | // Check if default and gutter is recursive 153 | @if flint-is-default($calc-key) and $recursive-center { 154 | float: none; 155 | // Check if default and gutter is not recurisve, wrap in query to not affect others 156 | } @else if flint-is-default($calc-key) and $calc-gutter == "center" and not $recursive-center { 157 | @include _($calc-key) { 158 | float: none; 159 | } 160 | // Not default, check if gutter was set to center but not recursive 161 | } @else if $calc-gutter == "center" and not $recursive-center or $i == null and $recursive-center { 162 | float: none; 163 | } 164 | 165 | // 166 | // Only run through if cache search was unsuccessful 167 | // 168 | @if not $cached { 169 | 170 | $output-gutter: flint-get-gutter(); 171 | 172 | @if $calc-gutter == null or $calc-gutter == "normal" or $calc-gutter == "default" or $calc-gutter == "regular" { 173 | 174 | $output-width-map: flint-calc-width($calc-key, $calc-span, if($calc-context, $calc-context, null), ($output-gutter * 2)); 175 | $output-margin-right: $output-gutter; 176 | $output-margin-left: $output-gutter; 177 | 178 | } @else if $calc-gutter == "inside" { 179 | 180 | $output-width-map: flint-calc-width($calc-key, $calc-span, if($calc-context, $calc-context, null), ($output-gutter * 4)); 181 | $output-margin-right: $output-gutter; 182 | $output-margin-left: $output-gutter; 183 | 184 | } @else if $calc-gutter == "alpha" or $calc-gutter == "no-left" or $calc-gutter == "first" { 185 | 186 | $output-width-map: flint-calc-width($calc-key, $calc-span, if($calc-context, $calc-context, null), $output-gutter); 187 | $output-margin-right: $output-gutter; 188 | $output-margin-left: 0; 189 | 190 | } @else if $calc-gutter == "omega" or $calc-gutter == "no-right" or $calc-gutter == "last" { 191 | 192 | $output-width-map: flint-calc-width($calc-key, $calc-span, if($calc-context, $calc-context, null), $output-gutter); 193 | $output-margin-right: 0; 194 | $output-margin-left: $output-gutter; 195 | 196 | } @else if $calc-gutter == "center" { 197 | 198 | $output-width-map: flint-calc-width($calc-key, $calc-span, if($calc-context, $calc-context, null), ($output-gutter * 2)); 199 | $output-margin-right: auto; 200 | $output-margin-left: auto; 201 | 202 | } @else if $calc-gutter == "row" or $calc-gutter == "none" { 203 | 204 | $output-width-map: flint-calc-width($calc-key, $calc-span, if($calc-context, $calc-context, null)); 205 | $output-margin-right: 0; 206 | $output-margin-left: 0; 207 | 208 | } @else { 209 | @if not $flint-development-mode { 210 | @error "Invalid gutter argument: #{$calc-gutter}. Please provide a valid argument."; 211 | } @else { 212 | $errors: true; 213 | } 214 | } 215 | } 216 | 217 | @if not $errors { 218 | 219 | // Cache result 220 | @if $calc-context != "auto" and $calc-span != 0 and not $cached { 221 | $flint-cached-results: map-merge($flint-cached-results, ( 222 | "#{$calc-key, $calc-span, $calc-context, $calc-gutter, $i}": ($output-width-map, $output-margin-right, $output-margin-left) 223 | )) !global; 224 | } 225 | 226 | // Output styles 227 | @include flint-output($output-width-map, $output-margin-right, $output-margin-left) { 228 | @content; 229 | } 230 | 231 | @if flint-get-value("settings", "instance-maps") { 232 | 233 | // Create new instance 234 | @include flint-new-instance($calc-key, $calc-span, $calc-context, $calc-gutter, map-get($output-width-map, "target"), $output-margin-right, $output-margin-left); 235 | 236 | // If debug mode, print instance 237 | @include flint-debug-instance($calc-key); 238 | } 239 | } 240 | } 241 | } 242 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | ### 2.3.7 4 | * Fix issue with Rails integration 5 | 6 | ### 2.3.4, 2.3.6 7 | * Fix compatibility issues with Libsass 8 | * Refactor and get rid of various functions 9 | 10 | ### 2.3.2, 2.3.3 11 | * Fix deprecation warning for multiline strings 12 | 13 | ### 2.3.1 14 | * Fix issue where grid overlay wasn't applied using `@at-root` 15 | 16 | ### 2.3.0 17 | * Add SVG grid overlay to `debug-mode`. 18 | 19 | ### 2.2.0 20 | * Rewrite `exists()` method in Ruby for a huge performance increase. 21 | * Write `Flint::Profiler` to help test future performance bottlenecks. 22 | * Update global variables to follow standard naming conventions. 23 | 24 | ### 2.1.4 25 | * Fix issue with using `unquote()` on non-strings. 26 | 27 | ### 2.1.2, 2.1.3 28 | * Update comments to follow SassDoc standards. 29 | * Small style fixes. 30 | 31 | ### 2.1.1 32 | * Fix issue with unassigned `$output-width` variable when using `$span: 0`. 33 | 34 | ### 2.1.0 35 | * Added support for `rem` values. 36 | * Set up proper submodule for Bootcamp. 37 | 38 | ### 2.0.9 39 | * Fixed issue with `$gutter: center` attempting to divide by `auto`. 40 | * Wrote tests for `$gutter` modifiers. 41 | 42 | ### 2.0.7, 2.0.8 10/17/14 43 | * Changed doc comments from `/* */` comments to `///`. 44 | 45 | ### 2.0.6 10/7/14 46 | * Remove redundant Ruby functions. 47 | * Update docs to include examples that follow SassDoc standards. 48 | 49 | ### 2.0.5 10/4/14 50 | * Update docs 51 | 52 | ### 2.0.4 10/3/14 53 | * Refactored Ruby `lib` for easier upkeep. 54 | * Removed `@content` from doc blocks for now. 55 | * Added `list_to_string()` Ruby function. 56 | * Fixed issue with `support-syntax-bem()` returning oddly quoted strings when using Sass functions. 57 | 58 | ### 2.0.3 10/2/14 59 | * Update documentation to follow SassDoc standards. 60 | 61 | ### 2.0.2 10/1/14 62 | * Reversed order that `map-merge` merges instance maps, so that newer instances are merged to the top rather than the bottom. Increased performance benchmarks by `23%`. 63 | * Added Ruby function for `map-fetch()`. Increased performance benchmarks by `15%`. 64 | * Updated main API mixin `_()` to follow SassDoc standards. 65 | 66 | ### 2.0.1 - 9/25/14 67 | * Updated Sass dependency to `~> 3.4` in gemspec. 68 | * Ignore `test` folder in bower. 69 | 70 | ### 2.0.0 - 9/25/14 71 | * Release `2.0.0`! 72 | 73 | ### 2.0.0.rc.4 - 9/17/14 74 | * Added ability to use na identical `$context` value with a variable `$span`. Example, `_(1 2 3 4, 4)`. 75 | 76 | ### 2.0.0.rc.3 - 9/16/14 77 | * Fixed issue with `$context` modifiers calling a division by 0. 78 | 79 | ### 2.0.0.rc.1 - 9/12/14 80 | * Revamped codebase considerably. 81 | * Modified layout of `$flint` configuration map. Breakpoints are now housed in their own separate section. 82 | * Removed `$shift` modifier. _(Don't like this one? Create an issue and let me know!)_ 83 | * Modified calculations to use fixed values all the way through the system, and then convert to percentages on output. Coupled with instance methods, this makes gutters infinitely nest-able and consistent even on fluid grids. 84 | * Added `instance-maps` option in config to enable or disable instance maps and all of the associated methods. 85 | * Modified docblocks to follow [SassDoc](https://github.com/SassDoc/sassdoc) standards. 86 | * Moved selector functions over to Sass 3.4. _(No more forced Ruby dependency!)_ 87 | * Modified tests; added new HTML test page. 88 | * _Lots of other cleanup and speed improvements._ 89 | 90 | ### 1.12.0 - 8/29/14 91 | * Added test suite and contributing guidelines. 92 | * Cleaned up a few functions. 93 | 94 | ### 1.11.2 - 8/13/14 95 | * Rewrite `flint-map-fetch()` and `flint-exists()` functions. 96 | * Add ability to call `@include _(, container)` for individual breakpoints. 97 | * Add ability to call `@include _(container, clear)` & `@include _(, container, clear)` consecutively. 98 | * Fix breakpoint query math for fixed `em` grids. 99 | 100 | ### 1.10.0 - 8/11/14 101 | * Add `$gutter: center` modifier. 102 | * Fix `SASS_PATH` issue. 103 | 104 | ### 1.9.1 - 8/4/14 105 | * Break Compass dependency. _(Will completely break in `2.0` when dependence on Ruby functions cease)._ 106 | * Add better error handling for invalid arguments. 107 | 108 | ### 1.8.0 - 8/1/14 109 | * Deprecated `$shift` modifier. 110 | * Optimized `for` query to output comma delimited list of queries instead of duplicating styles for each query. 111 | * Optimized `_main.scss`. Significantly cleaned up code by grouping like-calls together into the same conditional. 112 | * Removed prefixes from all properties. 113 | * Created `flint-box-sizing` mixin. Uses `box-sizing` mixin if it exists. 114 | * Removed `only screen` from media queries. 115 | 116 | ### 1.7.2 - 7/14/14 117 | * Removed `string-to-number` functions and all dependencies associated with them. 118 | 119 | ### 1.7.1 - 7/12/14 120 | * Fixed issue with `debug mode` defaulting to true. 121 | 122 | ### 1.7.0 - 7/11/14 123 | * Added Ruby functions to help with performance. 124 | * Added various memoization functions to help with performance. 125 | * Prefixed all functions and mixins with `flint-` to ensure compatibility with other plugins. 126 | * Cleaned up code in `calculate.scss`. 127 | 128 | ### 1.6.5 - 7/08/14 129 | * Fixed issue with `flint-support-syntax-bem` function. 130 | 131 | ### 1.6.4 - 7/08/14 132 | * Remove recursive option from `flint-str-replace` for performance reasons. 133 | 134 | ### 1.6.3 - 7/08/14 135 | * Added string flint-replace function. 136 | * Modified way BEM selectors are parsed with new function. 137 | * Removed `@dependance` declaratons from doc blocks. 138 | 139 | ### 1.6.2 - 7/07/14 140 | * Added warnings for improper arguments for various mixins and functions. 141 | * Slightly changed doc blocks. 142 | 143 | ### 1.6.1 - 7/03/14 144 | * Added functions for syntax-support that are easily extendable 145 | * Added syntax support option in config 146 | * Added offical support for BEM syntax 147 | * Fix minor issue with `$context: auto` conditional in `main.scss` 148 | 149 | ### 1.6.0 - 6/30/14 150 | * Add feature to pass arbitrary values to media query calls. 151 | * Fix issue with max-width conditional. 152 | * Clean up codebase. Add `flint-types-in-list()` function. 153 | 154 | ### 1.5.0 - 6/26/14 155 | * Default config is now in ems instead of pixels. 156 | * Fixed issues with breakpoint calculations when using ems. Should successfully break at the correct points when using alias conditionals and not be `~0.0625em` off. 157 | * Added warn directives when common mistakes occur. 158 | * Cleaned up doc blocks. 159 | 160 | ### 1.4.0 - 6/11/14 161 | * Cleaning house. Cleaned up function definitions and documentation, quoted all strings, and overall just made the code more tidy. 162 | 163 | ### 1.3.4 - 5/20/14 164 | * Fixed issue with `(for x y z)` loop not outputting correct breakpoints due to an invalid if statement. 165 | 166 | ### 1.3.3 - 5/19/14 167 | * Fixed issue with comma seperated parent selectors causing errors and other issues. 168 | * Added small clean up functions for comma seperated selector strings for various functions. 169 | 170 | ### 1.3.2 - 5/16/14 171 | * Added `$context: auto` for fixed grids. It will automatically get the parent instance's width, and calculate on that instead of the base breakpoint. This fixes issues where parents couldn't contain children of the same span, and the further you would nest, the worse the issue would get. 172 | 173 | ### 1.3.1 - 5/14/14 174 | * Fixed issue with `_(greater than y)` not outputting the correct calculations on `fixed` grids 175 | * Issue was that when you used for example: `_(greater than laptop)`, `laptop` would actually be included, instead of ommitted. It now acts as 'anything above laptops breakpoint', the same way `less than y` works. 176 | * Adjusted the way breakpoints are calculated for easier modifications moving forward. 177 | * Optimized `flint-calc-breakpoint()` function 178 | 179 | ### 1.3.0 - 5/09/14 180 | * Added ability to pass an abitrary `$context` while maintaining a consistent gutter 181 | * Small changes to `debug-mode` 182 | * Added parent instance selector to output 183 | * Added actual `$context` in place of `auto` in output 184 | 185 | ### 1.2.2 - 5/02/14 186 | * Adjusted `$length` variable in `flint-str-to-list()` for better performance. 187 | * Added 2 additional aliases for `$gutter` modifiers 188 | * `alpha > first` 189 | * `omega > flint-last` 190 | 191 | ### 1.2.1 - 4/30/14 192 | * Fixed issue with comma separated child selectors throwing an error. `Fixes #5` 193 | 194 | ### 1.2.0 - 4/25/14 195 | * Added aliases for `$gutter` modifiers 196 | * `null > default | regular | normal` 197 | * `alpha > no-left` 198 | * `omega > no-right` 199 | * `row > none` 200 | * Removed option for `gutter: false` in config. Use `0(unit)` from now on. 201 | 202 | ### 1.1.0 - 4/24/14 203 | * Added `$gutter: inside` modifier 204 | * Adjusted `$span: 0` to hide element instead of compiling with no width 205 | * Corrected small issue with `less than x`, `greater than x` on fixed grids 206 | * Cleaned up variable/function names 207 | * Added detailed comments to all mixins/functions 208 | * Built `.gemspec` so that Flint can be installed via `gem install flint-gs` 209 | * Added `bower.json` so that Flint can be installed via Bower 210 | * Organized file structure by splitting functions/mixins into separate files for easier modifications/version control moving forward. 211 | * You can now take advantage of both `$shift` and `$gutter` modifiers together. 212 | 213 | ### 1.0.0 - 4/11/14 214 | * You can now use `$context: auto`, and we'll do all the calculations for you. Just be sure a container element actually exists or you'll get some weird output, or none at all. Pretty cool feature utilizing the new `instance` map, which keeps track of every `instance` of the `_()` mixin, and saves all the tasty variables for use-cases like this. 215 | -------------------------------------------------------------------------------- /tests/input/functions/helpers/_helpers.scss: -------------------------------------------------------------------------------- 1 | // 2 | // Returns truthiness of a value 3 | // 4 | @include describe("[function] is-true") { 5 | 6 | @include it("should expect values to be truthy") { 7 | @include should(expect( 8 | flint-is-true(true)), 9 | to(be(true)) 10 | ); 11 | @include should(expect( 12 | flint-is-true("true")), 13 | to(be(true)) 14 | ); 15 | } 16 | 17 | @include it("should expect values to return false") { 18 | @include should(expect( 19 | flint-is-true(null)), 20 | to(be(false)) 21 | ); 22 | @include should(expect( 23 | flint-is-true(false)), 24 | to(be(false)) 25 | ); 26 | @include should(expect( 27 | flint-is-true(())), 28 | to(be(false)) 29 | ); 30 | @include should(expect( 31 | flint-is-true("")), 32 | to(be(false)) 33 | ); 34 | } 35 | } 36 | 37 | // 38 | // Checks if item is map 39 | // 40 | @include describe("[function] is-map") { 41 | 42 | $map: ("key": "value"); 43 | $list: ("one", "two", "three"); 44 | $string: "string"; 45 | $number: 1; 46 | $bool: true; 47 | $null: null; 48 | 49 | @include it("should expect variable to be a map and return true") { 50 | @include should(expect( 51 | flint-is-map($map)), 52 | to(be(true)) 53 | ); 54 | } 55 | 56 | @include it("should expect variable to be a map and return false") { 57 | @include should(expect( 58 | flint-is-map($list)), 59 | to(be(false)) 60 | ); 61 | @include should(expect( 62 | flint-is-map($string)), 63 | to(be(false)) 64 | ); 65 | @include should(expect( 66 | flint-is-map($number)), 67 | to(be(false)) 68 | ); 69 | @include should(expect( 70 | flint-is-map($bool)), 71 | to(be(false)) 72 | ); 73 | @include should(expect( 74 | flint-is-map($null)), 75 | to(be(false)) 76 | ); 77 | } 78 | } 79 | 80 | // 81 | // Checks if item is list 82 | // 83 | @include describe("[function] is-list") { 84 | 85 | $map: ("key": "value"); 86 | $list: ("one", "two", "three"); 87 | $string: "string"; 88 | $number: 1; 89 | $bool: true; 90 | $null: null; 91 | 92 | @include it("should expect variable to be a list and return true") { 93 | @include should(expect( 94 | flint-is-list($list)), 95 | to(be(true)) 96 | ); 97 | } 98 | 99 | @include it("should expect variable to be a list and return false") { 100 | @include should(expect( 101 | flint-is-list($map)), 102 | to(be(false)) 103 | ); 104 | @include should(expect( 105 | flint-is-list($string)), 106 | to(be(false)) 107 | ); 108 | @include should(expect( 109 | flint-is-list($number)), 110 | to(be(false)) 111 | ); 112 | @include should(expect( 113 | flint-is-list($bool)), 114 | to(be(false)) 115 | ); 116 | @include should(expect( 117 | flint-is-list($null)), 118 | to(be(false)) 119 | ); 120 | } 121 | } 122 | 123 | // 124 | // Checks if item is number 125 | // 126 | @include describe("[function] is-number") { 127 | 128 | $map: ("key": "value"); 129 | $list: ("one", "two", "three"); 130 | $string: "string"; 131 | $number: 1; 132 | $bool: true; 133 | $null: null; 134 | 135 | @include it("should expect variable to be a number and return true") { 136 | @include should(expect( 137 | flint-is-number($number)), 138 | to(be(true)) 139 | ); 140 | } 141 | 142 | @include it("should expect variable to be a number and return false") { 143 | @include should(expect( 144 | flint-is-number($map)), 145 | to(be(false)) 146 | ); 147 | @include should(expect( 148 | flint-is-number($list)), 149 | to(be(false)) 150 | ); 151 | @include should(expect( 152 | flint-is-number($string)), 153 | to(be(false)) 154 | ); 155 | @include should(expect( 156 | flint-is-number($bool)), 157 | to(be(false)) 158 | ); 159 | @include should(expect( 160 | flint-is-number($null)), 161 | to(be(false)) 162 | ); 163 | } 164 | } 165 | 166 | // 167 | // Checks if item is string 168 | // 169 | @include describe("[function] is-string") { 170 | 171 | $map: ("key": "value"); 172 | $list: ("one", "two", "three"); 173 | $string: "string"; 174 | $number: 1; 175 | $bool: true; 176 | $null: null; 177 | 178 | @include it("should expect variable to be a string and return true") { 179 | @include should(expect( 180 | flint-is-string($string)), 181 | to(be(true)) 182 | ); 183 | } 184 | 185 | @include it("should expect variable to be a string and return false") { 186 | @include should(expect( 187 | flint-is-string($map)), 188 | to(be(false)) 189 | ); 190 | @include should(expect( 191 | flint-is-string($list)), 192 | to(be(false)) 193 | ); 194 | @include should(expect( 195 | flint-is-string($number)), 196 | to(be(false)) 197 | ); 198 | @include should(expect( 199 | flint-is-string($bool)), 200 | to(be(false)) 201 | ); 202 | @include should(expect( 203 | flint-is-string($null)), 204 | to(be(false)) 205 | ); 206 | } 207 | } 208 | 209 | // 210 | // Checks if item is not string 211 | // 212 | @include describe("[function] is-not-string") { 213 | 214 | $map: ("key": "value"); 215 | $list: ("one", "two", "three"); 216 | $string: "string"; 217 | $number: 1; 218 | $bool: true; 219 | $null: null; 220 | 221 | @include it("should expect variable not to be a string") { 222 | @include should(expect( 223 | flint-is-not-string($string)), 224 | not-to(be(true)) 225 | ); 226 | @include should(expect( 227 | flint-is-not-string($map)), 228 | to(be(true)) 229 | ); 230 | @include should(expect( 231 | flint-is-not-string($list)), 232 | to(be(true)) 233 | ); 234 | @include should(expect( 235 | flint-is-not-string($number)), 236 | to(be(true)) 237 | ); 238 | @include should(expect( 239 | flint-is-not-string($bool)), 240 | to(be(true)) 241 | ); 242 | @include should(expect( 243 | flint-is-not-string($null)), 244 | to(be(true)) 245 | ); 246 | } 247 | } 248 | 249 | // 250 | // Get gutter value from config map 251 | // 252 | @include describe("[function] get-gutter") { 253 | 254 | @include it("should expect gutter value from config") { 255 | @include should(expect( 256 | flint-get-gutter()), 257 | to(be((0.625em))) 258 | ); 259 | } 260 | } 261 | 262 | // 263 | // Gets list of each breakpoint's key 264 | // 265 | @include describe("[function] get-all-keys") { 266 | 267 | @include it("should expect a list of all breakpoint keys") { 268 | @include should(expect( 269 | flint-get-all-keys()), 270 | to(be(("desktop", "laptop", "tablet", "mobile"))) 271 | ); 272 | } 273 | } 274 | 275 | // 276 | // Gets list of all breakpoints 277 | // 278 | @include describe("[function] get-all-breakpoints") { 279 | 280 | @include it("should expect a list of all breakpoint values") { 281 | @include should(expect( 282 | flint-get-all-breakpoints()), 283 | to(be((80em, 60em, 40em, 20em))) 284 | ); 285 | } 286 | } 287 | 288 | // 289 | // Checks if passed $key is the highest breakpoint 290 | // 291 | @include describe("[function] is-highest-breakpoint") { 292 | 293 | @include it("should expect to be highest breakpoint") { 294 | @include should(expect( 295 | flint-is-highest-breakpoint("desktop")), 296 | to(be(true)) 297 | ); 298 | } 299 | 300 | @include it("should expect not to be highest breakpoint") { 301 | @include should(expect( 302 | flint-is-highest-breakpoint("laptop")), 303 | to(be(false)) 304 | ); 305 | @include should(expect( 306 | flint-is-highest-breakpoint("tablet")), 307 | to(be(false)) 308 | ); 309 | @include should(expect( 310 | flint-is-highest-breakpoint("mobile")), 311 | to(be(false)) 312 | ); 313 | } 314 | } 315 | 316 | // 317 | // Checks if passed $key is the lowest breakpoint 318 | // 319 | @include describe("[function] is-lowest-breakpoint") { 320 | 321 | @include it("should expect to be lowest breakpoint") { 322 | @include should(expect( 323 | flint-is-lowest-breakpoint("mobile")), 324 | to(be(true)) 325 | ); 326 | } 327 | 328 | @include it("should expect not to be lowest breakpoint") { 329 | @include should(expect( 330 | flint-is-lowest-breakpoint("desktop")), 331 | to(be(false)) 332 | ); 333 | @include should(expect( 334 | flint-is-lowest-breakpoint("laptop")), 335 | to(be(false)) 336 | ); 337 | @include should(expect( 338 | flint-is-lowest-breakpoint("tablet")), 339 | to(be(false)) 340 | ); 341 | } 342 | } 343 | 344 | // 345 | // Checks if $key is grid default 346 | // 347 | @include describe("[function] is-default") { 348 | 349 | @include it("should expect to be default breakpoint") { 350 | @include should(expect( 351 | flint-is-default("mobile")), 352 | to(be(true)) 353 | ); 354 | } 355 | 356 | @include it("should expect not to be default breakpoint") { 357 | @include should(expect( 358 | flint-is-default("desktop")), 359 | to(be(false)) 360 | ); 361 | @include should(expect( 362 | flint-is-default("laptop")), 363 | to(be(false)) 364 | ); 365 | @include should(expect( 366 | flint-is-default("tablet")), 367 | to(be(false)) 368 | ); 369 | } 370 | } 371 | 372 | // 373 | // Gets all breakpoint column values 374 | // 375 | @include describe("[function] get-all-columns") { 376 | 377 | @include it("should expect a list of all breakpoint column values") { 378 | @include should(expect( 379 | flint-get-all-columns()), 380 | to(be((16, 12, 8, 4))) 381 | ); 382 | } 383 | } 384 | 385 | // 386 | // Returns the unit used in config 387 | // 388 | @include describe("[function] get-config-unit") { 389 | @include it("should expect configuration unit to be ems") { 390 | @include should(expect( 391 | flint-get-config-unit()), 392 | to(be("em")) 393 | ); 394 | } 395 | } 396 | 397 | // 398 | // Convert pixel value to em 399 | // 400 | @include describe("[function] to-em") { 401 | 402 | @include it("should expect passed pixel value to be converted to ems") { 403 | @include should(expect( 404 | flint-to-em(16px)), 405 | to(be(1em)) 406 | ); 407 | @include should(expect( 408 | flint-to-em(32px)), 409 | to(be(2em)) 410 | ); 411 | @include should(expect( 412 | flint-to-em(16px, 32px)), 413 | to(be(0.5em)) 414 | ); 415 | } 416 | } 417 | 418 | // 419 | // Convert pixel value to rem 420 | // 421 | @include describe("[function] to-rem") { 422 | 423 | @include it("should expect passed pixel value to be converted to rems") { 424 | @include should(expect( 425 | flint-to-rem(16px)), 426 | to(be(1rem)) 427 | ); 428 | @include should(expect( 429 | flint-to-rem(32px)), 430 | to(be(2rem)) 431 | ); 432 | @include should(expect( 433 | flint-to-rem(16px, 32px)), 434 | to(be(0.5rem)) 435 | ); 436 | } 437 | } 438 | -------------------------------------------------------------------------------- /stylesheets/flint/mixins/lib/_main.scss: -------------------------------------------------------------------------------- 1 | /// 2 | /// # Main API 3 | /// 4 | /// ---- 5 | /// 6 | /// ## Shorthand 7 | /// 8 | /// ### Recursive span 9 | /// Use this if you want identical column spans across all breakpoints. This is of course 10 | /// relative to each of your breakpoint's column count, so if your lowest breakpoint has 11 | /// a column count of `4`, then anything above that would likely cause layout issues 12 | /// for that breakpoint. 13 | /// 14 | /// ```scss 15 | /// div { 16 | /// @include _(2); 17 | /// } 18 | /// ``` 19 | /// 20 | /// ### Recursive Span With Identical Context 21 | /// Use this if your nested context is identical across all breakpoints. The `$context` should 22 | /// be the span value of the element's parent, or `auto`. 23 | /// 24 | /// ```scss 25 | /// div { 26 | /// @include _(4, 2); 27 | /// } 28 | /// ``` 29 | /// 30 | /// ### Recursive Span With Differing Context 31 | /// Use this if your nested context is not identical across all breakpoints. The `$context` 32 | /// should be the span value of the element's parent, or `auto`. 33 | /// 34 | /// ```scss 35 | /// div { 36 | /// @include _(4, 8 8 4 4); 37 | /// } 38 | /// ``` 39 | /// 40 | /// ### Variable Span 41 | /// Use this if your content needs different spans across each breakpoint. The order of 42 | /// operations is the order that your breakpoints are listed in your config (DESC). 43 | /// 44 | /// ```scss 45 | /// div { 46 | /// @include _(8 8 4 4); 47 | /// } 48 | /// ``` 49 | /// 50 | /// ### Variable Span With Identical Context 51 | /// Use this if your nested context is identical across all breakpoints. The `$context` 52 | /// should be the span value of the element's parent, or `auto`. 53 | /// 54 | /// ```scss 55 | /// div { 56 | /// @include _(4 4 2 2, 4); 57 | /// } 58 | /// ``` 59 | /// 60 | /// ### Variable Span With Differing Context 61 | /// Use this if your nested context is not identical across all breakpoints. The `$context` 62 | /// should be the span value of the element's parent, or `auto`. 63 | /// 64 | /// ```scss 65 | /// div { 66 | /// @include _(8 8 4 4, 8 8 4 4); 67 | /// } 68 | /// ``` 69 | /// 70 | /// ---- 71 | /// 72 | /// ## Longhand 73 | /// 74 | /// ### Span 75 | /// Use if you want to define each span by breakpoint `$alias`. 76 | /// 77 | /// ```scss 78 | /// div { 79 | /// @include _(desktop, 2); 80 | /// } 81 | /// ``` 82 | /// 83 | /// ### Span With Context 84 | /// Use if you want to define each span by breakpoint `$alias`. The `$context` should be the span 85 | /// value of the element's parent, or `auto`. 86 | /// 87 | /// ```scss 88 | /// div { 89 | /// @include _(desktop, 4, 2); 90 | /// } 91 | /// ``` 92 | /// 93 | /// ---- 94 | /// 95 | /// ## Automatic Context 96 | /// 97 | /// You can use `$context: auto`, and Flint will calculate based on the closest parent element's 98 | /// width instead of the current breakpoint. When using `auto`, Flint falls back from the topmost 99 | /// selector until one is found that has an instance, and it will calculate its span based on that 100 | /// instance's width for the current breakpoint. Think of the `auto` option as a self-correcting grid. 101 | /// 102 | /// When utilizing the `$context` argument, be sure to note the differences in the way the calculations 103 | /// happen depending on if you use a numerical value or `auto`. When using a numerical value, the span 104 | /// is calculated against the current breakpoint's value (example: `80em`), then it's divided by its column 105 | /// count (example: `16`), and then finally, it's multiplied by the passed `$context` value. When using 106 | /// `auto`, the span is _always_ calculated against the closest parent element's width instead 107 | /// of the current breakpoint's width. 108 | /// 109 | /// The difference in output varies, but your gutters will be more accurate across the board if you 110 | /// consistently use the `auto` option. This option allows you to infinitely nest elements on both fixed 111 | /// and fluid grids without dealing with the inconsistencies that can be caused by nesting elements that 112 | /// all use a gutter value of their own. Because the parent element's actual width is always used, the 113 | /// gutters never become out of sync. 114 | /// 115 | /// ```scss 116 | /// .parent { 117 | /// @include _(4); 118 | /// .child { 119 | /// @include _(3, 4); 120 | /// } 121 | /// } 122 | /// 123 | /// // Auto will work 124 | /// .parent { 125 | /// @include _(4); 126 | /// .child { 127 | /// @include _(3, auto); 128 | /// } 129 | /// } 130 | /// 131 | /// // Will also work 132 | /// .parent { 133 | /// @include _(4); 134 | /// } 135 | /// .parent .child { 136 | /// @include _(3, auto); 137 | /// } 138 | /// 139 | /// // Will not work, as the child has no relation to 140 | /// // the parent within the stylesheet 141 | /// .parent { 142 | /// @include _(6); 143 | /// } 144 | /// .child { 145 | /// @include _(3, auto); 146 | /// } 147 | /// ``` 148 | /// 149 | /// If you attempt to use this feature with a methodology like BEM, where selectors aren't neccassarily 150 | /// lists, but instead single strings, you'll notice that Flint can't find return a valid parent for the 151 | /// element. This is the reason for the `support-syntax` functionality. With it, Flint is able to parse 152 | /// selectors that are a single string, as opposed to a list, and successfully search for the passed 153 | /// selector's parent. 154 | /// 155 | /// ---- 156 | /// 157 | /// ## Modifiers 158 | /// 159 | /// ### Alpha 160 | /// Remove the left `$gutter` from the span. Other aliases for `alpha` include: `no-left` and `first`. 161 | /// 162 | /// ```scss 163 | /// div { 164 | /// @include _(12 8 6 4, $gutter: alpha); 165 | /// } 166 | /// ``` 167 | /// 168 | /// ### Omega 169 | /// Remove the right `$gutter` from the span. Other aliases for `omega` include: `no-right` and `last`. 170 | /// 171 | /// ```scss 172 | /// div { 173 | /// @include _(2, $gutter: omega); 174 | /// } 175 | /// ```` 176 | /// 177 | /// ### Row 178 | /// Remove both of the `$gutter` values from the span. Other aliases for `row` include: `none`. 179 | /// 180 | /// ```scss 181 | /// div { 182 | /// @include _(4, $gutter: row); 183 | /// } 184 | /// ``` 185 | /// 186 | /// ### Center 187 | /// Center the current span within it's container element. Outputs auto left and right margins. 188 | /// This modifier will also remove any float properties on the element. 189 | /// 190 | /// ```scss 191 | /// div { 192 | /// @include _(4, $gutter: center); 193 | /// } 194 | /// ``` 195 | /// 196 | /// ### Inside 197 | /// Sets both `$gutter` values on the inside of the element. Instead of deducting `$gutter*2` out 198 | /// of the final width, it will deduct `$gutter*4`. Useful for nesting elements inside of other 199 | /// elements without using `$context: auto`. 200 | /// 201 | /// ```scss 202 | /// div { 203 | /// @include _(16 12 8 4, $gutter: inside); 204 | /// } 205 | /// ``` 206 | /// 207 | /// ### Default 208 | /// Argument to use the default left/right `$gutter` values. Useful for when you want to use a 209 | /// variable `$gutter` argument. Other aliases for `default` include: `normal` and `regular`. 210 | /// 211 | /// ```scss 212 | /// div { 213 | /// @include _(4, $gutter: default); 214 | /// } 215 | /// ``` 216 | /// 217 | /// ### Variable Modifiers 218 | /// Instead of passing in a recursive `$gutter` value, you may specify a value for each breakpoint exactly 219 | /// like you would a `$span` argument. 220 | /// 221 | /// ```scss 222 | /// div { 223 | /// @include _(10 8 6 4, $gutter: alpha omega omega default); 224 | /// } 225 | /// ``` 226 | /// 227 | /// ---- 228 | /// 229 | /// ## Queries 230 | /// 231 | /// ### By Alias 232 | /// Use this type of query to wrap the `@content` in a single query for the specified breakpoint. 233 | /// 234 | /// ```scss 235 | /// div { 236 | /// @include _(desktop) { 237 | /// property: value; 238 | /// } 239 | /// } 240 | /// ``` 241 | /// 242 | /// ### From, To 243 | /// Use this type of query to wrap the `@content` in a single query between 2 breakpoints. Make 244 | /// sure to pass in the breakpoints from lowest to highest. 245 | /// 246 | /// ```scss 247 | /// div { 248 | /// @include _(from tablet to laptop) { 249 | /// property: value; 250 | /// } 251 | /// } 252 | /// ``` 253 | /// 254 | /// ### Greater Than 255 | /// Use this type of query to wrap the `@content` in a single query for anything above 256 | /// the passed breakpoint. 257 | /// 258 | /// ```scss 259 | /// div { 260 | /// @include _(greater than laptop) { 261 | /// property: value; 262 | /// } 263 | /// @include _(5em greater than tablet) { 264 | /// property: value; 265 | /// } 266 | /// @include _(greater than 55em) { 267 | /// property: value; 268 | /// } 269 | /// } 270 | /// ``` 271 | /// 272 | /// ### Less Than 273 | /// Use this type of query to wrap the `@content` in a single query for anything below 274 | /// the passed breakpoint. 275 | /// 276 | /// ```scss 277 | /// div { 278 | /// @include _(less than laptop) { 279 | /// property: value; 280 | /// } 281 | /// @include _(5em less than tablet) { 282 | /// property: value; 283 | /// } 284 | /// @include _(less than 8em) { 285 | /// property: value; 286 | /// } 287 | /// } 288 | /// ``` 289 | /// 290 | /// ### For 291 | /// Use this type of query to wrap the `@content` in a single comma delimited query 292 | /// for each passed `$alias`. 293 | /// 294 | /// ```scss 295 | /// div { 296 | /// @include _(for mobile tablet desktop) { 297 | /// property: value; 298 | /// } 299 | /// } 300 | /// ``` 301 | /// 302 | /// ---- 303 | /// 304 | /// ## Miscellaneous 305 | /// 306 | /// ### Clearfix 307 | /// Given that Flint is float based, you might find yourself needing to use a clearfix. Flint comes 308 | /// packaged with a micro-clearfix function. _Flint will attempt to use a local mixin named 309 | /// `clearfix`. If one is not found, it will use it's own._ 310 | /// 311 | /// ```scss 312 | /// div { 313 | /// @include _(clear); 314 | /// } 315 | /// ``` 316 | /// 317 | /// ### Foundation 318 | /// A foundation instance will output a global box-sizing: border-box declaration. If you selected 319 | /// `"border-box-sizing": true`, then it is advised to create a global foundation instance. If you 320 | /// don't, Flint will automatically apply a foundation instance with your first span declaration. 321 | /// This should be placed at the root of your stylesheet. _Flint will attempt to use a local 322 | /// mixin named `box-sizing`. If one is not found, it will use it's own._ 323 | /// 324 | /// ```scss 325 | /// @include _(foundation); 326 | /// ``` 327 | /// 328 | /// ### Container 329 | /// Containers act as a containing row for each individual breakpoint. It uses the `"max-width"` 330 | /// setting, if set. They do not float, so if you have `"center-container"` set, then it 331 | /// will also center your element using auto left and right margins. You may combine 332 | /// container and clear declarations, with arguments separated by a comma. 333 | /// 334 | /// ```scss 335 | /// div { 336 | /// @include _(container); 337 | /// } 338 | /// ``` 339 | /// 340 | /// ---- 341 | /// 342 | /// @access public 343 | /// 344 | /// @param {String|Number|List} $key [null] - key of breakpoint, or shorthand span 345 | /// @param {String|Number|List} $span [null] - value of span for column, or shorthand context 346 | /// @param {String|Number} $context [null] - context value of span, or null for shorthand 347 | /// @param {String|List} $gutter [null] - alias for gutter modifier 348 | /// 349 | /// @throws - Error if list lengths do not match number of breakpoints (when using variable shorthands). 350 | /// 351 | /// ---- 352 | /// 353 | /// @example scss - Recursive shorthand with no context 354 | /// _(2) 355 | /// 356 | /// @example scss - Recursive shorthand with identical context 357 | /// _(2, 4) 358 | /// 359 | /// @example scss - Recursive shorthand with differing context 360 | /// _(1, 2 4 6 8) 361 | /// _(1, auto) 362 | /// 363 | /// @example scss - Variable shorthand with no context 364 | /// _(1 2 3 4) 365 | /// 366 | /// @example scss - Variable shorthand with identical context 367 | /// _(1 2 3 4, 4) 368 | /// _(1 2 3 4, auto) 369 | /// 370 | /// @example scss - Variable shorthand with differing context 371 | /// _(4 3 2 1, 8 6 4 2) 372 | /// _(4 3 2 1, auto) 373 | /// 374 | /// @example scss - Call by alias with no context 375 | /// _(desktop, 2) 376 | /// 377 | /// @example scss - Call by alias with context 378 | /// _(desktop, 2, 4) 379 | /// _(desktop, 2, auto) 380 | /// 381 | /// @example scss - Call $key breakpoint by alias 382 | /// _(desktop) { ... } 383 | /// 384 | /// @example scss - From $key breakpoint to infinity 385 | /// _(from laptop to infinity) { ... } 386 | /// 387 | /// @example scss - From $key-x breakpoint to $key-y breakpoint 388 | /// _(from tablet to laptop) { ... } 389 | /// 390 | /// @example scss - From $num-x to $num-y 391 | /// _(from 20em to laptop) { ... } 392 | /// 393 | /// @example scss - Greater than $key breakpoint 394 | /// _(greater than tablet) { ... } 395 | /// 396 | /// @example scss - Greater than number 397 | /// _(greater than 15em) { ... } 398 | /// 399 | /// @example scss - Number greater than $key breakpoint 400 | /// _(5em greater than mobile) { ... } 401 | /// 402 | /// @example scss - Less than $key breakpoint 403 | /// _(less than laptop) { ... } 404 | /// 405 | /// @example scss - Less than number 406 | /// _(less than 35em) { ... } 407 | /// 408 | /// @example scss - Number less than $key breakpoint 409 | /// _(10em less than laptop) { ... } 410 | /// 411 | /// @example scss - For $key-x $key-y $key-z... 412 | /// _(for mobile tablet desktop) { ... } 413 | /// 414 | /// @example scss - Clear 415 | /// _(clear) 416 | /// 417 | /// @example scss - Foundation 418 | /// _(foundation) 419 | /// 420 | /// @example scss - Container 421 | /// _(container) 422 | /// 423 | /// ---- 424 | /// 425 | /// @author Ezekiel Gabrielse 426 | /// @link http://flint.gs 427 | /// 428 | /// @group Public API 429 | /// 430 | @mixin _( 431 | $key: null, 432 | $span: null, 433 | $context: null, 434 | $gutter: null 435 | ) { 436 | 437 | // 438 | // Get unit to modify queries with 439 | // 440 | $unit: null; 441 | 442 | @if flint-get-config-unit() == "rem" { 443 | $unit: flint-to-rem(1px); 444 | } @else if flint-get-config-unit() == "em" { 445 | $unit: flint-to-em(1px); 446 | } @else { 447 | $unit: 1; 448 | } 449 | 450 | // 451 | // Clearfix 452 | // 453 | @if $key == "clear" or $span == "clear" or $context == "clear" { 454 | 455 | // 456 | // Check if key exists as breakpoint, and if so wrap 457 | // in query to not affect other breakpoints 458 | // 459 | @if map-has-key(map-get($flint, "breakpoints"), $key) { 460 | 461 | @if flint-get-value("settings", "grid") == "fluid" { 462 | @if flint-is-highest-breakpoint($key) { 463 | @media ( min-width: (flint-calc-breakpoint("next", $key, flint-get-index($key)) + $unit) ) { 464 | @include flint-clearfix; 465 | @content; 466 | } 467 | } @else { 468 | @media ( min-width: (flint-calc-breakpoint("next", $key, flint-get-index($key)) + if(flint-is-lowest-breakpoint($key), 0, $unit)) ) and ( max-width: flint-calc-breakpoint("alias", $key, flint-get-index($key)) ) { 469 | @include flint-clearfix; 470 | @content; 471 | } 472 | } 473 | } @else if flint-get-value("settings", "grid") == "fixed" { 474 | @if flint-is-highest-breakpoint($key) { 475 | @media ( min-width: flint-calc-breakpoint("alias", $key, flint-get-index($key)) ) { 476 | @include flint-clearfix; 477 | @content; 478 | } 479 | } @else { 480 | @media ( min-width: flint-calc-breakpoint("alias", $key, flint-get-index($key)) ) and ( max-width: (flint-calc-breakpoint("prev", $key, flint-get-index($key)) - $unit) ) { 481 | @include flint-clearfix; 482 | @content; 483 | } 484 | } 485 | } 486 | 487 | } @else { 488 | 489 | @include flint-clearfix; 490 | @content; 491 | 492 | } 493 | } 494 | 495 | // 496 | // Apply grid overlay if debug mode is enabled 497 | // 498 | @if not $flint-overlay and flint-get-value("settings", "debug-mode") { 499 | $flint-overlay: true !global; 500 | @include flint-overlay-grid; 501 | } 502 | 503 | // 504 | // Foundation 505 | // 506 | @if $key == "foundation" { 507 | 508 | // Apply global border-box-sizing if set to true 509 | @if flint-get-value("settings", "border-box-sizing") { 510 | $flint-foundation: true !global; 511 | } 512 | 513 | // Foundation is now globally existant 514 | @if $flint-foundation { 515 | @at-root *, *:before, *:after { 516 | @include flint-box-sizing; 517 | @content; 518 | } 519 | } 520 | 521 | // 522 | // Container 523 | // 524 | } @else if $key == "container" or $span == "container" or $context == "container" { 525 | 526 | // Apply individually if foundation is not set globally, but is set to true in config 527 | @if flint-get-value("settings", "border-box-sizing") and not $flint-foundation { 528 | @include _("foundation"); 529 | } 530 | 531 | // Output container for each breakpoint if fixed grid 532 | @if $key == "container" and flint-get-value("settings", "grid") == "fixed" { 533 | 534 | @for $i from 1 through length($flint-all-keys) { 535 | 536 | // Set up variables 537 | $calc-key: flint-steal-key($i); 538 | 539 | // Key is default, no media queries 540 | @if flint-is-default($calc-key) { 541 | 542 | @include flint-container($calc-key, $i) { 543 | @content; 544 | } 545 | 546 | // Not default, wrap in media queries 547 | } @else { 548 | 549 | // Highest breakpoint? No max-width 550 | @if flint-is-highest-breakpoint($calc-key) { 551 | 552 | @media ( min-width: flint-calc-breakpoint("alias", $calc-key, $i) ) { 553 | @include flint-container($calc-key, $i) { 554 | @content; 555 | } 556 | } 557 | 558 | } @else { 559 | 560 | @media ( min-width: flint-calc-breakpoint("alias", $calc-key, $i) ) and ( max-width: (flint-calc-breakpoint("prev", $calc-key, $i) - $unit) ) { 561 | @include flint-container($calc-key, $i) { 562 | @content; 563 | } 564 | } 565 | 566 | } 567 | } 568 | } 569 | 570 | // Output container for specific breakpoint if exists 571 | } @else if map-has-key(map-get($flint, "breakpoints"), $key) and flint-get-value("settings", "grid") == "fixed" { 572 | 573 | @if flint-is-highest-breakpoint($key) { 574 | 575 | @media ( min-width: flint-calc-breakpoint("alias", $key, flint-get-index($key)) ) { 576 | @include flint-container($key) { 577 | @content; 578 | } 579 | } 580 | 581 | } @else { 582 | 583 | @media ( min-width: flint-calc-breakpoint("alias", $key, flint-get-index($key)) ) and ( max-width: (flint-calc-breakpoint("prev", $key, flint-get-index($key)) - $unit) ) { 584 | @include flint-container($key) { 585 | @content; 586 | } 587 | } 588 | 589 | } 590 | } @else if map-has-key(map-get($flint, "breakpoints"), $key) and flint-get-value("settings", "grid") == "fluid" { 591 | @if flint-is-highest-breakpoint($key) { 592 | 593 | @media ( min-width: (flint-calc-breakpoint("next", $key, flint-get-index($key)) + $unit) ) { 594 | @include flint-container { 595 | @content; 596 | } 597 | } 598 | 599 | } @else { 600 | 601 | @media ( min-width: (flint-calc-breakpoint("next", $key, flint-get-index($key)) + if(flint-is-lowest-breakpoint($key), 0, $unit)) ) and ( max-width: flint-calc-breakpoint("alias", $key, flint-get-index($key)) ) { 602 | @include flint-container { 603 | @content; 604 | } 605 | } 606 | 607 | } 608 | } @else { 609 | @include flint-container { 610 | @content; 611 | } 612 | } 613 | 614 | // 615 | // Create a new instance, add to global instance map 616 | // 617 | } @else { 618 | 619 | // Apply individually if foundation is not set globally, but is set to true in config 620 | @if flint-get-value("settings", "border-box-sizing") and not $flint-foundation { 621 | @include _("foundation"); 622 | } 623 | 624 | // 625 | // Recursive shorthand with no context 626 | // 627 | @if flint-is-number($key) and length($key) == 1 and $span == null 628 | 629 | // 630 | // Recursive shorthand with identical context 631 | // 632 | or flint-is-number($key) and length($key) == 1 and flint-is-number($span) and length($span) == 1 633 | or flint-is-number($key) and length($key) == 1 and $span == "auto" 634 | 635 | // 636 | // Recursive shorthand with differing context 637 | // 638 | or flint-is-number($key) and length($key) == 1 and flint-types-in-list($span, "number") 639 | or flint-is-number($key) and length($key) == 1 and $span == "auto" 640 | 641 | // 642 | // Variable shorthand with no context 643 | // 644 | or flint-types-in-list($key, "number") and $span == null 645 | 646 | // 647 | // Variable shorthand with identical context 648 | // 649 | or flint-types-in-list($key, "number") and flint-is-number($span) and length($span) == 1 650 | or flint-types-in-list($key, "number") and $span == "auto" 651 | 652 | // 653 | // Variable shorthand with differing context 654 | // 655 | or flint-types-in-list($key, "number") and flint-types-in-list($span, "number") 656 | or flint-types-in-list($key, "number") and $span == "auto" { 657 | 658 | // Emit erroring for invalid argument lengths 659 | @if flint-types-in-list($key, "number") and length($key) != length($flint-all-keys) { 660 | @if not $flint-development-mode { 661 | @error "Invalid argument length of #{length($key)} for span. Please provide an argument for each breakpoint in your config (#{length($flint-all-keys)}). Your argument was: #{$key}"; 662 | } 663 | } @else if flint-types-in-list($span, "number") and length($span) != length($flint-all-keys) { 664 | @if not $flint-development-mode { 665 | @error "Invalid argument length of #{length($span)} for context. Please provide an argument for each breakpoint in your config (#{length($flint-all-keys)}). Your argument was: #{$span}"; 666 | } 667 | } @else { 668 | 669 | @for $i from 1 through length($flint-all-keys) { 670 | 671 | $calc-key: flint-steal-key($i); 672 | $calc-span: $key; 673 | $calc-context: $span; 674 | $calc-gutter: $gutter; 675 | 676 | @if flint-is-default($calc-key) { 677 | 678 | @include flint-calculate($calc-key, $calc-span, $calc-context, $calc-gutter, $i) { 679 | @content; 680 | } 681 | 682 | } @else { 683 | 684 | @if flint-get-value("settings", "grid") == "fluid" { 685 | 686 | @if flint-is-highest-breakpoint($calc-key) { 687 | 688 | @media ( min-width: (flint-calc-breakpoint("next", $calc-key, $i) + $unit) ) { 689 | @include flint-calculate($calc-key, $calc-span, $calc-context, $calc-gutter, $i) { 690 | @content; 691 | } 692 | } 693 | 694 | } @else { 695 | 696 | @media ( min-width: (flint-calc-breakpoint("next", $calc-key, $i) + if(flint-is-lowest-breakpoint($calc-key), 0, $unit)) ) and ( max-width: flint-calc-breakpoint("alias", $calc-key, $i) ) { 697 | @include flint-calculate($calc-key, $calc-span, $calc-context, $calc-gutter, $i) { 698 | @content; 699 | } 700 | } 701 | 702 | } 703 | 704 | } @else if flint-get-value("settings", "grid") == "fixed" { 705 | 706 | @if flint-is-highest-breakpoint($calc-key) { 707 | 708 | @media ( min-width: flint-calc-breakpoint("alias", $calc-key, $i) ) { 709 | @include flint-calculate($calc-key, $calc-span, $calc-context, $calc-gutter, $i) { 710 | @content; 711 | } 712 | } 713 | 714 | } @else { 715 | 716 | @media ( min-width: flint-calc-breakpoint("alias", $calc-key, $i) ) and ( max-width: (flint-calc-breakpoint("prev", $calc-key, $i) - $unit) ) { 717 | @include flint-calculate($calc-key, $calc-span, $calc-context, $calc-gutter, $i) { 718 | @content; 719 | } 720 | } 721 | 722 | } 723 | 724 | } @else { 725 | @if not $flint-development-mode { 726 | @error "Invalid gutter settings in config map: #{flint-get-value('settings', 'grid')}. Valid arguments: fluid, fixed"; 727 | } 728 | } 729 | } 730 | } 731 | } 732 | 733 | // 734 | // Call by alias with no context 735 | // 736 | } @else if flint-is-string($key) and flint-is-number($span) and $context == null 737 | 738 | // 739 | // Call by alias with context 740 | // 741 | or flint-is-string($key) and flint-is-number($span) and flint-is-number($context) 742 | or flint-is-string($key) and flint-is-number($span) and $context == "auto" { 743 | 744 | // Throw error for invalid argument lengths 745 | @if not map-has-key(map-get($flint, "breakpoints"), $key) { 746 | @if not $flint-development-mode { 747 | @error "Invalid argument: #{$key}. Breakpoint does not exist. Please provide a valid argument."; 748 | } 749 | } @else { 750 | 751 | $calc-key: $key; 752 | $calc-span: $span; 753 | $calc-context: $context; 754 | $calc-gutter: $gutter; 755 | 756 | @if flint-is-default($calc-key) { 757 | 758 | @include flint-calculate ($calc-key, $calc-span, $calc-context, $calc-gutter) { 759 | @content; 760 | } 761 | 762 | } @else { 763 | 764 | @if flint-get-value("settings", "grid") == "fluid" { 765 | 766 | @if flint-is-highest-breakpoint($calc-key) { 767 | 768 | @media ( min-width: (flint-calc-breakpoint("next", $calc-key, flint-get-index($calc-key)) + $unit) ) { 769 | @include flint-calculate($calc-key, $calc-span, $calc-context, $calc-gutter) { 770 | @content; 771 | } 772 | } 773 | 774 | } @else { 775 | 776 | @media ( min-width: (flint-calc-breakpoint("next", $calc-key, flint-get-index($calc-key)) + if(flint-is-lowest-breakpoint($calc-key), 0, $unit)) ) and ( max-width: flint-calc-breakpoint("alias", $calc-key, flint-get-index($calc-key)) ) { 777 | @include flint-calculate($calc-key, $calc-span, $calc-context, $calc-gutter) { 778 | @content; 779 | } 780 | } 781 | 782 | } 783 | 784 | } @else if flint-get-value("settings", "grid") == "fixed" { 785 | 786 | @if flint-is-highest-breakpoint($calc-key) { 787 | 788 | @media ( min-width: flint-calc-breakpoint("alias", $calc-key, flint-get-index($calc-key)) ) { 789 | @include flint-calculate($calc-key, $calc-span, $calc-context, $calc-gutter) { 790 | @content; 791 | } 792 | } 793 | 794 | } @else { 795 | 796 | @media ( min-width: flint-calc-breakpoint("alias", $calc-key, flint-get-index($calc-key)) ) and ( max-width: (flint-calc-breakpoint("prev", $calc-key, flint-get-index($calc-key)) - $unit) ) { 797 | @include flint-calculate($calc-key, $calc-span, $calc-context, $calc-gutter) { 798 | @content; 799 | } 800 | } 801 | 802 | } 803 | 804 | } @else { 805 | @if not $flint-development-mode { 806 | @error "Invalid gutter settings in config map: #{flint-get-value('settings', 'grid')}. Valid arguments: fluid, fixed"; 807 | } 808 | } 809 | } 810 | } 811 | 812 | // 813 | // Wrap content in media query 814 | // 815 | } @else if map-has-key(map-get($flint, "breakpoints"), $key) and $span == null and $context == null 816 | or flint-is-list($key) and $span == null and $context == null { 817 | 818 | // 819 | // Call $key breakpoint by alias 820 | // 821 | @if length($key) == 1 { 822 | 823 | @if flint-get-value("settings", "grid") == "fluid" { 824 | @if flint-is-highest-breakpoint($key) { 825 | @media ( min-width: (flint-calc-breakpoint("next", $key, flint-get-index($key)) + $unit) ) { 826 | @content; 827 | } 828 | } @else { 829 | @media ( min-width: (flint-calc-breakpoint("next", $key, flint-get-index($key)) + if(flint-is-lowest-breakpoint($key), 0, $unit)) ) and ( max-width: flint-calc-breakpoint("alias", $key, flint-get-index($key)) ) { 830 | @content; 831 | } 832 | } 833 | } @else if flint-get-value("settings", "grid") == "fixed" { 834 | @if flint-is-highest-breakpoint($key) { 835 | @media ( min-width: flint-calc-breakpoint("alias", $key, flint-get-index($key)) ) { 836 | @content; 837 | } 838 | } @else { 839 | @media ( min-width: flint-calc-breakpoint("alias", $key, flint-get-index($key)) ) and ( max-width: (flint-calc-breakpoint("prev", $key, flint-get-index($key)) - $unit) ) { 840 | @content; 841 | } 842 | } 843 | } @else { 844 | @if not $flint-development-mode { 845 | @error "Invalid gutter settings in config map: #{flint-get-value('settings', 'grid')}. Valid arguments: fluid, fixed"; 846 | } 847 | } 848 | 849 | // 850 | // From $key breakpoint to infinity 851 | // 852 | } @else if flint-types-in-list($key, "string", 4) and nth($key, 1) == "from" and nth($key, 3) == "to" and nth($key, 4) == "infinity" { 853 | 854 | @if flint-get-value("settings", "grid") == "fluid" { 855 | @media ( min-width: (flint-calc-breakpoint("next", nth($key, 2), flint-get-index(nth($key, 2))) + if(flint-is-lowest-breakpoint(nth($key, 2)), 0, $unit)) ) { 856 | @content; 857 | } 858 | } @else if flint-get-value("settings", "grid") == "fixed" { 859 | @media ( min-width: flint-calc-breakpoint("alias", nth($key, 2), flint-get-index(nth($key, 2))) ) { 860 | @content; 861 | } 862 | } @else { 863 | @if not $flint-development-mode { 864 | @error "Invalid gutter settings in config map: #{flint-get-value('settings', 'grid')}. Valid arguments: fluid, fixed"; 865 | } 866 | } 867 | 868 | // 869 | // From $key-x breakpoint to $key-y breakpoint 870 | // 871 | } @else if flint-types-in-list($key, "string", 4) and nth($key, 1) == "from" and nth($key, 3) == "to" { 872 | 873 | @if flint-get-value("settings", "grid") == "fluid" { 874 | @media ( min-width: (flint-calc-breakpoint("next", nth($key, 2), flint-get-index(nth($key, 2))) + if(flint-is-lowest-breakpoint(nth($key, 2)), 0, $unit)) ) and ( max-width: flint-calc-breakpoint("alias", nth($key, 4), flint-get-index(nth($key, 4))) ) { 875 | @content; 876 | } 877 | } @else if flint-get-value("settings", "grid") == "fixed" { 878 | @media ( min-width: flint-calc-breakpoint("alias", nth($key, 2), flint-get-index(nth($key, 2))) ) and ( max-width: (flint-calc-breakpoint("prev", nth($key, 4), flint-get-index(nth($key, 4))) - if(flint-is-highest-breakpoint(nth($key, 4)), 0, $unit)) ) { 879 | @content; 880 | } 881 | } @else { 882 | @if not $flint-development-mode { 883 | @error "Invalid gutter settings in config map: #{flint-get-value('settings', 'grid')}. Valid arguments: fluid, fixed"; 884 | } 885 | } 886 | 887 | // 888 | // From $num-x to $num-y 889 | // 890 | } @else if flint-types-in-list($key, "string" "number" "string" "number", 4) and nth($key, 1) == "from" and nth($key, 3) == "to" { 891 | // Make sure passed units match units used in config 892 | @if flint-get-config-unit() == unit(nth($key, 2)) and flint-get-config-unit() == unit(nth($key, 4)) { 893 | @media ( min-width: nth($key, 2) ) and ( max-width: nth($key, 4) ) { 894 | @content; 895 | } 896 | // Throw error 897 | } @else { 898 | @if not $flint-development-mode { 899 | @error "Passed units [#{unit(nth($key, 2))}, #{unit(nth($key, 4))}] do not match the unit used in your config map: #{flint-get-config-unit()}"; 900 | } 901 | } 902 | 903 | // 904 | // Greater than $key breakpoint 905 | // 906 | } @else if flint-types-in-list($key, "string", 3) and nth($key, 1) == "greater" and nth($key, 2) == "than" { 907 | 908 | @if flint-get-value("settings", "grid") == "fluid" { 909 | @media ( min-width: (flint-calc-breakpoint("alias", nth($key, 3), flint-get-index(nth($key, 3))) + $unit) ) { 910 | @content; 911 | } 912 | } @else if flint-get-value("settings", "grid") == "fixed" { 913 | @media ( min-width: flint-calc-breakpoint("prev", nth($key, 3), flint-get-index(nth($key, 3))) ) { 914 | @content; 915 | } 916 | } @else { 917 | @if not $flint-development-mode { 918 | @error "Invalid gutter settings in config map: #{flint-get-value('settings', 'grid')}. Valid arguments: fluid, fixed"; 919 | } 920 | } 921 | 922 | // 923 | // Greater than number 924 | // 925 | } @else if flint-types-in-list($key, "string" "string" "number", 3) and nth($key, 1) == "greater" and nth($key, 2) == "than" { 926 | 927 | @if flint-get-config-unit() == unit(nth($key, 3)) { 928 | @media ( min-width: nth($key, 3) + $unit ) { 929 | @content; 930 | } 931 | } @else { 932 | @if not $flint-development-mode { 933 | @error "Passed units [#{unit(nth($key, 3))}] do not match the unit used in your config map: #{flint-get-config-unit()}"; 934 | } 935 | } 936 | 937 | // 938 | // Number greater than $key breakpoint 939 | // 940 | } @else if flint-types-in-list($key, "number" "string" "string" "string", 4) and nth($key, 2) == "greater" and nth($key, 3) == "than" { 941 | 942 | @if flint-get-config-unit() == unit(nth($key, 1)) { 943 | @media ( min-width: (flint-calc-breakpoint("alias", nth($key, 4), flint-get-index(nth($key, 4))) + nth($key, 1)) ) { 944 | @content; 945 | } 946 | } @else { 947 | @if not $flint-development-mode { 948 | @error "Passed units [#{unit(nth($key, 1))}] do not match the unit used in your config map: #{flint-get-config-unit()}"; 949 | } 950 | } 951 | 952 | // 953 | // Less than $key breakpoint 954 | // 955 | } @else if flint-types-in-list($key, "string", 3) and nth($key, 1) == "less" and nth($key, 2) == "than" { 956 | 957 | @if flint-get-value("settings", "grid") == "fluid" { 958 | @media ( max-width: flint-calc-breakpoint("next", nth($key, 3), flint-get-index(nth($key, 3))) ) { 959 | @content; 960 | } 961 | } @else if flint-get-value("settings", "grid") == "fixed" { 962 | @media ( max-width: (flint-calc-breakpoint("alias", nth($key, 3), flint-get-index(nth($key, 3))) - $unit) ) { 963 | @content; 964 | } 965 | } @else { 966 | @if not $flint-development-mode { 967 | @error "Invalid gutter settings in config map: #{flint-get-value('settings', 'grid')}. Valid arguments: fluid, fixed"; 968 | } 969 | } 970 | 971 | // 972 | // Less than number 973 | // 974 | } @else if flint-types-in-list($key, "string" "string" "number", 3) and nth($key, 1) == "less" and nth($key, 2) == "than" { 975 | 976 | @if flint-get-config-unit() == unit(nth($key, 3)) { 977 | @media ( max-width: nth($key, 3) - $unit ) { 978 | @content; 979 | } 980 | } @else { 981 | @if not $flint-development-mode { 982 | @error "Passed units [#{unit(nth($key, 3))}] do not match the unit used in your config map: #{flint-get-config-unit()}"; 983 | } 984 | } 985 | 986 | // 987 | // Number less than $key breakpoint 988 | // 989 | } @else if flint-types-in-list($key, "number" "string" "string" "string", 4) and nth($key, 2) == "less" and nth($key, 3) == "than" { 990 | 991 | @if flint-get-config-unit() == unit(nth($key, 1)) { 992 | @media ( max-width: (flint-calc-breakpoint("alias", nth($key, 4), flint-get-index(nth($key, 4))) - nth($key, 1)) ) { 993 | @content; 994 | } 995 | } @else { 996 | @if not $flint-development-mode { 997 | @error "Passed units [#{unit(nth($key, 1))}] do not match the unit used in your config map: #{flint-get-config-unit()}"; 998 | } 999 | } 1000 | 1001 | // 1002 | // For $key-x $key-y $key-z 1003 | // 1004 | } @else if flint-types-in-list($key, "string") and nth($key, 1) == "for" { 1005 | // Define empty query list 1006 | $query: (); 1007 | 1008 | // 1009 | // Build out comma delimited query list for each breakpoint 1010 | // 1011 | @for $i from 1 through length($key) { 1012 | $calc-key: nth($key, $i); 1013 | 1014 | @if map-has-key(map-get($flint, "breakpoints"), $calc-key) { 1015 | @if flint-get-value("settings", "grid") == "fluid" { 1016 | @if flint-is-highest-breakpoint($calc-key) { 1017 | $query: append($query, unquote('( min-width: #{(flint-calc-breakpoint("next", $calc-key, flint-get-index($calc-key)) + $unit)} )'), "comma"); 1018 | } @else { 1019 | $query: append($query, unquote('( min-width: #{(flint-calc-breakpoint("next", $calc-key, flint-get-index($calc-key)) + if(flint-is-lowest-breakpoint($calc-key), 0, $unit))} ) and ( max-width: #{flint-calc-breakpoint("alias", $calc-key, flint-get-index($calc-key))} )'), "comma"); 1020 | } 1021 | } @else if flint-get-value("settings", "grid") == "fixed" { 1022 | @if flint-is-highest-breakpoint($calc-key) { 1023 | $query: append($query, unquote('( min-width: #{flint-calc-breakpoint("alias", $calc-key, flint-get-index($calc-key))} )'), "comma"); 1024 | } @else { 1025 | $query: append($query, unquote('( min-width: #{flint-calc-breakpoint("alias", $calc-key, flint-get-index($calc-key))} ) and ( max-width: #{(flint-calc-breakpoint("prev", $calc-key, flint-get-index($calc-key)) - $unit)} )'), "comma"); 1026 | } 1027 | } @else { 1028 | @if not $flint-development-mode { 1029 | @error "Invalid gutter settings in config map: #{flint-get-value('settings', 'grid')}. Valid arguments: fluid, fixed"; 1030 | } 1031 | } 1032 | } @else { 1033 | @if not $calc-key == "for" { 1034 | @if not $flint-development-mode { 1035 | @error "Invalid argument: #{$calc-key}. Breakpoint does not exist. Please provide a valid argument."; 1036 | } 1037 | } 1038 | } 1039 | } 1040 | 1041 | @media #{$query} { 1042 | @content; 1043 | } 1044 | } 1045 | 1046 | // 1047 | // Invalid argument 1048 | // 1049 | } @else { 1050 | @if $key != "clear" { 1051 | @if not $flint-development-mode { 1052 | @error "Invalid argument(s). Please double check and provide a valid argument. If you're calling by alias, please provide a single span argument for your breakpoint. See documentation for additional details."; 1053 | } 1054 | } 1055 | } 1056 | } 1057 | } 1058 | --------------------------------------------------------------------------------