├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── build └── sass-concat.js ├── dist └── cell.scss ├── docs └── sass │ ├── assets │ ├── css │ │ └── main.css │ ├── images │ │ ├── favicon.png │ │ ├── logo_full_compact.svg │ │ ├── logo_full_inline.svg │ │ ├── logo_light_compact.svg │ │ └── logo_light_inline.svg │ └── js │ │ ├── main.js │ │ ├── main.min.js │ │ ├── search.js │ │ ├── sidebar.js │ │ └── vendor │ │ ├── fuse.min.js │ │ ├── jquery.min.js │ │ └── prism.min.js │ └── index.html ├── package-lock.json ├── package.json ├── src ├── _cell.scss ├── _config.scss ├── atoms │ ├── _display.scss │ ├── _position.scss │ └── _visibility.scss ├── mixins │ ├── _component.scss │ ├── _context.scss │ ├── _extend.scss │ ├── _modifier.scss │ ├── _module.scss │ ├── _option.scss │ ├── _pseudo-state.scss │ ├── _value.scss │ └── _wrapper.scss └── utilities │ ├── _create-config.scss │ ├── _create-selector-from-context.scss │ ├── _css-properties.scss │ ├── _enabled.scss │ ├── _get-module-name.scss │ ├── _get-param.scss │ ├── _merge-css-maps.scss │ ├── _module-tree.scss │ ├── _option.scss │ ├── _parse-cq.scss │ ├── _remove-junk.scss │ ├── _remove-modifiers.scss │ ├── _selector-to-map.scss │ ├── _setting.scss │ ├── _strip-glue.scss │ ├── _theme.scss │ ├── _this.scss │ └── _value-enabled.scss ├── stylelint.config.js └── test ├── mixins └── _module.scss ├── tests.js ├── tests.scss └── utilities ├── _config.scss ├── _option.scss ├── _setting.scss └── _this.scss /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .vscode 3 | .settings 4 | .sass-cache 5 | .DS_Store 6 | debug.log 7 | node_modules -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 10 4 | install: 5 | - npm install 6 | before_script: 7 | - npm run build -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/One-Nexus/Cell/blob/master/LICENSE) 2 | [![Build Status](https://travis-ci.com/One-Nexus/Cell.svg?branch=master)](https://travis-ci.com/One-Nexus/Cell) 3 | [![npm version](https://badge.fury.io/js/%40onenexus%2Fcell.svg)]((https://www.npmjs.com/package/@onenexus/cell)) 4 | [![npm downloads](https://img.shields.io/npm/dm/@onenexus/cell.svg)](https://www.npmjs.com/package/@onenexus/cell) 5 | 6 | > Style BEM DOM elements using Sass [[View SassDocs](https://one-nexus.github.io/Cell/sass/)] 7 | 8 | 9 | 10 | * [Overview](#overview) 11 | * [Installation & Setup](#installation--setup) 12 | * [Creating a Module](https://github.com/One-Nexus/Cell/wiki/Creating-a-Module) 13 | * [Mixins](#mixins) 14 | * [Utility Functions](#utilities) 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 |
CodeSandbox Demos
Standard DemoJavaScript DemoReact DemoBasic Sass-Only Demo
31 | 32 | ## Overview 33 | 34 | Cell is used for styling DOM elements that follow the [Cell naming convention](https://github.com/One-Nexus/Cell/wiki/Cell-Naming-Convention) (which is almost identical to [BEM](http://getbem.com/)). 35 | 36 | > [Learn how to integrate with React components](#using-with-react) 37 | 38 | * Cell is used for creating modular, configurable and scalable Sass components 39 | * Works with any Sass implementation (Ruby, Dart, Node...) 40 | * Requires Sass 3.4+ (4.9+ if using Node-Sass) 41 | * [Import themes/configuration into your Sass/Cell components as JavaScript/JSON](https://github.com/One-Nexus/Cell/wiki/JavaScript-Configuration#usage) 42 | * Built for the [Synergy framework](https://github.com/One-Nexus/Synergy) 43 | * [Compatible with Cell Query](https://github.com/One-Nexus/Synergy-Front-End-Guides/wiki/Cell-Query) 44 | 45 | ### Example 46 | 47 | Given the following markup for an accordion with an active panel component: 48 | 49 | > [View CodeSandbox Demo](https://codesandbox.io/s/cell-demo--basic-p55bc) 50 | 51 | > Unlike traditional BEM, you do not need separate classes for modifiers 52 | 53 | ```html 54 |
55 |
56 |
foo
57 |
bar
58 |
59 |
60 |
fizz
61 |
buzz
62 |
63 |
64 | ``` 65 | 66 | This can be styled with Cell like so: 67 | 68 | ```scss 69 | @include module('accordion') { 70 | @include component('panel') { 71 | ... 72 | 73 | @include is('active') { 74 | @include component('content') { 75 | display: block; 76 | } 77 | } 78 | } 79 | 80 | @include component('title') { 81 | ... 82 | } 83 | 84 | @include component('content') { 85 | ... 86 | display: none; 87 | } 88 | } 89 | ``` 90 | 91 | ### Using `context()` 92 | 93 | The above examples use the traditional _cascading_ paradigm to apply styles under certain conditions. You can see that to _show_ the `content` component above, the `display` property is applied in a cascading fashion _inside_ the `panel` component. 94 | 95 | Cell allows you to go about this in a dfferent way, allowing you to keep all styles pertaining to a single component in one place, thanks to the [`context()`](https://github.com/One-Nexus/Cell/wiki/Context()) mixin, as seen in this example (this will produce identical CSS to the previous example): 96 | 97 | ```scss 98 | @include module('accordion') { 99 | @include component('panel') { 100 | ... 101 | } 102 | 103 | @include component('title') { 104 | ... 105 | } 106 | 107 | @include component('content') { 108 | ... 109 | display: none; 110 | 111 | @include context(($this, 'panel'), 'active') { 112 | display: block; 113 | } 114 | } 115 | } 116 | ``` 117 | 118 | ### Using [Cell Atoms](https://github.com/One-Nexus/Cell/wiki/Atoms) 119 | 120 | > [Learn more about Cell Atoms](https://github.com/One-Nexus/Cell/wiki/Atoms) 121 | 122 | Continuing from the previous example, the `display` Atom can instead be used to handle the `display` property: 123 | 124 | ```scss 125 | @include module('accordion') { 126 | @include component('panel') { 127 | ... 128 | } 129 | 130 | @include component('title') { 131 | ... 132 | } 133 | 134 | @include component('content') { 135 | ... 136 | @include display((($this, 'panel'), 'active'), block, none); 137 | } 138 | } 139 | ``` 140 | 141 | ### Using [Cell Query (CQ)](https://github.com/One-Nexus/Synergy-Front-End-Guides/wiki/Cell-Query) 142 | 143 | Cell can interpret and parse CQ by passing a CQ compatible Sass map as the second parameter to the `module()` mixin, allowing the `accordion` example to be re-written as: 144 | 145 | ```scss 146 | @include module('accordion', ( 147 | 'panel': ( 148 | ... 149 | ), 150 | 151 | 'title': ( 152 | ... 153 | ), 154 | 155 | 'content': ( 156 | ... 157 | 'display': none, 158 | 159 | 'panel-is-active': ( 160 | 'display': block 161 | ) 162 | ) 163 | )); 164 | ``` 165 | 166 | > [Learn more about Cell and Cell Query (CQ)](https://github.com/One-Nexus/Cell/wiki/Cell-Query) 167 | 168 | ## Installation & Setup 169 | 170 | ``` 171 | npm install --save @onenexus/cell 172 | ``` 173 | 174 | ```scss 175 | // this path will vary depending on where the library is being imported 176 | @import '../../node_modules/@onenexus/cell/dist/cell'; 177 | ``` 178 | 179 | If you are using Node Sass, you can import the library anywhere using: 180 | 181 | ```scss 182 | @import '~@onenexus/cell/dist/cell'; 183 | ``` 184 | 185 | > See the [JavaScript Configuration](https://github.com/One-Nexus/Cell/wiki/JavaScript-Configuration) page for instructions on how to use JavaScript/JSON configuration 186 | 187 | ## Using with JavaScript 188 | 189 | Cell can be used with JavaScript for things like [theming](https://github.com/One-Nexus/Cell/wiki/Theming) and [module configuration](https://github.com/One-Nexus/Cell/wiki/Module-Configuration). 190 | 191 | > [View CodeSandbox Demo](https://codesandbox.io/s/cell-demo--js-iklx3) 192 | 193 | > [Using React?](#using-with-react) 194 | 195 | ### Example 196 | 197 | ``` 198 | modules/ 199 | |--myModule/ 200 | | |--config.js 201 | | |--styles.scss 202 | themes/ 203 | |--myTheme.js 204 | app.scss 205 | ``` 206 | 207 | ###### themes/myTheme.js 208 | 209 | ```js 210 | export default { 211 | colors: { 212 | primary: '#00d4ff', 213 | secondary: '#58ed02' 214 | }, 215 | breakpoints: { 216 | small: '720px', 217 | large: '1400px' 218 | } 219 | } 220 | ``` 221 | 222 | ###### modules/myModule/config.js 223 | 224 | ```js 225 | export default (theme) => ({ 226 | name: 'myModule', 227 | background: theme.colors.primary, 228 | gutter: '1em' 229 | }); 230 | ``` 231 | 232 | ###### modules/myModule/styles.scss 233 | 234 | ```scss 235 | @import 'config.js'; 236 | 237 | @include module { 238 | display: block; 239 | margin-top: this('gutter'); 240 | 241 | @media (min-width: theme('breakpoints', 'small')) { 242 | display: inline-block; 243 | } 244 | } 245 | ``` 246 | 247 | ###### app.scss 248 | 249 | ```scss 250 | @import '~@onenexus/cell/dist/cell'; 251 | @import 'themes/myTheme.js'; 252 | @import 'modules/myModule/styles'; 253 | ``` 254 | 255 | ###### CSS Output 256 | 257 | ```css 258 | .myModule, [class*="myModule--"] { 259 | background: #00d4ff; 260 | display: block; 261 | margin-top: 1em; 262 | } 263 | 264 | @media (min-width: 720px) { 265 | .myModule, [class*="myModule--"] { 266 | display: inline-block; 267 | } 268 | } 269 | ``` 270 | 271 | > Note that the `background` property is output to CSS despite not being hard-coded inside `styles.scss` - this is because configuration properties that correspond to CSS properties can be automatically parsed as CSS - read the [Cell Query page](https://github.com/One-Nexus/Cell/wiki/Cell-Query) to learn more 272 | 273 | > Read the [JavaScript Configuration page](https://github.com/One-Nexus/Cell/wiki/JavaScript-Configuration) for setup instructions and more information 274 | 275 | ## Using with React 276 | 277 | Using Cell with React can be as simple as configuring your Webpack to use [Sass-Loader](https://github.com/webpack-contrib/sass-loader). See how the below React accordion component can be styled by importing its corresponding Cell module (`styles.scss`): 278 | 279 | > [View CodeSandbox Demo](https://codesandbox.io/s/cell-demo--react-hygf9) 280 | 281 | ###### modules/Accordion/index.js 282 | 283 | ```jsx 284 | import React, { useState } from 'react'; 285 | import './styles.scss'; 286 | 287 | const Accordion = ({ panels, ...props }) => { 288 | const [activeIndex, toggle] = useState(0); 289 | 290 | return ( 291 |
292 | {panels.map(({ heading, content }, index) => ( 293 |
294 |
toggle(index)}> 295 | {title} 296 |
297 | 298 |
299 | {content} 300 |
301 |
302 | ))} 303 |
304 | ); 305 | } 306 | 307 | export default Accordion; 308 | ``` 309 | 310 | ### Using with Lucid (React Library) 311 | 312 | [Lucid](https://github.com/One-Nexus/Lucid) is a React library for working with the Cell/BEM naming convention. If using Lucid, the above React component could be rewritten as: 313 | 314 | ```jsx 315 | import React, { useState } from 'react'; 316 | import { Module, Component } from '@onenexus/lucid'; 317 | import './styles'; 318 | 319 | const Accordion = ({ panels, ...props }) => { 320 | const [activeIndex, toggle] = useState(0); 321 | 322 | return ( 323 | 324 | {panels.map(({ heading, content }, index) => ( 325 | 326 | toggle(index)}> 327 | {heading} 328 | 329 | 330 | 331 | {content} 332 | 333 | 334 | ))} 335 | 336 | ); 337 | } 338 | 339 | export default Accordion; 340 | ``` 341 | 342 | This solution offers all the practical benefits of scoped styling (thanks to the underlying Cell/BEM naming convention) without any of the uglyness that BEM usually brings, and without any of the overhead that CSS-in-JS techniques (and actual *scoping*) bring, keeping everything clean and tidy. 343 | 344 | ## Useful Wiki Pages 345 | 346 | * [Creating a Cell Module](https://github.com/One-Nexus/Cell/wiki/Creating-a-Module) 347 | * [Module Configuration](https://github.com/One-Nexus/Cell/wiki/Module-Configuration) 348 | * [Theming](https://github.com/One-Nexus/Cell/wiki/Theming) 349 | * [Cell Query (CQ)](https://github.com/One-Nexus/Cell/wiki/Cell-Query) 350 | * [Using with JavaScript](https://github.com/One-Nexus/Cell/wiki/JavaScript-Configuration) 351 | * [Atoms](https://github.com/One-Nexus/Cell/wiki/Atoms) 352 | 353 | ## Mixins 354 | 355 | Cell comes with the following mixins to help create and structure your modules in the most efficient way possible: 356 | 357 | * [Module](https://github.com/One-Nexus/Cell/wiki/Module()) 358 | * [Component](https://github.com/One-Nexus/Cell/wiki/Component()) 359 | * [Modifier](https://github.com/One-Nexus/Cell/wiki/Modifier()) 360 | * [Option](https://github.com/One-Nexus/Cell/wiki/Option()) 361 | * [Value](https://github.com/One-Nexus/Cell/wiki/Value()) 362 | * [Extend](https://github.com/One-Nexus/Cell/wiki/Extend()) 363 | * [Context](https://github.com/One-Nexus/Cell/wiki/Context()) 364 | * [Pseudo-State](https://github.com/One-Nexus/Cell/wiki/Pseudo-State()) 365 | * [Wrapper](https://github.com/One-Nexus/Cell/wiki/Wrapper()) 366 | 367 | ## Utility Functions 368 | 369 | * [Create Config](https://github.com/One-Nexus/Cell/wiki/utilities#create-config) 370 | * [Enabled](https://github.com/One-Nexus/Cell/wiki/utilities#enabled) 371 | * [Value Enabled](https://github.com/One-Nexus/Cell/wiki/utilities#value-enabled) 372 | * [Option](https://github.com/One-Nexus/Cell/wiki/utilities#option) 373 | * [Setting](https://github.com/One-Nexus/Cell/wiki/utilities#setting) 374 | * [This](https://github.com/One-Nexus/Cell/wiki/utilities#this) 375 | * [Theme](https://github.com/One-Nexus/Cell/wiki/utilities#theme) 376 | 377 | ## BEM Inspired Motivation 378 | 379 | The initial motiviation behind creating Cell is twofold: 380 | 381 | * Address the uglyness of BEM 382 | * Address the practical implementation of BEM using Sass 383 | 384 | BEM solves very real problems like no other solution due to [its inherent nature](https://itnext.io/thinking-of-bem-as-a-ui-philosophy-instead-of-a-css-naming-convention-9727e2cf9328), however it is [often considered quite ugly](https://hackernoon.com/bem-should-not-exist-6414005765d6); the `__` and `--` thrown into your HTML along with [repeated keywords when using modifiers](https://stackoverflow.com/questions/32052836/sass-bem-avoid-modifier-duplication-when-element-is-inside-a-modifier) (`block__component block__component--modifier-1 block__component--modifier-2`) make the HTML extremely jarring to look at. Cell solves these issues by abstracting the logic into mixins and making use of CSS's [wildcard attribute selector](https://developer.mozilla.org/en-US/docs/Web/CSS/Attribute_selectors). 385 | 386 | Since the initial conception, Cell has evolved to become a fully-fledged framework for writing scalable and maintainable CSS. 387 | 388 | --- 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | -------------------------------------------------------------------------------- /build/sass-concat.js: -------------------------------------------------------------------------------- 1 | const concat = require('concat'); 2 | const path = require('path'); 3 | const fs = require('fs'); 4 | 5 | const files = [ 6 | // vendor 7 | './node_modules/Sass-Boost/dist/_sass-boost.scss', 8 | // config 9 | './src/_config.scss', 10 | // atoms 11 | './src/atoms/_display.scss', 12 | './src/atoms/_position.scss', 13 | './src/atoms/_visibility.scss', 14 | // utilities 15 | './src/utilities/_create-config.scss', 16 | './src/utilities/_create-selector-from-context.scss', 17 | './src/utilities/_css-properties.scss', 18 | './src/utilities/_enabled.scss', 19 | './src/utilities/_get-module-name.scss', 20 | './src/utilities/_get-param.scss', 21 | './src/utilities/_merge-css-maps.scss', 22 | './src/utilities/_module-tree.scss', 23 | './src/utilities/_option.scss', 24 | './src/utilities/_remove-junk.scss', 25 | './src/utilities/_remove-modifiers.scss', 26 | './src/utilities/_parse-cq.scss', 27 | './src/utilities/_selector-to-map.scss', 28 | './src/utilities/_setting.scss', 29 | './src/utilities/_strip-glue.scss', 30 | './src/utilities/_theme.scss', 31 | './src/utilities/_this.scss', 32 | './src/utilities/_value-enabled.scss', 33 | // mixins 34 | './src/mixins/_module.scss', 35 | './src/mixins/_component.scss', 36 | './src/mixins/_modifier.scss', 37 | './src/mixins/_extend.scss', 38 | './src/mixins/_context.scss', 39 | './src/mixins/_option.scss', 40 | './src/mixins/_pseudo-state.scss', 41 | './src/mixins/_value.scss', 42 | './src/mixins/_wrapper.scss' 43 | ]; 44 | 45 | concat(files).then(result => { 46 | fs.writeFile(path.join(__dirname, '../dist/cell.scss'), result, error => { 47 | if (error) { 48 | return console.warn(error); 49 | } 50 | }); 51 | }); -------------------------------------------------------------------------------- /docs/sass/assets/css/main.css: -------------------------------------------------------------------------------- 1 | @import url(https://fonts.googleapis.com/css?family=Roboto:400,100,300,500,700); 2 | 3 | .container:after, 4 | .header:after, 5 | .searchbar:after { 6 | content: ""; 7 | display: table; 8 | clear: both 9 | } 10 | .visually-hidden { 11 | width: 1px; 12 | height: 1px; 13 | position: absolute; 14 | padding: 0; 15 | margin: -1px; 16 | overflow: hidden; 17 | clip: rect(0 0 0 0); 18 | border: 0; 19 | } 20 | .sidebar__title { 21 | text-overflow: ellipsis; 22 | overflow: hidden; 23 | white-space: nowrap; 24 | } 25 | code[class*='language-'], 26 | pre[class*='language-'] { 27 | color: black; 28 | text-shadow: 0 1px white; 29 | font-family: Consolas, Monaco, 'Andale Mono', monospace; 30 | direction: ltr; 31 | text-align: left; 32 | white-space: pre; 33 | word-spacing: normal; 34 | word-break: normal; 35 | -moz-tab-size: 4; 36 | -o-tab-size: 4; 37 | tab-size: 4; 38 | -webkit-hyphens: none; 39 | -moz-hyphens: none; 40 | -ms-hyphens: none; 41 | hyphens: none 42 | } 43 | pre[class*='language-']::-moz-selection, 44 | pre[class*='language-']::-moz-selection, 45 | code[class*='language-']::-moz-selection, 46 | code[class*='language-']::-moz-selection { 47 | text-shadow: none; 48 | background: #b3d4fc 49 | } 50 | pre[class*='language-']::selection, 51 | pre[class*='language-']::selection, 52 | code[class*='language-']::selection, 53 | code[class*='language-']::selection { 54 | text-shadow: none; 55 | background: #b3d4fc 56 | } 57 | @media print { 58 | code[class*='language-'], 59 | pre[class*='language-'] { 60 | text-shadow: none 61 | } 62 | } 63 | pre[class*='language-'] { 64 | padding: 1em; 65 | margin: .5em 0; 66 | overflow: auto 67 | } 68 | :not(pre)>code[class*='language-'], 69 | pre[class*='language-'] { 70 | background: white 71 | } 72 | :not(pre)>code[class*='language-'] { 73 | padding: .1em; 74 | border-radius: .3em 75 | } 76 | .token.comment, 77 | .token.prolog, 78 | .token.doctype, 79 | .token.cdata { 80 | color: slategray 81 | } 82 | .token.punctuation { 83 | color: #999 84 | } 85 | .namespace { 86 | opacity: .7 87 | } 88 | .token.property, 89 | .token.tag, 90 | .token.boolean, 91 | .token.number, 92 | .token.constant, 93 | .token.symbol { 94 | color: #905 95 | } 96 | .token.selector, 97 | .token.attr-name, 98 | .token.string, 99 | .token.builtin { 100 | color: #690 101 | } 102 | .token.operator, 103 | .token.entity, 104 | .token.url, 105 | .language-css .token.string, 106 | .style .token.string, 107 | .token.variable { 108 | color: #a67f59; 109 | background: rgba(255, 255, 255, 0.5) 110 | } 111 | .token.atrule, 112 | .token.attr-value, 113 | .token.keyword { 114 | color: #07a 115 | } 116 | .token.regex, 117 | .token.important { 118 | color: #e90 119 | } 120 | .token.important { 121 | font-weight: bold 122 | } 123 | .token.entity { 124 | cursor: help 125 | } 126 | html { 127 | -webkit-box-sizing: border-box; 128 | -moz-box-sizing: border-box; 129 | box-sizing: border-box 130 | } 131 | *, 132 | *::after, 133 | *::before { 134 | -webkit-box-sizing: inherit; 135 | -moz-box-sizing: inherit; 136 | box-sizing: inherit 137 | } 138 | body { 139 | font: 1em/1.35 "Roboto", "Helvetica Neue Light", "Helvetica Neue", "Helvetica", "Arial", sans-serif; 140 | overflow: auto; 141 | margin: 0 142 | } 143 | a { 144 | transition: 0.15s; 145 | text-decoration: none; 146 | color: #333; 147 | } 148 | a:hover, 149 | a:hover code { 150 | color: #2196F3; 151 | } 152 | table p { 153 | margin: 0 0 0.5rem 154 | } 155 | :not(pre)>code { 156 | color: tomato; 157 | white-space: nowrap; 158 | font-weight: normal 159 | } 160 | :not(pre)>code:hover { 161 | color: black !important; 162 | } 163 | @media (max-width: 800px) { 164 | table, 165 | tbody, 166 | tr, 167 | td, 168 | th { 169 | display: block 170 | } 171 | thead { 172 | width: 1px; 173 | height: 1px; 174 | position: absolute; 175 | padding: 0; 176 | margin: -1px; 177 | overflow: hidden; 178 | clip: rect(0 0 0 0); 179 | border: 0 180 | } 181 | tr { 182 | padding-bottom: 1em; 183 | margin-bottom: 1em; 184 | border-bottom: 2px solid #ddd 185 | } 186 | td::before, 187 | th::before { 188 | content: attr(data-label)": "; 189 | text-transform: capitalize; 190 | font-weight: bold 191 | } 192 | td p, 193 | th p { 194 | display: inline 195 | } 196 | } 197 | .layout-toggle { 198 | display: none 199 | } 200 | @media (min-width: 801px) { 201 | .layout-toggle { 202 | position: absolute; 203 | top: 8px; 204 | left: 20px; 205 | font-size: 2em; 206 | cursor: pointer; 207 | color: #1565C0; 208 | display: block 209 | } 210 | .layout-toggle:hover { 211 | color: #0D47A1; 212 | } 213 | } 214 | @media (min-width: 801px) { 215 | .sidebar-closed .sidebar { 216 | -webkit-transform: translateX(-280px); 217 | -ms-transform: translateX(-280px); 218 | transform: translateX(-280px) 219 | } 220 | .sidebar-closed .main { 221 | padding-left: 0 222 | } 223 | .sidebar-closed .header { 224 | left: 0 225 | } 226 | } 227 | .list-unstyled { 228 | padding-left: 0; 229 | list-style: none; 230 | line-height: 1.5; 231 | margin-top: 0; 232 | margin-bottom: 1.5rem 233 | } 234 | .list-inline li { 235 | display: inline-block 236 | } 237 | .container { 238 | max-width: 100%; 239 | width: 1170px; 240 | margin: 0 auto; 241 | padding: 0 2rem 242 | } 243 | .relative { 244 | position: relative 245 | } 246 | .clear { 247 | clear: both 248 | } 249 | .header { 250 | position: fixed; 251 | top: 0; 252 | right: 0; 253 | left: 280px; 254 | padding: 1em 0; 255 | background: #2196F3; 256 | color: #e0e0e0; 257 | z-index: 4000 258 | } 259 | @media (max-width: 800px) { 260 | .header { 261 | left: 0 262 | } 263 | } 264 | @media (min-width: 801px) { 265 | .header { 266 | transition: 0.2s cubic-bezier(0.215, 0.61, 0.355, 1) 267 | } 268 | } 269 | .header__title { 270 | font-weight: 500; 271 | text-align: center; 272 | margin: 0 0 0.5em 0 273 | } 274 | .header__title a { 275 | color: #e0e0e0 276 | } 277 | @media (min-width: 801px) { 278 | .header__title { 279 | float: left; 280 | font-size: 1em; 281 | margin-top: .25em; 282 | margin-bottom: 0 283 | } 284 | } 285 | .searchbar { 286 | display: inline-block; 287 | float: right 288 | } 289 | @media (max-width: 800px) { 290 | .searchbar { 291 | display: block; 292 | float: none 293 | } 294 | } 295 | .searchbar__form { 296 | float: right; 297 | position: relative 298 | } 299 | @media (max-width: 800px) { 300 | .searchbar__form { 301 | float: none 302 | } 303 | } 304 | @media (min-width: 801px) { 305 | .searchbar__form { 306 | min-width: 15em 307 | } 308 | } 309 | .searchbar__field { 310 | border: none; 311 | padding: 0.5em 0; 312 | font-size: 1em; 313 | margin: 0; 314 | width: 100%; 315 | color: #FFF; 316 | outline: none; 317 | background-color: transparent; 318 | border-bottom: 1px solid rgba(255,255,255,.7); 319 | } 320 | .searchbar__field::-webkit-input-placeholder 321 | { 322 | color: rgba(255,255,255,.7); 323 | } 324 | .searchbar__suggestions { 325 | position: absolute; 326 | top: 100%; 327 | right: 0; 328 | left: 0; 329 | box-shadow: 0 1.5px 4px rgba(0, 0, 0, 0.24), 0 1.5px 6px rgba(0, 0, 0, 0.12); 330 | border: 1px solid #e0e0e0; 331 | background: white; 332 | padding: 0; 333 | margin: 0; 334 | list-style: none; 335 | z-index: 2 336 | } 337 | .searchbar__suggestions:empty { 338 | display: none 339 | } 340 | .searchbar__suggestions .selected { 341 | background: #ddd 342 | } 343 | .searchbar__suggestions li { 344 | border-bottom: 1px solid #e0e0e0 345 | } 346 | .searchbar__suggestions li:last-of-type { 347 | border: none 348 | } 349 | .searchbar__suggestions a { 350 | display: block; 351 | padding: 0.5em; 352 | font-size: 0.9em 353 | } 354 | .searchbar__suggestions a:hover, 355 | .searchbar__suggestions a:active, 356 | .searchbar__suggestions a:focus { 357 | background: #e0e0e0 358 | } 359 | .searchbar__suggestions code { 360 | margin-right: .5em 361 | } 362 | @media (min-width: 801px) { 363 | .sidebar { 364 | position: fixed; 365 | top: 0; 366 | bottom: 0; 367 | left: 0; 368 | overflow: auto; 369 | width: 280px; 370 | z-index: 2; 371 | border-right: 1px solid #e0e0e0; 372 | transition: 0.2s cubic-bezier(0.215, 0.61, 0.355, 1) 373 | } 374 | } 375 | @media (max-width: 800px) { 376 | .sidebar { 377 | margin-top: 4em 378 | } 379 | } 380 | .sidebar__annotation { 381 | color: #5c4863 382 | } 383 | .sidebar__item { 384 | font-size: 0.9em 385 | } 386 | .sidebar__item a { 387 | padding: 0.5em 4.5em; 388 | display: block; 389 | text-decoration: none; 390 | color: #555 391 | } 392 | .sidebar__item:hover, 393 | .sidebar__item:active, 394 | .sidebar__item:focus { 395 | background: #EEE; 396 | color: #333; 397 | } 398 | .sidebar__item.is-collapsed+* { 399 | display: none 400 | } 401 | .sidebar__item--heading { 402 | padding: 1em 1.5em 403 | } 404 | .sidebar__item--heading a { 405 | font-weight: bold 406 | } 407 | .sidebar__item--sub-heading { 408 | padding: 0.5em 2.5em 409 | } 410 | .sidebar__item--sub-heading a { 411 | color: #888 412 | } 413 | .sidebar__item--heading, 414 | .sidebar__item--sub-heading { 415 | position: relative 416 | } 417 | .sidebar__item--heading:after, 418 | .sidebar__item--sub-heading:after { 419 | position: absolute; 420 | top: 50%; 421 | right: 2em; 422 | content: '\25BC'; 423 | margin-top: -0.5em; 424 | color: #ddd; 425 | font-size: 0.7em 426 | } 427 | .sidebar__item--heading.is-collapsed:after, 428 | .sidebar__item--sub-heading.is-collapsed:after { 429 | content: '\25B6' 430 | } 431 | 432 | .sidebar__item--heading a, 433 | .sidebar__item--sub-heading a { 434 | padding: 0; 435 | display: inline 436 | } 437 | .sidebar__description { 438 | color: #e0e0e0; 439 | padding-right: 2em 440 | } 441 | .sidebar__header { 442 | border-bottom: 1px solid #e0e0e0 443 | } 444 | .sidebar__title { 445 | font-size: 1em; 446 | margin: 0; 447 | padding: 1.45em 448 | } 449 | .btn-toggle { 450 | background: #EFEFEF; 451 | border: none; 452 | border-bottom: 1px solid #e0e0e0; 453 | display: block; 454 | padding: 1em; 455 | width: 100%; 456 | cursor: pointer; 457 | color: #999; 458 | font-weight: bold; 459 | margin: 0; 460 | transition: 0.15s ease-out; 461 | outline: none; 462 | } 463 | .btn-toggle:hover, 464 | .btn-toggle:active, 465 | .btn-toggle:focus { 466 | background: #EEE; 467 | color: #333; 468 | } 469 | .main { 470 | background: #f9f9f9; 471 | position: relative 472 | } 473 | @media (min-width: 801px) { 474 | .main { 475 | transition: 0.2s cubic-bezier(0.215, 0.61, 0.355, 1); 476 | padding-left: 280px; 477 | padding-top: 4em; 478 | min-height: 45em 479 | } 480 | } 481 | .main__section { 482 | margin-top: 5em; 483 | } 484 | .header+.main__section { 485 | margin-top: 0; 486 | border-top: none 487 | } 488 | .main__heading, 489 | .main__heading--secondary { 490 | padding: 1em 0; 491 | margin-top: 0 492 | } 493 | @media (min-width: 801px) { 494 | .main__heading, 495 | .main__heading--secondary { 496 | padding: 2em 0 0 497 | } 498 | } 499 | .main__heading { 500 | color: #fff; 501 | font-size: 3.5em; 502 | text-align: center; 503 | padding-bottom: .5em; 504 | margin-bottom: 1em; 505 | background: #2196F3; 506 | text-align: left; 507 | font-weight: 100; 508 | } 509 | .main__heading--secondary { 510 | font-size: 2.75em; 511 | color: #2196F3; 512 | font-weight: 100; 513 | padding-top: 0; 514 | padding-bottom: .5em; 515 | margin-bottom: -2rem; 516 | position: relative; 517 | border-bottom: 1px solid #ddd; 518 | } 519 | .main__heading--secondary .container { 520 | overflow: hidden; 521 | white-space: nowrap; 522 | text-overflow: ellipsis 523 | } 524 | .main__heading--secondary::before { 525 | /*content: ''; 526 | position: absolute; 527 | left: 0; 528 | right: 0; 529 | bottom: 0.15em; 530 | height: 0.2em; 531 | background-color: #dd5a6f*/ 532 | } 533 | .footer { 534 | background: #e0e0e0; 535 | padding: 1em 0 536 | } 537 | .footer .container { 538 | position: relative 539 | } 540 | .footer__project-info { 541 | float: left 542 | } 543 | .footer__watermark { 544 | position: absolute; 545 | right: 0; 546 | top: -0.7em 547 | } 548 | .footer__watermark img { 549 | display: block; 550 | max-width: 7em 551 | } 552 | .project-info__name, 553 | .project-info__version, 554 | .project-info__license { 555 | display: inline-block 556 | } 557 | .project-info__version, 558 | .project-info__license { 559 | color: #555 560 | } 561 | .project-info__license { 562 | text-indent: -0.25em 563 | } 564 | .main__section { 565 | margin-bottom: 4.5rem 566 | } 567 | .main__sub-section:after { 568 | border-bottom: 1px solid #EEE; 569 | content: ''; 570 | display: block; 571 | padding-top: 10%; 572 | margin-bottom: 10%; 573 | width: 100%; 574 | } 575 | .item__heading { 576 | color: #333; 577 | margin: 4.5rem 0 1.5rem 0; 578 | position: relative; 579 | font-size: 2em; 580 | font-weight: 300; 581 | float: left 582 | } 583 | .item__name { 584 | color: #333; 585 | } 586 | .item__example { 587 | margin-bottom: 1.5rem 588 | } 589 | .item__example, 590 | .item__code { 591 | border: 1px solid #e0e0e0; 592 | word-wrap: break-word; 593 | line-height: 1.42 594 | } 595 | .item__code { 596 | padding-right: 7em; 597 | clear: both; 598 | cursor: pointer; 599 | transition: box-shadow .2s ease; 600 | } 601 | .item__code:hover { 602 | box-shadow: 0 10px 20px rgba(0, 0, 0, 0.1); 603 | border: 1px solid #BCBCBC; 604 | 605 | } 606 | .item__code--togglable::after { 607 | position: absolute; 608 | right: 0; 609 | bottom: -2.5em; 610 | -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; 611 | opacity: 0; 612 | color: #c4c4c4; 613 | font-size: 0.8em; 614 | transition: 0.2s ease-out 615 | } 616 | .item__code--togglable:hover::after, 617 | .item__code--togglable:active::after, 618 | .item__code--togglable:focus::after { 619 | -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=100)"; 620 | opacity: 1 621 | } 622 | .item__code--togglable[data-current-state='expanded']::after { 623 | content: 'Click to collapse.' 624 | } 625 | .item__code--togglable[data-current-state='collapsed']::after { 626 | content: 'Click to expand.' 627 | } 628 | .example__description { 629 | padding: 1em; 630 | background: #EFEFEF 631 | } 632 | .example__description p { 633 | margin: 0 634 | } 635 | .example__code[class*='language-'] { 636 | margin: 0 637 | } 638 | .item__anchor { 639 | font-size: 0.6em; 640 | color: #eeafb9 641 | } 642 | @media (min-width: 801px) { 643 | .item__anchor { 644 | position: absolute; 645 | right: 101%; 646 | bottom: 0.25em; 647 | -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; 648 | opacity: 0 649 | } 650 | .item:hover .item__anchor { 651 | -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=100)"; 652 | opacity: 1 653 | } 654 | } 655 | .item__deprecated { 656 | display: inline-block; 657 | overflow: hidden; 658 | margin-top: 5.5em; 659 | margin-left: 1em 660 | } 661 | .item__deprecated strong { 662 | float: left; 663 | color: #c00; 664 | text-transform: uppercase 665 | } 666 | .item__deprecated p { 667 | float: left; 668 | margin: 0; 669 | padding-left: 0.5em 670 | } 671 | .item__type { 672 | color: #ddd; 673 | text-transform: capitalize; 674 | font-size: 0.75em 675 | } 676 | .item__alias, 677 | .item__aliased { 678 | color: #ddd; 679 | font-size: 0.8em 680 | } 681 | .item__sub-heading { 682 | color: #333; 683 | margin-top: 1.5rem; 684 | margin-bottom: 1rem; 685 | font-size: 1em 686 | } 687 | .item__parameters { 688 | width: 100%; 689 | margin-bottom: 1em; 690 | border-collapse: collapse 691 | } 692 | .item__parameters thead th { 693 | vertical-align: bottom; 694 | border-bottom: 2px solid #ddd; 695 | border-top: none; 696 | text-align: left; 697 | color: #707070 698 | } 699 | .item__parameters tbody th { 700 | text-align: left 701 | } 702 | .item__parameters td, 703 | .item__parameters th { 704 | padding: 0.5em 0.5em 0.5em 0; 705 | vertical-align: top 706 | } 707 | @media (min-width: 801px) { 708 | tbody>.item__parameter:first-of-type>td { 709 | border-top: none 710 | } 711 | .item__parameters td, 712 | .item__parameters th { 713 | border-top: 1px solid #ddd 714 | } 715 | } 716 | .item__access { 717 | text-transform: capitalize; 718 | color: #5c4863; 719 | font-size: 0.8em 720 | } 721 | .item__since { 722 | float: right; 723 | padding-top: 0.9em; 724 | color: #c4c4c4; 725 | margin-bottom: 1em 726 | } 727 | .item__source-link { 728 | position: absolute; 729 | top: 1px; 730 | right: 1px; 731 | background: white; 732 | padding: 1em; 733 | z-index: 2; 734 | color: #c4c4c4 735 | } 736 | .item__cross-type { 737 | color: #4d4d4d; 738 | font-family: 'Consolas', 'Monaco', 'Andale Mono', monospace; 739 | font-size: 0.8em 740 | } 741 | .item__description { 742 | margin-bottom: 1.5rem 743 | } 744 | li.item__description { 745 | margin-bottom: 0 746 | } 747 | .item__description--inline>* { 748 | display: inline-block; 749 | margin: 0 750 | } 751 | .item__code-wrapper { 752 | position: relative; 753 | clear: both; 754 | margin-bottom: 1.5rem 755 | } 756 | .color-preview--inline { 757 | padding: 2px 4px; 758 | border: 1px solid rgba(0, 0, 0, 0.1); 759 | border-radius: 3px 760 | } 761 | .color-preview--block { 762 | width: 2em; 763 | height: 2em; 764 | position: absolute; 765 | top: 140%; 766 | right: 0; 767 | top: calc(100% + 20px); 768 | border: 1px solid rgba(0, 0, 0, 0.1); 769 | border-radius: 3px 770 | } 771 | -------------------------------------------------------------------------------- /docs/sass/assets/images/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/One-Nexus/Cell/27cb9ae146a0adadfb8685ffdee80971cd0543db/docs/sass/assets/images/favicon.png -------------------------------------------------------------------------------- /docs/sass/assets/images/logo_full_compact.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/sass/assets/images/logo_full_inline.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/sass/assets/images/logo_light_compact.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/sass/assets/images/logo_light_inline.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/sass/assets/js/main.js: -------------------------------------------------------------------------------- 1 | /* global document */ 2 | 3 | (function ($, global) { 4 | 'use strict'; 5 | 6 | // Constructor 7 | var App = function (conf) { 8 | this.conf = $.extend({ 9 | // Search module 10 | search: new global.Search(), 11 | 12 | // Sidebar module 13 | sidebar: new global.Sidebar(), 14 | 15 | // Initialisation 16 | init: true 17 | }, conf || {}); 18 | 19 | // Launch the module 20 | if (this.conf.init !== false) { 21 | this.initialize(); 22 | } 23 | }; 24 | 25 | // Initialisation method 26 | App.prototype.initialize = function () { 27 | this.codePreview(); 28 | }; 29 | 30 | // Toggle code preview collapsed/expanded modes 31 | App.prototype.codePreview = function () { 32 | var $item; 33 | var $code; 34 | var switchTo; 35 | 36 | $('.item__code--togglable').on('click', function () { 37 | $item = $(this); 38 | $code = $item.find('code'); 39 | switchTo = $item.attr('data-current-state') === 'expanded' ? 'collapsed' : 'expanded'; 40 | 41 | $item.attr('data-current-state', switchTo); 42 | $code.html($item.attr('data-' + switchTo)); 43 | Prism.highlightElement($code[0]); 44 | }); 45 | }; 46 | 47 | global.App = App; 48 | }(window.jQuery, window)); 49 | 50 | (function ($, global) { 51 | 52 | $(document).ready(function () { 53 | var app = new global.App(); 54 | }); 55 | 56 | }(window.jQuery, window)); -------------------------------------------------------------------------------- /docs/sass/assets/js/main.min.js: -------------------------------------------------------------------------------- 1 | !function(t){function e(t,n){this.list=t,this.options=n=n||{};var i,o,s;for(i=0,keys=["sort","includeScore","shouldSort"],o=keys.length;o>i;i++)s=keys[i],this.options[s]=s in n?n[s]:e.defaultOptions[s];for(i=0,keys=["searchFn","sortFn","keys","getFn"],o=keys.length;o>i;i++)s=keys[i],this.options[s]=n[s]||e.defaultOptions[s]}var n=function(t,e){if(e=e||{},this.options=e,this.options.location=e.location||n.defaultOptions.location,this.options.distance="distance"in e?e.distance:n.defaultOptions.distance,this.options.threshold="threshold"in e?e.threshold:n.defaultOptions.threshold,this.options.maxPatternLength=e.maxPatternLength||n.defaultOptions.maxPatternLength,this.pattern=e.caseSensitive?t:t.toLowerCase(),this.patternLen=t.length,this.patternLen>this.options.maxPatternLength)throw new Error("Pattern length is too long");this.matchmask=1<i;)this._bitapScore(e,l+o)<=u?i=o:d=o,o=Math.floor((d-i)/2+i);for(d=o,s=Math.max(1,l-o+1),r=Math.min(l+o,c)+this.patternLen,a=Array(r+2),a[r+1]=(1<=s;n--)if(p=this.patternAlphabet[t.charAt(n-1)],a[n]=0===e?(a[n+1]<<1|1)&p:(a[n+1]<<1|1)&p|((h[n+1]|h[n])<<1|1)|h[n+1],a[n]&this.matchmask&&(g=this._bitapScore(e,n-1),u>=g)){if(u=g,f=n-1,m.push(f),!(f>l))break;s=Math.max(1,2*l-f)}if(this._bitapScore(e+1,l)>u)break;h=a}return{isMatch:f>=0,score:g}};var i={deepValue:function(t,e){for(var n=0,e=e.split("."),i=e.length;i>n;n++){if(!t)return null;t=t[e[n]]}return t}};e.defaultOptions={id:null,caseSensitive:!1,includeScore:!1,shouldSort:!0,searchFn:n,sortFn:function(t,e){return t.score-e.score},getFn:i.deepValue,keys:[]},e.prototype.search=function(t){var e,n,o,s,r,a=new this.options.searchFn(t,this.options),h=this.list,p=h.length,c=this.options,l=this.options.keys,u=l.length,f=[],d={},g=[],m=function(t,e,n){void 0!==t&&null!==t&&"string"==typeof t&&(s=a.search(t),s.isMatch&&(r=d[n],r?r.score=Math.min(r.score,s.score):(d[n]={item:e,score:s.score},f.push(d[n]))))};if("string"==typeof h[0])for(var e=0;p>e;e++)m(h[e],e,e);else for(var e=0;p>e;e++)for(o=h[e],n=0;u>n;n++)m(this.options.getFn(o,l[n]),o,e);c.shouldSort&&f.sort(c.sortFn);for(var y=c.includeScore?function(t){return f[t]}:function(t){return f[t].item},L=c.id?function(t){return i.deepValue(y(t),c.id)}:function(t){return y(t)},e=0,v=f.length;v>e;e++)g.push(L(e));return g},"object"==typeof exports?module.exports=e:"function"==typeof define&&define.amd?define(function(){return e}):t.Fuse=e}(this);(function($,global){var Sidebar=function(conf){this.conf=$.extend({collapsedClass:"is-collapsed",storageKey:"_sassdoc_sidebar_index",indexAttribute:"data-slug",toggleBtn:".js-btn-toggle",init:true},conf||{});if(this.conf.init===true){this.initialize()}};Sidebar.prototype.initialize=function(){this.conf.nodes=$("["+this.conf.indexAttribute+"]");this.load();this.updateDOM();this.bind();this.loadToggle()};Sidebar.prototype.loadToggle=function(){$("",{"class":"layout-toggle",html:"×","data-alt":"☰"}).appendTo($(".header"));$(".layout-toggle").on("click",function(){var $this=$(this);var alt;$("body").toggleClass("sidebar-closed");alt=$this.html();$this.html($this.data("alt"));$this.data("alt",alt)})};Sidebar.prototype.load=function(){var index="localStorage"in global?global.localStorage.getItem(this.conf.storageKey):null;this.index=index?JSON.parse(index):this.buildIndex()};Sidebar.prototype.buildIndex=function(){var index={};var $item;this.conf.nodes.each($.proxy(function(index,item){$item=$(item);index[$item.attr(this.conf.indexAttribute)]=!$item.hasClass(this.conf.collapsedClass)},this));return index};Sidebar.prototype.updateDOM=function(){var item;for(item in this.index){if(this.index[item]===false){$("["+this.conf.indexAttribute+'="'+item+'"]').addClass(this.conf.collapsedClass)}}};Sidebar.prototype.save=function(){if(!("localStorage"in global)){return}global.localStorage.setItem(this.conf.storageKey,JSON.stringify(this.index))};Sidebar.prototype.bind=function(){var $item,slug,fn,text;var collapsed=false;global.onbeforeunload=$.proxy(function(){this.save()},this);$(this.conf.toggleBtn).on("click",$.proxy(function(event){$node=$(event.target);text=$node.attr("data-alt");$node.attr("data-alt",$node.text());$node.text(text);fn=collapsed===true?"removeClass":"addClass";this.conf.nodes.each($.proxy(function(index,item){$item=$(item);slug=$item.attr(this.conf.indexAttribute);this.index[slug]=collapsed;$("["+this.conf.indexAttribute+'="'+slug+'"]')[fn](this.conf.collapsedClass)},this));collapsed=!collapsed;this.save()},this));this.conf.nodes.on("click",$.proxy(function(event){$item=$(event.target);slug=$item.attr(this.conf.indexAttribute);this.index[slug]=!this.index[slug];$item.toggleClass(this.conf.collapsedClass)},this))};global.Sidebar=Sidebar})(window.jQuery,window);(function($,global){var Search=function(conf){this.conf=$.extend({search:{items:".sassdoc__item",input:"#js-search-input",form:"#js-search",suggestionsWrapper:"#js-search-suggestions"},fuse:{keys:["name"],threshold:.3},init:true},conf||{});if(this.conf.init===true){this.initialize()}};Search.prototype.initialize=function(){this.index=new Fuse($.map($(this.conf.search.items),function(item){var $item=$(item);return{name:$item.data("name"),type:$item.data("type"),node:$item}}),this.conf.fuse);this.initializeSearch()};Search.prototype.fillSuggestions=function(items){var searchSuggestions=$(this.conf.search.suggestionsWrapper);searchSuggestions.html("");var suggestions=$.map(items.slice(0,10),function(item){var $li=$("
  • ",{"data-type":item.type,"data-name":item.name,html:''+item.type.slice(0,3)+" "+item.name+""});searchSuggestions.append($li);return $li});return suggestions};Search.prototype.search=function(term){return this.fillSuggestions(this.index.search(term))};Search.prototype.initializeSearch=function(){var searchForm=$(this.conf.search.form);var searchInput=$(this.conf.search.input);var searchSuggestions=$(this.conf.search.suggestionsWrapper);var currentSelection=-1;var suggestions=[];var selected;var self=this;searchSuggestions.on("click",function(e){var target=$(event.target);if(target.nodeName==="A"){searchInput.val(target.parent().data("name"));suggestions=self.fillSuggestions([])}});searchForm.on("keyup",function(e){e.preventDefault();if(e.keyCode===13){if(selected){suggestions=self.fillSuggestions([]);searchInput.val(selected.data("name"));window.location=selected.children().first().attr("href")}e.stopPropagation()}if(e.keyCode===40){currentSelection=(currentSelection+1)%suggestions.length}if(e.keyCode===38){currentSelection=currentSelection-1;if(currentSelection<0){currentSelection=suggestions.length-1}}if(suggestions[currentSelection]){if(selected){selected.removeClass("selected")}selected=suggestions[currentSelection];selected.addClass("selected")}});searchInput.on("keyup",function(e){if(e.keyCode!==40&&e.keyCode!==38){currentSelection=-1;suggestions=self.search($(this).val())}else{e.preventDefault()}}).on("search",function(){suggestions=self.search($(this).val())})};global.Search=Search})(window.jQuery,window);(function($,global){"use strict";var App=function(conf){this.conf=$.extend({search:new global.Search,sidebar:new global.Sidebar,init:true},conf||{});if(this.conf.init!==false){this.initialize()}};App.prototype.initialize=function(){this.codePreview()};App.prototype.codePreview=function(){var $item;var $code;var switchTo;$(".item__code--togglable").on("click",function(){$item=$(this);$code=$item.find("code");switchTo=$item.attr("data-current-state")==="expanded"?"collapsed":"expanded";$item.attr("data-current-state",switchTo);$code.html($item.attr("data-"+switchTo));Prism.highlightElement($code[0])})};global.App=App})(window.jQuery,window);(function($,global){$(document).ready(function(){var app=new global.App})})(window.jQuery,window);var self=typeof window!="undefined"?window:{},Prism=function(){var e=/\blang(?:uage)?-(?!\*)(\w+)\b/i,t=self.Prism={util:{encode:function(e){return e instanceof n?new n(e.type,t.util.encode(e.content)):t.util.type(e)==="Array"?e.map(t.util.encode):e.replace(/&/g,"&").replace(/e.length)break e;if(p instanceof i)continue;a.lastIndex=0;var d=a.exec(p);if(d){l&&(c=d[1].length);var v=d.index-1+c,d=d[0].slice(c),m=d.length,g=v+m,y=p.slice(0,v+1),b=p.slice(g+1),w=[h,1];y&&w.push(y);var E=new i(u,f?t.tokenize(d,f):d);w.push(E);b&&w.push(b);Array.prototype.splice.apply(s,w)}}}return s},hooks:{all:{},add:function(e,n){var r=t.hooks.all;r[e]=r[e]||[];r[e].push(n)},run:function(e,n){var r=t.hooks.all[e];if(!r||!r.length)return;for(var i=0,s;s=r[i++];)s(n)}}},n=t.Token=function(e,t){this.type=e;this.content=t};n.stringify=function(e,r,i){if(typeof e=="string")return e;if(Object.prototype.toString.call(e)=="[object Array]")return e.map(function(t){return n.stringify(t,r,e)}).join("");var s={type:e.type,content:n.stringify(e.content,r,i),tag:"span",classes:["token",e.type],attributes:{},language:r,parent:i};s.type=="comment"&&(s.attributes.spellcheck="true");t.hooks.run("wrap",s);var o="";for(var u in s.attributes)o+=u+'="'+(s.attributes[u]||"")+'"';return"<"+s.tag+' class="'+s.classes.join(" ")+'" '+o+">"+s.content+""};if(!self.document){if(!self.addEventListener)return self.Prism;self.addEventListener("message",function(e){var n=JSON.parse(e.data),r=n.language,i=n.code;self.postMessage(JSON.stringify(t.tokenize(i,t.languages[r])));self.close()},!1);return self.Prism}var r=document.getElementsByTagName("script");r=r[r.length-1];if(r){t.filename=r.src;document.addEventListener&&!r.hasAttribute("data-manual")&&document.addEventListener("DOMContentLoaded",t.highlightAll)}return self.Prism}();typeof module!="undefined"&&module.exports&&(module.exports=Prism);Prism.languages.markup={comment://g,prolog:/<\?.+?\?>/,doctype://,cdata://i,tag:{pattern:/<\/?[\w:-]+\s*(?:\s+[\w:-]+(?:=(?:("|')(\\?[\w\W])*?\1|[^\s'">=]+))?\s*)*\/?>/gi,inside:{tag:{pattern:/^<\/?[\w:-]+/i,inside:{punctuation:/^<\/?/,namespace:/^[\w-]+?:/}},"attr-value":{pattern:/=(?:('|")[\w\W]*?(\1)|[^\s>]+)/gi,inside:{punctuation:/=|>|"/g}},punctuation:/\/?>/g,"attr-name":{pattern:/[\w:-]+/g,inside:{namespace:/^[\w-]+?:/}}}},entity:/\&#?[\da-z]{1,8};/gi};Prism.hooks.add("wrap",function(e){e.type==="entity"&&(e.attributes.title=e.content.replace(/&/,"&"))});Prism.languages.css={comment:/\/\*[\w\W]*?\*\//g,atrule:{pattern:/@[\w-]+?.*?(;|(?=\s*{))/gi,inside:{punctuation:/[;:]/g}},url:/url\((["']?).*?\1\)/gi,selector:/[^\{\}\s][^\{\};]*(?=\s*\{)/g,property:/(\b|\B)[\w-]+(?=\s*:)/gi,string:/("|')(\\?.)*?\1/g,important:/\B!important\b/gi,punctuation:/[\{\};:]/g,"function":/[-a-z0-9]+(?=\()/gi};Prism.languages.markup&&Prism.languages.insertBefore("markup","tag",{style:{pattern:/[\w\W]*?<\/style>/gi,inside:{tag:{pattern:/|<\/style>/gi,inside:Prism.languages.markup.tag.inside},rest:Prism.languages.css}}});Prism.languages.css.selector={pattern:/[^\{\}\s][^\{\}]*(?=\s*\{)/g,inside:{"pseudo-element":/:(?:after|before|first-letter|first-line|selection)|::[-\w]+/g,"pseudo-class":/:[-\w]+(?:\(.*\))?/g,"class":/\.[-:\.\w]+/g,id:/#[-:\.\w]+/g}};Prism.languages.insertBefore("css","ignore",{hexcode:/#[\da-f]{3,6}/gi,entity:/\\[\da-f]{1,8}/gi,number:/[\d%\.]+/g});Prism.languages.clike={comment:{pattern:/(^|[^\\])(\/\*[\w\W]*?\*\/|(^|[^:])\/\/.*?(\r?\n|$))/g,lookbehind:!0},string:/("|')(\\?.)*?\1/g,"class-name":{pattern:/((?:(?:class|interface|extends|implements|trait|instanceof|new)\s+)|(?:catch\s+\())[a-z0-9_\.\\]+/gi,lookbehind:!0,inside:{punctuation:/(\.|\\)/}},keyword:/\b(if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\b/g,"boolean":/\b(true|false)\b/g,"function":{pattern:/[a-z0-9_]+\(/gi,inside:{punctuation:/\(/}},number:/\b-?(0x[\dA-Fa-f]+|\d*\.?\d+([Ee]-?\d+)?)\b/g,operator:/[-+]{1,2}|!|<=?|>=?|={1,3}|&{1,2}|\|?\||\?|\*|\/|\~|\^|\%/g,ignore:/&(lt|gt|amp);/gi,punctuation:/[{}[\];(),.:]/g};Prism.languages.javascript=Prism.languages.extend("clike",{keyword:/\b(break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|false|finally|for|function|get|if|implements|import|in|instanceof|interface|let|new|null|package|private|protected|public|return|set|static|super|switch|this|throw|true|try|typeof|var|void|while|with|yield)\b/g,number:/\b-?(0x[\dA-Fa-f]+|\d*\.?\d+([Ee]-?\d+)?|NaN|-?Infinity)\b/g});Prism.languages.insertBefore("javascript","keyword",{regex:{pattern:/(^|[^/])\/(?!\/)(\[.+?]|\\.|[^/\r\n])+\/[gim]{0,3}(?=\s*($|[\r\n,.;})]))/g,lookbehind:!0}});Prism.languages.markup&&Prism.languages.insertBefore("markup","tag",{script:{pattern:/[\w\W]*?<\/script>/gi,inside:{tag:{pattern:/|<\/script>/gi,inside:Prism.languages.markup.tag.inside},rest:Prism.languages.javascript}}});Prism.languages.scss=Prism.languages.extend("css",{comment:{pattern:/(^|[^\\])(\/\*[\w\W]*?\*\/|\/\/.*?(\r?\n|$))/g,lookbehind:!0},atrule:/@[\w-]+(?=\s+(\(|\{|;))/gi,url:/([-a-z]+-)*url(?=\()/gi,selector:/([^@;\{\}\(\)]?([^@;\{\}\(\)]|&|\#\{\$[-_\w]+\})+)(?=\s*\{(\}|\s|[^\}]+(:|\{)[^\}]+))/gm});Prism.languages.insertBefore("scss","atrule",{keyword:/@(if|else if|else|for|each|while|import|extend|debug|warn|mixin|include|function|return|content)|(?=@for\s+\$[-_\w]+\s)+from/i});Prism.languages.insertBefore("scss","property",{variable:/((\$[-_\w]+)|(#\{\$[-_\w]+\}))/i});Prism.languages.insertBefore("scss","ignore",{placeholder:/%[-_\w]+/i,statement:/\B!(default|optional)\b/gi,"boolean":/\b(true|false)\b/g,"null":/\b(null)\b/g,operator:/\s+([-+]{1,2}|={1,2}|!=|\|?\||\?|\*|\/|\%)\s+/g}); -------------------------------------------------------------------------------- /docs/sass/assets/js/search.js: -------------------------------------------------------------------------------- 1 | (function ($, global) { 2 | 3 | var Search = function (conf) { 4 | this.conf = $.extend({ 5 | // Search DOM 6 | search: { 7 | items: '.sassdoc__item', 8 | input: '#js-search-input', 9 | form: '#js-search', 10 | suggestionsWrapper: '#js-search-suggestions' 11 | }, 12 | 13 | // Fuse options 14 | fuse: { 15 | keys: ['name'], 16 | threshold: 0.3 17 | }, 18 | 19 | init: true 20 | }, conf || {}); 21 | 22 | if (this.conf.init === true) { 23 | this.initialize(); 24 | } 25 | }; 26 | 27 | Search.prototype.initialize = function () { 28 | // Fuse engine instanciation 29 | this.index = new Fuse($.map($(this.conf.search.items), function (item) { 30 | var $item = $(item); 31 | 32 | return { 33 | name: $item.data('name'), 34 | type: $item.data('type'), 35 | node: $item 36 | }; 37 | }), this.conf.fuse); 38 | 39 | this.initializeSearch(); 40 | }; 41 | 42 | // Fill DOM with search suggestions 43 | Search.prototype.fillSuggestions = function (items) { 44 | var searchSuggestions = $(this.conf.search.suggestionsWrapper); 45 | searchSuggestions.html(''); 46 | 47 | var suggestions = $.map(items.slice(0, 10), function (item) { 48 | var $li = $('
  • ', { 49 | 'data-type': item.type, 50 | 'data-name': item.name, 51 | 'html': '' + item.type.slice(0, 3) + ' ' + item.name + '' 52 | }); 53 | 54 | searchSuggestions.append($li); 55 | return $li; 56 | }); 57 | 58 | return suggestions; 59 | }; 60 | 61 | // Perform a search on a given term 62 | Search.prototype.search = function (term) { 63 | return this.fillSuggestions(this.index.search(term)); 64 | }; 65 | 66 | // Search logic 67 | Search.prototype.initializeSearch = function () { 68 | var searchForm = $(this.conf.search.form); 69 | var searchInput = $(this.conf.search.input); 70 | var searchSuggestions = $(this.conf.search.suggestionsWrapper); 71 | 72 | var currentSelection = -1; 73 | var suggestions = []; 74 | var selected; 75 | 76 | var self = this; 77 | 78 | // Clicking on a suggestion 79 | searchSuggestions.on('click', function (e) { 80 | var target = $(event.target); 81 | 82 | if (target.nodeName === 'A') { 83 | searchInput.val(target.parent().data('name')); 84 | suggestions = self.fillSuggestions([]); 85 | } 86 | }); 87 | 88 | // Filling the form 89 | searchForm.on('keyup', function (e) { 90 | e.preventDefault(); 91 | 92 | // Enter 93 | if (e.keyCode === 13) { 94 | if (selected) { 95 | suggestions = self.fillSuggestions([]); 96 | searchInput.val(selected.data('name')); 97 | window.location = selected.children().first().attr('href'); 98 | } 99 | 100 | e.stopPropagation(); 101 | } 102 | 103 | // KeyDown 104 | if (e.keyCode === 40) { 105 | currentSelection = (currentSelection + 1) % suggestions.length; 106 | } 107 | 108 | // KeyUp 109 | if (e.keyCode === 38) { 110 | currentSelection = currentSelection - 1; 111 | 112 | if (currentSelection < 0) { 113 | currentSelection = suggestions.length - 1; 114 | } 115 | } 116 | 117 | if (suggestions[currentSelection]) { 118 | if (selected) { 119 | selected.removeClass('selected'); 120 | } 121 | 122 | selected = suggestions[currentSelection]; 123 | selected.addClass('selected'); 124 | } 125 | 126 | }); 127 | 128 | searchInput.on('keyup', function (e) { 129 | if (e.keyCode !== 40 && e.keyCode !== 38) { 130 | currentSelection = -1; 131 | suggestions = self.search($(this).val()); 132 | } 133 | 134 | else { 135 | e.preventDefault(); 136 | } 137 | }).on('search', function () { 138 | suggestions = self.search($(this).val()); 139 | }); 140 | }; 141 | 142 | global.Search = Search; 143 | 144 | }(window.jQuery, window)); -------------------------------------------------------------------------------- /docs/sass/assets/js/sidebar.js: -------------------------------------------------------------------------------- 1 | (function ($, global) { 2 | 3 | var Sidebar = function (conf) { 4 | this.conf = $.extend({ 5 | 6 | // Collapsed class 7 | collapsedClass: 'is-collapsed', 8 | 9 | // Storage key 10 | storageKey: '_sassdoc_sidebar_index', 11 | 12 | // Index attribute 13 | indexAttribute: 'data-slug', 14 | 15 | // Toggle button 16 | toggleBtn: '.js-btn-toggle', 17 | 18 | // Automatic initialization 19 | init: true 20 | }, conf || {}); 21 | 22 | if (this.conf.init === true) { 23 | this.initialize(); 24 | } 25 | }; 26 | 27 | /** 28 | * Initialize module 29 | */ 30 | Sidebar.prototype.initialize = function () { 31 | this.conf.nodes = $('[' + this.conf.indexAttribute + ']'); 32 | 33 | this.load(); 34 | this.updateDOM(); 35 | this.bind(); 36 | this.loadToggle(); 37 | }; 38 | 39 | 40 | /** 41 | * Load sidebar toggle 42 | */ 43 | Sidebar.prototype.loadToggle = function () { 44 | $('', { 45 | 'class': 'layout-toggle', 46 | 'html': '×', 47 | 'data-alt': '☰' 48 | }).appendTo( $('.header') ); 49 | 50 | $('.layout-toggle').on('click', function () { 51 | var $this = $(this); 52 | var alt; 53 | 54 | $('body').toggleClass('sidebar-closed'); 55 | 56 | alt = $this.html(); 57 | $this.html($this.data('alt')); 58 | $this.data('alt', alt); 59 | }); 60 | }; 61 | 62 | /** 63 | * Load data from storage or create fresh index 64 | */ 65 | Sidebar.prototype.load = function () { 66 | var index = 'localStorage' in global ? 67 | global.localStorage.getItem(this.conf.storageKey) : 68 | null; 69 | 70 | this.index = index ? JSON.parse(index) : this.buildIndex(); 71 | }; 72 | 73 | /** 74 | * Build a fresh index 75 | */ 76 | Sidebar.prototype.buildIndex = function () { 77 | var index = {}; 78 | var $item; 79 | 80 | this.conf.nodes.each($.proxy(function (index, item) { 81 | $item = $(item); 82 | 83 | index[$item.attr(this.conf.indexAttribute)] = !$item.hasClass(this.conf.collapsedClass); 84 | }, this)); 85 | 86 | return index; 87 | }; 88 | 89 | /** 90 | * Update DOM based on index 91 | */ 92 | Sidebar.prototype.updateDOM = function () { 93 | var item; 94 | 95 | for (item in this.index) { 96 | if (this.index[item] === false) { 97 | $('[' + this.conf.indexAttribute + '="' + item + '"]').addClass(this.conf.collapsedClass); 98 | } 99 | } 100 | }; 101 | 102 | /** 103 | * Save index in storage 104 | */ 105 | Sidebar.prototype.save = function () { 106 | if (!('localStorage' in global)) { 107 | return; 108 | } 109 | 110 | global.localStorage.setItem(this.conf.storageKey, JSON.stringify(this.index)); 111 | }; 112 | 113 | /** 114 | * Bind UI events 115 | */ 116 | Sidebar.prototype.bind = function () { 117 | var $item, slug, fn, text; 118 | var collapsed = false; 119 | 120 | // Save index in localStorage 121 | global.onbeforeunload = $.proxy(function () { 122 | this.save(); 123 | }, this); 124 | 125 | // Toggle all 126 | $(this.conf.toggleBtn).on('click', $.proxy(function (event) { 127 | $node = $(event.target); 128 | 129 | text = $node.attr('data-alt'); 130 | $node.attr('data-alt', $node.text()); 131 | $node.text(text); 132 | 133 | fn = collapsed === true ? 'removeClass' : 'addClass'; 134 | 135 | this.conf.nodes.each($.proxy(function (index, item) { 136 | $item = $(item); 137 | slug = $item.attr(this.conf.indexAttribute); 138 | 139 | this.index[slug] = collapsed; 140 | 141 | $('[' + this.conf.indexAttribute + '="' + slug + '"]')[fn](this.conf.collapsedClass); 142 | }, this)); 143 | 144 | collapsed = !collapsed; 145 | this.save(); 146 | }, this)); 147 | 148 | // Toggle item 149 | this.conf.nodes.on('click', $.proxy(function (event) { 150 | $item = $(event.target); 151 | slug = $item.attr(this.conf.indexAttribute); 152 | 153 | // Update index 154 | this.index[slug] = !this.index[slug]; 155 | 156 | // Update DOM 157 | $item.toggleClass(this.conf.collapsedClass); 158 | }, this)); 159 | }; 160 | 161 | global.Sidebar = Sidebar; 162 | 163 | }(window.jQuery, window)); 164 | -------------------------------------------------------------------------------- /docs/sass/assets/js/vendor/fuse.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Fuse - Lightweight fuzzy-search 4 | * 5 | * Copyright (c) 2012 Kirollos Risk . 6 | * All Rights Reserved. Apache Software License 2.0 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | */ 20 | !function(t){function e(t,n){this.list=t,this.options=n=n||{};var i,o,s;for(i=0,keys=["sort","includeScore","shouldSort"],o=keys.length;o>i;i++)s=keys[i],this.options[s]=s in n?n[s]:e.defaultOptions[s];for(i=0,keys=["searchFn","sortFn","keys","getFn"],o=keys.length;o>i;i++)s=keys[i],this.options[s]=n[s]||e.defaultOptions[s]}var n=function(t,e){if(e=e||{},this.options=e,this.options.location=e.location||n.defaultOptions.location,this.options.distance="distance"in e?e.distance:n.defaultOptions.distance,this.options.threshold="threshold"in e?e.threshold:n.defaultOptions.threshold,this.options.maxPatternLength=e.maxPatternLength||n.defaultOptions.maxPatternLength,this.pattern=e.caseSensitive?t:t.toLowerCase(),this.patternLen=t.length,this.patternLen>this.options.maxPatternLength)throw new Error("Pattern length is too long");this.matchmask=1<i;)this._bitapScore(e,l+o)<=u?i=o:d=o,o=Math.floor((d-i)/2+i);for(d=o,s=Math.max(1,l-o+1),r=Math.min(l+o,c)+this.patternLen,a=Array(r+2),a[r+1]=(1<=s;n--)if(p=this.patternAlphabet[t.charAt(n-1)],a[n]=0===e?(a[n+1]<<1|1)&p:(a[n+1]<<1|1)&p|((h[n+1]|h[n])<<1|1)|h[n+1],a[n]&this.matchmask&&(g=this._bitapScore(e,n-1),u>=g)){if(u=g,f=n-1,m.push(f),!(f>l))break;s=Math.max(1,2*l-f)}if(this._bitapScore(e+1,l)>u)break;h=a}return{isMatch:f>=0,score:g}};var i={deepValue:function(t,e){for(var n=0,e=e.split("."),i=e.length;i>n;n++){if(!t)return null;t=t[e[n]]}return t}};e.defaultOptions={id:null,caseSensitive:!1,includeScore:!1,shouldSort:!0,searchFn:n,sortFn:function(t,e){return t.score-e.score},getFn:i.deepValue,keys:[]},e.prototype.search=function(t){var e,n,o,s,r,a=new this.options.searchFn(t,this.options),h=this.list,p=h.length,c=this.options,l=this.options.keys,u=l.length,f=[],d={},g=[],m=function(t,e,n){void 0!==t&&null!==t&&"string"==typeof t&&(s=a.search(t),s.isMatch&&(r=d[n],r?r.score=Math.min(r.score,s.score):(d[n]={item:e,score:s.score},f.push(d[n]))))};if("string"==typeof h[0])for(var e=0;p>e;e++)m(h[e],e,e);else for(var e=0;p>e;e++)for(o=h[e],n=0;u>n;n++)m(this.options.getFn(o,l[n]),o,e);c.shouldSort&&f.sort(c.sortFn);for(var y=c.includeScore?function(t){return f[t]}:function(t){return f[t].item},L=c.id?function(t){return i.deepValue(y(t),c.id)}:function(t){return y(t)},e=0,v=f.length;v>e;e++)g.push(L(e));return g},"object"==typeof exports?module.exports=e:"function"==typeof define&&define.amd?define(function(){return e}):t.Fuse=e}(this); -------------------------------------------------------------------------------- /docs/sass/assets/js/vendor/prism.min.js: -------------------------------------------------------------------------------- 1 | /* http://prismjs.com/download.html?themes=prism&languages=markup+css+css-extras+clike+javascript+scss */ 2 | var self=typeof window!="undefined"?window:{},Prism=function(){var e=/\blang(?:uage)?-(?!\*)(\w+)\b/i,t=self.Prism={util:{encode:function(e){return e instanceof n?new n(e.type,t.util.encode(e.content)):t.util.type(e)==="Array"?e.map(t.util.encode):e.replace(/&/g,"&").replace(/e.length)break e;if(p instanceof i)continue;a.lastIndex=0;var d=a.exec(p);if(d){l&&(c=d[1].length);var v=d.index-1+c,d=d[0].slice(c),m=d.length,g=v+m,y=p.slice(0,v+1),b=p.slice(g+1),w=[h,1];y&&w.push(y);var E=new i(u,f?t.tokenize(d,f):d);w.push(E);b&&w.push(b);Array.prototype.splice.apply(s,w)}}}return s},hooks:{all:{},add:function(e,n){var r=t.hooks.all;r[e]=r[e]||[];r[e].push(n)},run:function(e,n){var r=t.hooks.all[e];if(!r||!r.length)return;for(var i=0,s;s=r[i++];)s(n)}}},n=t.Token=function(e,t){this.type=e;this.content=t};n.stringify=function(e,r,i){if(typeof e=="string")return e;if(Object.prototype.toString.call(e)=="[object Array]")return e.map(function(t){return n.stringify(t,r,e)}).join("");var s={type:e.type,content:n.stringify(e.content,r,i),tag:"span",classes:["token",e.type],attributes:{},language:r,parent:i};s.type=="comment"&&(s.attributes.spellcheck="true");t.hooks.run("wrap",s);var o="";for(var u in s.attributes)o+=u+'="'+(s.attributes[u]||"")+'"';return"<"+s.tag+' class="'+s.classes.join(" ")+'" '+o+">"+s.content+""};if(!self.document){if(!self.addEventListener)return self.Prism;self.addEventListener("message",function(e){var n=JSON.parse(e.data),r=n.language,i=n.code;self.postMessage(JSON.stringify(t.tokenize(i,t.languages[r])));self.close()},!1);return self.Prism}var r=document.getElementsByTagName("script");r=r[r.length-1];if(r){t.filename=r.src;document.addEventListener&&!r.hasAttribute("data-manual")&&document.addEventListener("DOMContentLoaded",t.highlightAll)}return self.Prism}();typeof module!="undefined"&&module.exports&&(module.exports=Prism);; 3 | Prism.languages.markup={comment://g,prolog:/<\?.+?\?>/,doctype://,cdata://i,tag:{pattern:/<\/?[\w:-]+\s*(?:\s+[\w:-]+(?:=(?:("|')(\\?[\w\W])*?\1|[^\s'">=]+))?\s*)*\/?>/gi,inside:{tag:{pattern:/^<\/?[\w:-]+/i,inside:{punctuation:/^<\/?/,namespace:/^[\w-]+?:/}},"attr-value":{pattern:/=(?:('|")[\w\W]*?(\1)|[^\s>]+)/gi,inside:{punctuation:/=|>|"/g}},punctuation:/\/?>/g,"attr-name":{pattern:/[\w:-]+/g,inside:{namespace:/^[\w-]+?:/}}}},entity:/\&#?[\da-z]{1,8};/gi};Prism.hooks.add("wrap",function(e){e.type==="entity"&&(e.attributes.title=e.content.replace(/&/,"&"))});; 4 | Prism.languages.css={comment:/\/\*[\w\W]*?\*\//g,atrule:{pattern:/@[\w-]+?.*?(;|(?=\s*{))/gi,inside:{punctuation:/[;:]/g}},url:/url\((["']?).*?\1\)/gi,selector:/[^\{\}\s][^\{\};]*(?=\s*\{)/g,property:/(\b|\B)[\w-]+(?=\s*:)/ig,string:/("|')(\\?.)*?\1/g,important:/\B!important\b/gi,punctuation:/[\{\};:]/g,"function":/[-a-z0-9]+(?=\()/ig};Prism.languages.markup&&Prism.languages.insertBefore("markup","tag",{style:{pattern:/[\w\W]*?<\/style>/ig,inside:{tag:{pattern:/|<\/style>/ig,inside:Prism.languages.markup.tag.inside},rest:Prism.languages.css}}});; 5 | Prism.languages.css.selector={pattern:/[^\{\}\s][^\{\}]*(?=\s*\{)/g,inside:{"pseudo-element":/:(?:after|before|first-letter|first-line|selection)|::[-\w]+/g,"pseudo-class":/:[-\w]+(?:\(.*\))?/g,"class":/\.[-:\.\w]+/g,id:/#[-:\.\w]+/g}};Prism.languages.insertBefore("css","ignore",{hexcode:/#[\da-f]{3,6}/gi,entity:/\\[\da-f]{1,8}/gi,number:/[\d%\.]+/g});; 6 | Prism.languages.clike={comment:{pattern:/(^|[^\\])(\/\*[\w\W]*?\*\/|(^|[^:])\/\/.*?(\r?\n|$))/g,lookbehind:!0},string:/("|')(\\?.)*?\1/g,"class-name":{pattern:/((?:(?:class|interface|extends|implements|trait|instanceof|new)\s+)|(?:catch\s+\())[a-z0-9_\.\\]+/ig,lookbehind:!0,inside:{punctuation:/(\.|\\)/}},keyword:/\b(if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\b/g,"boolean":/\b(true|false)\b/g,"function":{pattern:/[a-z0-9_]+\(/ig,inside:{punctuation:/\(/}},number:/\b-?(0x[\dA-Fa-f]+|\d*\.?\d+([Ee]-?\d+)?)\b/g,operator:/[-+]{1,2}|!|<=?|>=?|={1,3}|&{1,2}|\|?\||\?|\*|\/|\~|\^|\%/g,ignore:/&(lt|gt|amp);/gi,punctuation:/[{}[\];(),.:]/g};; 7 | Prism.languages.javascript=Prism.languages.extend("clike",{keyword:/\b(break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|false|finally|for|function|get|if|implements|import|in|instanceof|interface|let|new|null|package|private|protected|public|return|set|static|super|switch|this|throw|true|try|typeof|var|void|while|with|yield)\b/g,number:/\b-?(0x[\dA-Fa-f]+|\d*\.?\d+([Ee]-?\d+)?|NaN|-?Infinity)\b/g});Prism.languages.insertBefore("javascript","keyword",{regex:{pattern:/(^|[^/])\/(?!\/)(\[.+?]|\\.|[^/\r\n])+\/[gim]{0,3}(?=\s*($|[\r\n,.;})]))/g,lookbehind:!0}});Prism.languages.markup&&Prism.languages.insertBefore("markup","tag",{script:{pattern:/[\w\W]*?<\/script>/ig,inside:{tag:{pattern:/|<\/script>/ig,inside:Prism.languages.markup.tag.inside},rest:Prism.languages.javascript}}}); 8 | ; 9 | Prism.languages.scss=Prism.languages.extend("css",{comment:{pattern:/(^|[^\\])(\/\*[\w\W]*?\*\/|\/\/.*?(\r?\n|$))/g,lookbehind:!0},atrule:/@[\w-]+(?=\s+(\(|\{|;))/gi,url:/([-a-z]+-)*url(?=\()/gi,selector:/([^@;\{\}\(\)]?([^@;\{\}\(\)]|&|\#\{\$[-_\w]+\})+)(?=\s*\{(\}|\s|[^\}]+(:|\{)[^\}]+))/gm});Prism.languages.insertBefore("scss","atrule",{keyword:/@(if|else if|else|for|each|while|import|extend|debug|warn|mixin|include|function|return|content)|(?=@for\s+\$[-_\w]+\s)+from/i});Prism.languages.insertBefore("scss","property",{variable:/((\$[-_\w]+)|(#\{\$[-_\w]+\}))/i});Prism.languages.insertBefore("scss","ignore",{placeholder:/%[-_\w]+/i,statement:/\B!(default|optional)\b/gi,"boolean":/\b(true|false)\b/g,"null":/\b(null)\b/g,operator:/\s+([-+]{1,2}|={1,2}|!=|\|?\||\?|\*|\/|\%)\s+/g});; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@onenexus/cell", 3 | "version": "1.0.0-beta.21", 4 | "description": "Style BEM DOM elements using Sass", 5 | "main": "dist/_synergy.scss", 6 | "author": "(Edmund Reed)[http://twitter.com/esr360] ", 7 | "homepage": "https://github.com/One-Nexus/Cell", 8 | "keywords": [ 9 | "sass", 10 | "scss", 11 | "OOCSS", 12 | "BEM", 13 | "modular", 14 | "modules", 15 | "components", 16 | "front-end", 17 | "framework", 18 | "web", 19 | "synergy" 20 | ], 21 | "bugs": { 22 | "url": "https://github.com/One-Nexus/Cell/issues" 23 | }, 24 | "license": "MIT", 25 | "repository": { 26 | "type": "git", 27 | "url": "https://github.com/One-Nexus/Cell.git" 28 | }, 29 | "dependencies": { 30 | "@onenexus/synergy-sass-importer": "^1.0.0-beta.9", 31 | "Sass-Boost": "^1.1.0" 32 | }, 33 | "devDependencies": { 34 | "concat": "^1.0.3", 35 | "mocha": "^6.2.2", 36 | "node-sass": "^4.13.1", 37 | "sass-true": "^5.0.0", 38 | "sassdoc": "^2.5.0", 39 | "sassdoc-theme-flippant": "^0.1.0", 40 | "stylelint": "^8.4.0" 41 | }, 42 | "scripts": { 43 | "lint": "stylelint src/**/*.scss", 44 | "test": "mocha test/tests.js", 45 | "docs": "sassdoc src/ -d docs/sass --theme flippant", 46 | "sass": "node ./build/sass-concat.js", 47 | "build": "npm run lint && npm test && npm run docs && npm run sass" 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/_cell.scss: -------------------------------------------------------------------------------- 1 | ///**************************************************************** 2 | /// Synergy - https://github.com/One-Nexus/Cell 3 | /// 4 | /// @author [@esr360](http://twitter.com/esr360) 5 | ///**************************************************************** 6 | 7 | @import '../node_modules/Sass-Boost/src/sass-boost'; 8 | 9 | @import 'config'; 10 | 11 | @import 'atoms/display'; 12 | @import 'atoms/position'; 13 | @import 'atoms/visibility'; 14 | 15 | @import 'utilities/create-config'; 16 | @import 'utilities/create-selector-from-context'; 17 | @import 'utilities/css-properties'; 18 | @import 'utilities/enabled'; 19 | @import 'utilities/parse-cq'; 20 | @import 'utilities/get-module-name'; 21 | @import 'utilities/get-param'; 22 | @import 'utilities/merge-css-maps'; 23 | @import 'utilities/module-tree'; 24 | @import 'utilities/option'; 25 | @import 'utilities/remove-junk'; 26 | @import 'utilities/remove-modifiers'; 27 | @import 'utilities/selector-to-map'; 28 | @import 'utilities/setting'; 29 | @import 'utilities/strip-glue'; 30 | @import 'utilities/theme'; 31 | @import 'utilities/this'; 32 | @import 'utilities/value-enabled'; 33 | 34 | @import 'mixins/module'; 35 | @import 'mixins/component'; 36 | @import 'mixins/modifier'; 37 | @import 'mixins/extend'; 38 | @import 'mixins/context'; 39 | @import 'mixins/option'; 40 | @import 'mixins/pseudo-state'; 41 | @import 'mixins/value'; 42 | @import 'mixins/wrapper'; -------------------------------------------------------------------------------- /src/_config.scss: -------------------------------------------------------------------------------- 1 | // Prepend all selectors with a namespace 2 | $moduleNamespace: null !default; 3 | 4 | // Set the glue to chain modifiers to modules 5 | $modifierGlue: '--' !default; 6 | 7 | // Set the glue to chain components to modules 8 | $componentGlue: '__' !default; 9 | 10 | // Extend each module option as a modifier by default? 11 | $extendOptions: true !default; 12 | 13 | // Custom parser to use for configuration 14 | $sassConfigParser: null !default; 15 | 16 | // Automatically generate CSS from module configuration 17 | $outputCSSFromConfig: false !default; 18 | 19 | // The variable to hold a single module (do not edit) 20 | $module: null !default; -------------------------------------------------------------------------------- /src/atoms/_display.scss: -------------------------------------------------------------------------------- 1 | /// Cell Atom - Display property 2 | /// 3 | /// @param {list} $context - The desired context/condition 4 | /// @param {*} $default - The default value to use when the context is not met 5 | /// @param {*} $value - The value to use when the context is met 6 | @mixin display($context, $value, $default) { 7 | display: $default; 8 | 9 | @include context($context...) { 10 | display: $value; 11 | } 12 | } -------------------------------------------------------------------------------- /src/atoms/_position.scss: -------------------------------------------------------------------------------- 1 | /// Cell Atom - Position property 2 | /// 3 | /// @param {list} $context - The desired context/condition 4 | /// @param {*} $default - The default value to use when the context is not met 5 | /// @param {*} $value - The value to use when the context is met 6 | @mixin position($context, $value, $default) { 7 | position: $default; 8 | 9 | @include context($context...) { 10 | position: $value; 11 | } 12 | } -------------------------------------------------------------------------------- /src/atoms/_visibility.scss: -------------------------------------------------------------------------------- 1 | /// Cell Atom - Visibility property 2 | /// 3 | /// @param {list} $context - The desired context/condition 4 | /// @param {*} $default - The default value to use when the context is not met 5 | /// @param {*} $value - The value to use when the context is met 6 | @mixin visibility($context, $value, $default) { 7 | visibility: $default; 8 | 9 | @include context($context...) { 10 | visibility: $value; 11 | } 12 | } -------------------------------------------------------------------------------- /src/mixins/_component.scss: -------------------------------------------------------------------------------- 1 | /// Create a component based off the main module 2 | /// 3 | /// @param {string|list} $components - The component or components to be used 4 | /// @param {map} $content 5 | /// @param {bool} $sub-component 6 | /// @param {string} $glue 7 | /// @param {bool} $cascade 8 | @mixin component( 9 | $components: null, 10 | $content: (), 11 | $sub-component: false, 12 | $glue: $componentGlue, 13 | $cascade: true 14 | ) { 15 | $this: &; 16 | $module-map: selector-to-map($this); 17 | $selectors: '[class*="#{$module}#{$glue}"]'; 18 | $namespace: map-get($module-map, 'module'); 19 | 20 | @if str-index($namespace, '%') == 1 { 21 | $namespace: $module; 22 | } 23 | 24 | @if $sub-component { 25 | $namespace: nth(module-tree(&), length(module-tree(&))); 26 | } 27 | 28 | @if $components { 29 | $selectors: (); 30 | 31 | @each $component in $components { 32 | $selector: '.#{$namespace}#{$glue}#{$component}, [class*="#{$namespace}#{$glue}#{$component}#{$modifierGlue}"]'; 33 | 34 | @if not $cascade { 35 | $selector: '> #{$selector}'; 36 | } 37 | 38 | $selectors: join($selectors, $selector, comma); 39 | } 40 | } 41 | 42 | $parents: (); 43 | 44 | @each $selector in & { 45 | // spoof the selector into a list 46 | $selector: selector-parse(str-replace(inspect($selector), ' ', ', ')); 47 | 48 | $is-modifier: str-index(inspect(nth($selector, length($selector))), '[class*="#{$modifierGlue}'); 49 | $is-pseudo-state: str-index(inspect(nth($selector, length($selector))), ':'); 50 | 51 | // if the last item isn't a modifier or pseudo state, remove it 52 | @if not ($is-modifier or $is-pseudo-state) { 53 | $selector: list-remove($selector, nth($selector, length($selector))); 54 | } 55 | 56 | @if length($selector) == 1 { 57 | $selector: nth($selector, 1); 58 | } 59 | 60 | // Re-build the parent selector 61 | $parents: append($parents, str-replace(inspect($selector), ', ', ' '), comma); 62 | } 63 | 64 | $parents: list-remove-duplicates($parents); 65 | 66 | @if length($parents) == 1 { 67 | $parents: nth($parents, 1); 68 | } 69 | 70 | @if ($parents == '()') { 71 | @at-root #{$selectors} { 72 | @content; 73 | 74 | @include parse-cq($content); 75 | } 76 | } 77 | @else { 78 | @at-root #{$parents} { 79 | #{$selectors} { 80 | @content; 81 | 82 | @include parse-cq($content); 83 | } 84 | } 85 | } 86 | } 87 | 88 | /// Alis for `component` mixin with $sub-component: true 89 | /// 90 | /// @param {string|list} $components 91 | /// @param {map} $content 92 | /// @param {string} $glue 93 | @mixin sub-component($components: null, $content: (), $glue: $componentGlue) { 94 | @include component($components, $content, true, $glue) { 95 | @content; 96 | } 97 | } 98 | 99 | /// Alias for component() mixin 100 | /// 101 | /// @author [@esr360](http://twitter.com/esr360) 102 | /// @access public 103 | @mixin components($args...) { 104 | @include component($args...) { 105 | @content; 106 | } 107 | } -------------------------------------------------------------------------------- /src/mixins/_context.scss: -------------------------------------------------------------------------------- 1 | /// Apply styles to a component within a certain context 2 | /// 3 | /// @param {arglist} $context 4 | @mixin context($context...) { 5 | $selector: create-selector-from-context($context...); 6 | $scope: &; 7 | 8 | @at-root #{$selector} { 9 | #{$scope} { 10 | @content; 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /src/mixins/_extend.scss: -------------------------------------------------------------------------------- 1 | /// Extend one or more modifiers of a module to create a new modifier 2 | /// combining the ones you pass 3 | /// 4 | /// @param {string|list} $modifiers [null] - The modifiers which you wish to combine 5 | /// @param {string} $parent [null] - The parent module if not current one 6 | /// @param {bool} $core [false] - Extend the core '.module' styles? 7 | @mixin extend($modifiers: null, $parent: null, $core: false) { 8 | $namespaced-parent: if($moduleNamespace and $parent, $moduleNamespace + $parent, $parent); 9 | 10 | @if $core or not $modifiers { 11 | @extend .#{$namespaced-parent}; 12 | } 13 | 14 | @each $modifier in $modifiers { 15 | @if type-of($modifier) == 'string' { 16 | $selector: if($parent, $namespaced-parent, $module); 17 | 18 | @extend [class*="#{$selector}#{$modifierGlue}"][class*="#{$modifierGlue}#{$modifier}"]; 19 | } 20 | @else if type-of($modifier) == 'list' { 21 | $namespaced-selector: ('[class*="#{$namespaced-parent}#{$modifierGlue}"]'); 22 | $module-selector: ('[class*="#{$module}#{$modifierGlue}"]'); 23 | 24 | $selectors: if($parent, $namespaced-selector, $module-selector); 25 | 26 | @each $item in $modifier { 27 | $selectors: join($selectors, '[class*="#{$modifierGlue}#{$item}"]', comma); 28 | } 29 | 30 | @extend #{$selectors}; 31 | } 32 | } 33 | } 34 | 35 | // Alias for extending entire modules 36 | @mixin _module($module, $modifiers: null, $core: true) { 37 | @include extend($parent: $module, $modifiers: $modifiers, $core: $core); 38 | } -------------------------------------------------------------------------------- /src/mixins/_modifier.scss: -------------------------------------------------------------------------------- 1 | /// Create a modifier for a module 2 | /// 3 | /// @param {string|list} $modifiers - The modifier(s) which you wish to create 4 | /// @param {string} $special [null] - Add special contextual options to modifier 5 | /// @param {bool} $glue ['--'] - Desired modifier separator/glue 6 | /// @param {string} $module 7 | @mixin modifier($modifiers, $special: null, $glue: $modifierGlue, $module: $module) { 8 | $scope: &; 9 | 10 | @if str-index(inspect(&), '.#{$module}') { 11 | $scope: (); 12 | 13 | @for $i from 1 through length(&) { 14 | @if $i % 2 == 0 { 15 | $scope: append($scope, nth(&, $i), comma); 16 | } 17 | } 18 | } 19 | 20 | $modifiers-chunk: (); 21 | 22 | @each $modifier in $modifiers { 23 | @if $special == 'not' { 24 | $modifiers-chunk: join($modifiers-chunk, ':not([class*="#{$glue}#{$modifier}"])', comma); 25 | } 26 | @else { 27 | $modifiers-chunk: join($modifiers-chunk, '[class*="#{$glue}#{$modifier}"]', comma); 28 | } 29 | 30 | $selector: #{$scope}#{$modifiers-chunk}; 31 | 32 | // pseudo-elements must be at the end 33 | @if str-index($selector, ':before') and str-index($selector, ':before') != (str-length($selector) - 6) { 34 | $selector: str-replace($selector, ':before', '') + ':before'; 35 | } 36 | @if str-index($selector, ':after') and str-index($selector, ':after') != (str-length($selector) - 5) { 37 | $selector: str-replace($selector, ':after', '') + ':after'; 38 | } 39 | 40 | @at-root #{$selector} { 41 | @content; 42 | } 43 | } 44 | } 45 | 46 | /// Alias for modifier() mixin 47 | @mixin modifiers($args...) { 48 | @include modifier($args...) { 49 | @content; 50 | } 51 | } 52 | 53 | /// Alias for modifier() mixin 54 | @mixin is($args...) { 55 | @include modifier($args...) { 56 | @content; 57 | } 58 | } -------------------------------------------------------------------------------- /src/mixins/_module.scss: -------------------------------------------------------------------------------- 1 | /// Create a new module 2 | /// 3 | /// @param {string|list} $modules - The module(s) you wish to create 4 | /// @param {map} $content 5 | @mixin module( 6 | $modules: if(variable-exists('config'), (map-get($config, 'name')), ''), 7 | $content: () 8 | ) { 9 | $config: () !default; 10 | 11 | @if type-of($modules) == 'map' { 12 | $modules: if(variable-exists('config'), (map-get($config, 'name')), ''); 13 | } 14 | 15 | @if ($moduleNamespace) { 16 | $modules: $moduleNamespace + $modules; 17 | } 18 | 19 | // disable any output 20 | $disable-output: if(variable-exists('disable-output'), $disable-output, false); 21 | 22 | @if variable-exists('config') and map-has-key($config, 'disable-output') { 23 | $disable-output: map-get($config, 'disable-output'); 24 | } 25 | 26 | // @TODO this needs to identify if nested within itself, not nested in general 27 | $nested: &; 28 | 29 | // We are creating a root module, so create a global variable 30 | @if not $nested { 31 | $module: $modules !global; 32 | $this: $module !global; 33 | } 34 | 35 | $selectors: (); 36 | 37 | @each $module in $modules { 38 | $selectors: join($selectors, '.#{$module}', comma); 39 | $selectors: join($selectors, '[class*="#{$module}#{$modifierGlue}"]', comma); 40 | } 41 | 42 | $targetExists: variable-exists('config') and map-has-key($config, 'target'); 43 | // @TODO tidy up how $target is used here and in $modifier - also probably won't work for component() 44 | $target: if($targetExists, ('module': $module, 'target': map-get($config, 'target')), false) !global; 45 | 46 | @if not $disable-output { 47 | #{$selectors} { 48 | @if not $nested { 49 | @include module-content($modules, $config, $target); 50 | } 51 | 52 | @content; 53 | 54 | @include parse-cq($content); 55 | } 56 | } 57 | } 58 | 59 | /// Render a module's content 60 | /// 61 | /// @param {string|list} $module 62 | /// @param {map} $config 63 | /// @param {*} $target 64 | @mixin module-content($module, $config, $target) { 65 | @include extend-modifiers; 66 | @include combine-modifiers; 67 | 68 | @if variable-exists('config') and $outputCSSFromConfig { 69 | @if $module == map-get($config, 'name') or $target { 70 | @if type-of($target) == 'map' and map-get($target, 'module') == $module { 71 | #{map-get($target, 'target')} { 72 | @include parse-cq($config); 73 | } 74 | } 75 | @else { 76 | @include parse-cq($config); 77 | } 78 | } 79 | } 80 | } 81 | 82 | /// Alias for module() mixin 83 | /// 84 | /// @param {string|list} $modules - The module(s) you wish to create 85 | @mixin modules($modules) { 86 | @include module($modules) { 87 | @content; 88 | } 89 | } 90 | 91 | /// Combine modifiers into a new, single modifier 92 | /// 93 | /// @param {map} $styles - The CSS styles to output 94 | @mixin combine-modifiers($combine: if(variable-exists('config'), (map-get($config, 'combine')), '()')) { 95 | @if variable-exists('config') and $combine { 96 | @each $new-modifier, $target-modifiers in $combine { 97 | @include modifier($new-modifier) { 98 | @include extend(($target-modifiers)); 99 | } 100 | } 101 | } 102 | } 103 | 104 | /// Extend modifiers into the naked module 105 | /// 106 | /// @param {map} $styles - The CSS styles to output 107 | @mixin extend-modifiers($modifiers: if(variable-exists('config'), (map-get($config, 'modifiers')), '()')) { 108 | @if variable-exists('config') and $modifiers { 109 | @include extend(($modifiers)); 110 | } 111 | } -------------------------------------------------------------------------------- /src/mixins/_option.scss: -------------------------------------------------------------------------------- 1 | /// Apply styles to a module if a passed option returns true 2 | /// 3 | /// @param {arglist} $option-path - The option which you wish to test against 4 | @mixin option($option-path...) { 5 | $value : map-get-deep($config, $option-path...); 6 | $option : nth($option-path, length($option-path)) !global; 7 | 8 | // Output the styles if the option is enabled 9 | @if value-enabled($value) { 10 | @content; 11 | 12 | @include parse-cq($value); 13 | } 14 | 15 | // Create a modifier for the option if it is not enabled 16 | // by default 17 | @if $extendOptions and not value-enabled($value) { 18 | @include modifier($option) { 19 | @content; 20 | 21 | @include parse-cq($value); 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /src/mixins/_pseudo-state.scss: -------------------------------------------------------------------------------- 1 | /// Used to generate selectors for pseudo states 2 | /// 3 | /// @param {string} $state 4 | @mixin pseudo-state($state) { 5 | $scope: &; 6 | $selector: (); 7 | 8 | @each $item in $scope { 9 | $chunk: '#{$item}:#{$state}'; 10 | 11 | // pseudo-elements must be at the end 12 | @if str-index($chunk, ':before') and str-index($chunk, ':before') != (str-length($chunk) - 5) { 13 | $chunk: str-replace($chunk, ':before', '') + ':before'; 14 | } 15 | @if str-index($chunk, ':after') and str-index($chunk, ':after') != (str-length($chunk) - 5) { 16 | $chunk: str-replace($chunk, ':after', '') + ':after'; 17 | } 18 | 19 | $selector: append($selector, $chunk, comma); 20 | } 21 | 22 | @at-root #{$selector} { 23 | @content; 24 | } 25 | } 26 | 27 | /// Alias for `pseudo-state` mixin with $state: 'hover' 28 | @mixin hover { 29 | @include pseudo-state('hover') { 30 | @content; 31 | } 32 | } -------------------------------------------------------------------------------- /src/mixins/_value.scss: -------------------------------------------------------------------------------- 1 | /// Apply styles when a defined option is a particular value 2 | /// 3 | /// @param $value - The value you wish to apply styles to 4 | @mixin value($value) { 5 | // Create a unique, random placeholder to store styles 6 | $placeholder : $value + random(9999); 7 | $get-option: option($config, $option); 8 | $target: if(type-of($get-option) == 'map', option($config, $option, 'enabled'), $get-option); 9 | 10 | // Determine if the option's value is our value of interest 11 | $enabled: if($target == $value, true, false); 12 | 13 | @if ($enabled) { 14 | @content; 15 | } 16 | 17 | // Create a modifier for the option 18 | @if $extendOptions and not $enabled { 19 | @include modifier($option) { 20 | @include modifier($value) { 21 | @content; 22 | } 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /src/mixins/_wrapper.scss: -------------------------------------------------------------------------------- 1 | /// Wrap a module or group a collection of modules 2 | /// 3 | /// @param {string} $namespace 4 | /// @param {string} $scope 5 | @mixin wrapper($namespace: 'wrapper', $scope: $module) { 6 | @at-root { 7 | @include module($namespace) { 8 | @include modifier($scope, $module: $namespace) { 9 | @content; 10 | } 11 | } 12 | } 13 | } 14 | 15 | /// Alias for wrapper() mixin 16 | @mixin group($scope: $module) { 17 | @include wrapper('group', $scope) { 18 | @content; 19 | } 20 | } -------------------------------------------------------------------------------- /src/utilities/_create-config.scss: -------------------------------------------------------------------------------- 1 | /// Used to merge a module's default configuration with any custom 2 | /// values passed to the module 3 | /// 4 | /// @param {map} $map-old - The map which holds default configuration 5 | /// @param {map} $map-new - The map which holds custom values 6 | /// @param {string} $parser - Custom parser to use for configuration 7 | @function create-config($map-old: (), $map-new: (), $parser: $sassConfigParser) { 8 | $map-old: map-merge(( 9 | 'extendOptions' : $extendOptions 10 | ), $map-old); 11 | 12 | // Merge theme values 13 | @if variable-exists('theme') and not variable-exists('CellThemeProcessed') { 14 | @if map-has-key($theme, 'modules') { 15 | $map-old: map-merge-deep($map-old, map-get-deep($theme, 'modules', map-get($map-old, 'name'))); 16 | } 17 | } 18 | 19 | // Merge default and custom options 20 | $map-merged: map-merge-deep($map-old, $map-new); 21 | 22 | // Evaluate configuration values 23 | $map-merged: eval-config($map-merged); 24 | 25 | // Evaluate configuration values 26 | @if ($parser) { 27 | $map-merged: call(get-function($parser), $map-merged); 28 | } 29 | 30 | // Store config in global variable 31 | $config: $map-merged !global; 32 | $smart-config: smart-config($config) !global; 33 | 34 | // Return merged map 35 | @return $map-merged; 36 | } 37 | 38 | /// Evaluate properties from function-calls 39 | @function eval-config($config) { 40 | $evaluated-config: (); 41 | 42 | @each $key, $value in $config { 43 | @if type-of($value) == 'map' { 44 | $evaluated-config: map-set($evaluated-config, $key, eval-config($value)); 45 | } 46 | 47 | @else { 48 | @if type-of($value) == 'list' and type-of(nth($value, 1)) == 'string' and function-exists(nth($value, 1)) { 49 | $value: call(get-function(nth($value, 1)), nth($value, 2)...); 50 | } 51 | 52 | $evaluated-config: map-set($evaluated-config, $key, $value); 53 | } 54 | } 55 | 56 | @return $evaluated-config; 57 | } 58 | 59 | /// Convert configuration keys such as `component(item)` into the 60 | /// paramater name, i.e. `item`, so they can be retreived with `this()` 61 | @function smart-config($config) { 62 | $smart-config: (); 63 | 64 | @each $key, $value in $config { 65 | @if type-of($value) == 'map' { 66 | $smart-config: map-set($smart-config, get-param($key), smart-config($value)); 67 | } 68 | 69 | @else { 70 | @if type-of($key) == 'string' { 71 | $key: get-param($key); 72 | } 73 | 74 | $smart-config: map-set($smart-config, $key, $value); 75 | } 76 | } 77 | 78 | @return $smart-config; 79 | } -------------------------------------------------------------------------------- /src/utilities/_create-selector-from-context.scss: -------------------------------------------------------------------------------- 1 | /// Used to create a selector from context() arguments 2 | /// 3 | /// @param {(string|list)} $block - The name of the module/component that has the context 4 | /// @param {string} $context - The context you wish to test 5 | /// @param {bool} $pipeContexts 6 | @function create-selector-from-context($block, $context: null, $pipeContexts: false) { 7 | $selector: (); 8 | $pipedContexts: ''; 9 | $excludeRootSelector: false; 10 | 11 | @if $context == '' { 12 | $context: null; 13 | } 14 | 15 | @if $pipeContexts { 16 | @each $item in $context { 17 | @if str-index($item, ':') == 1 { 18 | $pipedContexts: $pipedContexts + $item; 19 | } 20 | @else { 21 | $excludeRootSelector: true; 22 | $pipedContexts: $pipedContexts + '[class*="#{$modifierGlue}#{$item}"]'; 23 | } 24 | } 25 | @if type-of($block) == 'string' and not $excludeRootSelector { 26 | $selector: '.#{$block}#{$pipedContexts}, [class*="#{$block}#{$modifierGlue}"]#{$pipedContexts}'; 27 | } 28 | @else { 29 | $selector: '#{generate-chunk($block)}#{$pipedContexts}'; 30 | } 31 | } 32 | 33 | @else { 34 | @if $context { 35 | @each $item in $context { 36 | @if str-index($item, ':') == 1 { 37 | @if type-of($block) == 'string' { 38 | $selector: append($selector, '.#{$block}#{$item}', comma); 39 | } 40 | $selector: append($selector, '#{generate-chunk($block)}#{$item}', comma); 41 | } 42 | @else { 43 | $selector: append($selector, '#{generate-chunk($block)}[class*="#{$modifierGlue}#{$item}"]', comma); 44 | } 45 | } 46 | } 47 | @else { 48 | @if type-of($block) == 'string' { 49 | $selector: append($selector, '.#{$block}', comma); 50 | $selector: append($selector, '[class*="#{$block}#{$modifierGlue}"]', comma); 51 | } 52 | @else { 53 | $selector: append($selector, generate-chunk($block), comma); 54 | } 55 | } 56 | } 57 | 58 | @return $selector; 59 | } 60 | 61 | /// Generate a selector chunk from a $block list 62 | /// 63 | /// @param {(string|list)} $block 64 | @function generate-chunk($block) { 65 | $chunk: ''; 66 | 67 | @if type-of($block) == 'list' { 68 | @for $i from 1 through length($block) { 69 | @if $i == 1 { 70 | $chunk: $chunk + '[class*="#{nth($block, $i)}#{$componentGlue}"]'; 71 | } 72 | @else { 73 | $chunk: $chunk + '[class*="#{$componentGlue}#{nth($block, $i)}"]'; 74 | } 75 | } 76 | } 77 | @else { 78 | $chunk: '[class*="#{$block}#{$modifierGlue}"]'; 79 | } 80 | 81 | @return $chunk; 82 | } -------------------------------------------------------------------------------- /src/utilities/_css-properties.scss: -------------------------------------------------------------------------------- 1 | /// List of known and valid CSS properties 2 | /// 3 | /// @type Map 4 | $css-properties: ( 5 | 'accelerator', 6 | '-wap-accesskey', 7 | 'align-content', 8 | '-webkit-align-content', 9 | 'align-items', 10 | '-webkit-align-items', 11 | 'align-self', 12 | '-webkit-align-self', 13 | 'alignment-baseline', 14 | 'all', 15 | 'alt', 16 | '-webkit-alt', 17 | 'animation', 18 | 'animation-delay', 19 | '-moz-animation-delay', 20 | '-ms-animation-delay', 21 | '-webkit-animation-delay', 22 | 'animation-direction', 23 | '-moz-animation-direction', 24 | '-ms-animation-direction', 25 | '-webkit-animation-direction', 26 | 'animation-duration', 27 | '-moz-animation-duration', 28 | '-ms-animation-duration', 29 | '-webkit-animation-duration', 30 | 'animation-fill-mode', 31 | '-moz-animation-fill-mode', 32 | '-ms-animation-fill-mode', 33 | '-webkit-animation-fill-mode', 34 | 'animation-iteration-count', 35 | '-moz-animation-iteration-count', 36 | '-ms-animation-iteration-count', 37 | '-webkit-animation-iteration-count', 38 | '-moz-animation', 39 | '-ms-animation', 40 | 'animation-name', 41 | '-moz-animation-name', 42 | '-ms-animation-name', 43 | '-webkit-animation-name', 44 | 'animation-play-state', 45 | '-moz-animation-play-state', 46 | '-ms-animation-play-state', 47 | '-webkit-animation-play-state', 48 | 'animation-timing-function', 49 | '-moz-animation-timing-function', 50 | '-ms-animation-timing-function', 51 | '-webkit-animation-timing-function', 52 | '-webkit-animation', 53 | '-webkit-app-region', 54 | 'appearance', 55 | '-moz-appearance', 56 | '-webkit-appearance', 57 | '-webkit-aspect-ratio', 58 | 'audio-level', 59 | 'azimuth', 60 | 'backdrop-filter', 61 | '-webkit-backdrop-filter', 62 | 'backface-visibility', 63 | '-moz-backface-visibility', 64 | '-ms-backface-visibility', 65 | '-webkit-backface-visibility', 66 | 'background', 67 | 'background-attachment', 68 | '-webkit-background-attachment', 69 | 'background-blend-mode', 70 | 'background-clip', 71 | '-moz-background-clip', 72 | '-webkit-background-clip', 73 | 'background-color', 74 | '-webkit-background-color', 75 | '-webkit-background-composite', 76 | 'background-image', 77 | 'background-image-transform', 78 | '-webkit-background-image', 79 | '-moz-background-inline-policy', 80 | 'background-origin', 81 | '-moz-background-origin', 82 | '-webkit-background-origin', 83 | 'background-position', 84 | '-webkit-background-position', 85 | 'background-position-x', 86 | '-webkit-background-position-x', 87 | 'background-position-y', 88 | '-webkit-background-position-y', 89 | 'background-repeat', 90 | '-webkit-background-repeat', 91 | 'background-repeat-x', 92 | 'background-repeat-y', 93 | 'background-size', 94 | '-moz-background-size', 95 | '-webkit-background-size', 96 | '-webkit-background', 97 | 'baseline-shift', 98 | 'behavior', 99 | '-moz-binding', 100 | '-ms-block-progression', 101 | 'block-size', 102 | 'block-step', 103 | 'block-step-align', 104 | 'block-step-insert', 105 | 'block-step-round', 106 | 'block-step-size', 107 | 'bookmark-label', 108 | 'bookmark-level', 109 | 'bookmark-state', 110 | 'border', 111 | '-webkit-border-after-color', 112 | '-webkit-border-after-style', 113 | '-webkit-border-after', 114 | '-webkit-border-after-width', 115 | '-webkit-border-before-color', 116 | '-webkit-border-before-style', 117 | '-webkit-border-before', 118 | '-webkit-border-before-width', 119 | 'border-block', 120 | 'border-block-color', 121 | 'border-block-end', 122 | 'border-block-end-color', 123 | 'border-block-end-style', 124 | 'border-block-end-width', 125 | 'border-block-start', 126 | 'border-block-start-color', 127 | 'border-block-start-style', 128 | 'border-block-start-width', 129 | 'border-block-style', 130 | 'border-block-width', 131 | 'border-bottom', 132 | 'border-bottom-color', 133 | '-moz-border-bottom-colors', 134 | 'border-bottom-left-radius', 135 | '-webkit-border-bottom-left-radius', 136 | 'border-bottom-right-radius', 137 | '-webkit-border-bottom-right-radius', 138 | 'border-bottom-style', 139 | 'border-bottom-width', 140 | 'border-boundary', 141 | 'border-collapse', 142 | 'border-color', 143 | '-moz-border-end-color', 144 | '-webkit-border-end-color', 145 | '-moz-border-end', 146 | '-moz-border-end-style', 147 | '-webkit-border-end-style', 148 | '-webkit-border-end', 149 | '-moz-border-end-width', 150 | '-webkit-border-end-width', 151 | '-webkit-border-fit', 152 | '-webkit-border-horizontal-spacing', 153 | 'border-image', 154 | '-moz-border-image', 155 | '-o-border-image', 156 | 'border-image-outset', 157 | '-webkit-border-image-outset', 158 | 'border-image-repeat', 159 | '-webkit-border-image-repeat', 160 | 'border-image-slice', 161 | '-webkit-border-image-slice', 162 | 'border-image-source', 163 | '-webkit-border-image-source', 164 | 'border-image-transform', 165 | '-webkit-border-image', 166 | 'border-image-width', 167 | '-webkit-border-image-width', 168 | 'border-inline', 169 | 'border-inline-color', 170 | 'border-inline-end', 171 | 'border-inline-end-color', 172 | 'border-inline-end-style', 173 | 'border-inline-end-width', 174 | 'border-inline-start', 175 | 'border-inline-start-color', 176 | 'border-inline-start-style', 177 | 'border-inline-start-width', 178 | 'border-inline-style', 179 | 'border-inline-width', 180 | 'border-left', 181 | 'border-left-color', 182 | '-moz-border-left-colors', 183 | 'border-left-style', 184 | 'border-left-width', 185 | 'border-radius', 186 | '-moz-border-radius-bottomleft', 187 | '-moz-border-radius-bottomright', 188 | '-moz-border-radius', 189 | '-moz-border-radius-topleft', 190 | '-moz-border-radius-topright', 191 | '-webkit-border-radius', 192 | 'border-right', 193 | 'border-right-color', 194 | '-moz-border-right-colors', 195 | 'border-right-style', 196 | 'border-right-width', 197 | 'border-spacing', 198 | '-moz-border-start-color', 199 | '-webkit-border-start-color', 200 | '-moz-border-start', 201 | '-moz-border-start-style', 202 | '-webkit-border-start-style', 203 | '-webkit-border-start', 204 | '-moz-border-start-width', 205 | '-webkit-border-start-width', 206 | 'border-style', 207 | 'border-top', 208 | 'border-top-color', 209 | '-moz-border-top-colors', 210 | 'border-top-left-radius', 211 | '-webkit-border-top-left-radius', 212 | 'border-top-right-radius', 213 | '-webkit-border-top-right-radius', 214 | 'border-top-style', 215 | 'border-top-width', 216 | '-webkit-border-vertical-spacing', 217 | 'border-width', 218 | 'bottom', 219 | '-moz-box-align', 220 | '-webkit-box-align', 221 | 'box-decoration-break', 222 | '-webkit-box-decoration-break', 223 | '-moz-box-direction', 224 | '-webkit-box-direction', 225 | '-webkit-box-flex-group', 226 | '-moz-box-flex', 227 | '-webkit-box-flex', 228 | '-webkit-box-lines', 229 | '-moz-box-ordinal-group', 230 | '-webkit-box-ordinal-group', 231 | '-moz-box-orient', 232 | '-webkit-box-orient', 233 | '-moz-box-pack', 234 | '-webkit-box-pack', 235 | '-webkit-box-reflect', 236 | 'box-shadow', 237 | '-moz-box-shadow', 238 | '-webkit-box-shadow', 239 | 'box-sizing', 240 | '-moz-box-sizing', 241 | '-webkit-box-sizing', 242 | 'box-snap', 243 | 'break-after', 244 | 'break-before', 245 | 'break-inside', 246 | 'buffered-rendering', 247 | 'caption-side', 248 | 'caret', 249 | 'caret-animation', 250 | 'caret-color', 251 | 'caret-shape', 252 | 'chains', 253 | 'clear', 254 | 'clip', 255 | 'clip-path', 256 | '-webkit-clip-path', 257 | 'clip-rule', 258 | 'color', 259 | 'color-adjust', 260 | '-webkit-color-correction', 261 | 'color-interpolation', 262 | 'color-interpolation-filters', 263 | 'color-profile', 264 | 'color-rendering', 265 | '-webkit-column-axis', 266 | '-webkit-column-break-after', 267 | '-webkit-column-break-before', 268 | '-webkit-column-break-inside', 269 | 'column-count', 270 | '-moz-column-count', 271 | '-webkit-column-count', 272 | 'column-fill', 273 | '-moz-column-fill', 274 | '-webkit-column-fill', 275 | 'column-gap', 276 | '-moz-column-gap', 277 | '-webkit-column-gap', 278 | 'column-progression', 279 | '-webkit-column-progression', 280 | 'column-rule', 281 | 'column-rule-color', 282 | '-moz-column-rule-color', 283 | '-webkit-column-rule-color', 284 | '-moz-column-rule', 285 | 'column-rule-style', 286 | '-moz-column-rule-style', 287 | '-webkit-column-rule-style', 288 | '-webkit-column-rule', 289 | 'column-rule-width', 290 | '-moz-column-rule-width', 291 | '-webkit-column-rule-width', 292 | 'column-span', 293 | '-webkit-column-span', 294 | 'column-width', 295 | '-moz-column-width', 296 | '-webkit-column-width', 297 | 'columns', 298 | '-moz-columns', 299 | '-webkit-columns', 300 | '-webkit-composition-fill-color', 301 | '-webkit-composition-frame-color', 302 | 'contain', 303 | 'content', 304 | '-ms-content-zoom-chaining', 305 | '-ms-content-zoom-limit-max', 306 | '-ms-content-zoom-limit-min', 307 | '-ms-content-zoom-limit', 308 | '-ms-content-zoom-snap', 309 | '-ms-content-zoom-snap-points', 310 | '-ms-content-zoom-snap-type', 311 | '-ms-content-zooming', 312 | 'continue', 313 | 'counter-increment', 314 | 'counter-reset', 315 | 'counter-set', 316 | 'cue', 317 | 'cue-after', 318 | 'cue-before', 319 | 'cursor', 320 | '-webkit-cursor-visibility', 321 | 'cx', 322 | 'cy', 323 | 'd', 324 | '-apple-dashboard-region', 325 | '-webkit-dashboard-region', 326 | 'direction', 327 | 'display', 328 | 'display-align', 329 | 'dominant-baseline', 330 | 'elevation', 331 | 'empty-cells', 332 | 'enable-background', 333 | 'fill', 334 | 'fill-break', 335 | 'fill-color', 336 | 'fill-image', 337 | 'fill-opacity', 338 | 'fill-origin', 339 | 'fill-position', 340 | 'fill-repeat', 341 | 'fill-rule', 342 | 'fill-size', 343 | 'filter', 344 | '-ms-filter', 345 | '-webkit-filter', 346 | 'flex', 347 | '-ms-flex-align', 348 | '-webkit-flex-align', 349 | 'flex-basis', 350 | '-webkit-flex-basis', 351 | 'flex-direction', 352 | '-ms-flex-direction', 353 | '-webkit-flex-direction', 354 | 'flex-flow', 355 | '-ms-flex-flow', 356 | '-webkit-flex-flow', 357 | 'flex-grow', 358 | '-webkit-flex-grow', 359 | '-ms-flex-item-align', 360 | '-webkit-flex-item-align', 361 | '-ms-flex-line-pack', 362 | '-webkit-flex-line-pack', 363 | '-ms-flex', 364 | '-ms-flex-negative', 365 | '-ms-flex-order', 366 | '-webkit-flex-order', 367 | '-ms-flex-pack', 368 | '-webkit-flex-pack', 369 | '-ms-flex-positive', 370 | '-ms-flex-preferred-size', 371 | 'flex-shrink', 372 | '-webkit-flex-shrink', 373 | '-webkit-flex', 374 | 'flex-wrap', 375 | '-ms-flex-wrap', 376 | '-webkit-flex-wrap', 377 | 'float', 378 | 'float-defer', 379 | '-moz-float-edge', 380 | 'float-offset', 381 | 'float-reference', 382 | 'flood-color', 383 | 'flood-opacity', 384 | 'flow', 385 | 'flow-from', 386 | '-ms-flow-from', 387 | '-webkit-flow-from', 388 | 'flow-into', 389 | '-ms-flow-into', 390 | '-webkit-flow-into', 391 | 'font', 392 | 'font-display', 393 | 'font-family', 394 | 'font-feature-settings', 395 | '-moz-font-feature-settings', 396 | '-ms-font-feature-settings', 397 | '-webkit-font-feature-settings', 398 | 'font-kerning', 399 | '-webkit-font-kerning', 400 | 'font-language-override', 401 | '-moz-font-language-override', 402 | 'font-max-size', 403 | 'font-min-size', 404 | 'font-optical-sizing', 405 | 'font-palette', 406 | 'font-presentation', 407 | 'font-size', 408 | 'font-size-adjust', 409 | '-webkit-font-size-delta', 410 | '-webkit-font-smoothing', 411 | 'font-stretch', 412 | 'font-style', 413 | 'font-synthesis', 414 | 'font-variant', 415 | 'font-variant-alternates', 416 | 'font-variant-caps', 417 | 'font-variant-east-asian', 418 | 'font-variant-ligatures', 419 | '-webkit-font-variant-ligatures', 420 | 'font-variant-numeric', 421 | 'font-variant-position', 422 | 'font-variation-settings', 423 | 'font-weight', 424 | 'footnote-display', 425 | 'footnote-policy', 426 | '-moz-force-broken-image-icon', 427 | 'glyph-orientation-horizontal', 428 | 'glyph-orientation-vertical', 429 | 'grid', 430 | '-webkit-grid-after', 431 | 'grid-area', 432 | 'grid-auto-columns', 433 | '-webkit-grid-auto-columns', 434 | 'grid-auto-flow', 435 | '-webkit-grid-auto-flow', 436 | 'grid-auto-rows', 437 | '-webkit-grid-auto-rows', 438 | '-webkit-grid-before', 439 | 'grid-column', 440 | '-ms-grid-column-align', 441 | 'grid-column-end', 442 | 'grid-column-gap', 443 | '-ms-grid-column', 444 | '-ms-grid-column-span', 445 | 'grid-column-start', 446 | '-webkit-grid-column', 447 | '-ms-grid-columns', 448 | '-webkit-grid-columns', 449 | '-webkit-grid-end', 450 | 'grid-gap', 451 | 'grid-row', 452 | '-ms-grid-row-align', 453 | 'grid-row-end', 454 | 'grid-row-gap', 455 | '-ms-grid-row', 456 | '-ms-grid-row-span', 457 | 'grid-row-start', 458 | '-webkit-grid-row', 459 | '-ms-grid-rows', 460 | '-webkit-grid-rows', 461 | '-webkit-grid-start', 462 | 'grid-template', 463 | 'grid-template-areas', 464 | 'grid-template-columns', 465 | 'grid-template-rows', 466 | 'hanging-punctuation', 467 | 'height', 468 | '-ms-high-contrast-adjust', 469 | '-webkit-highlight', 470 | 'hyphenate-character', 471 | '-webkit-hyphenate-character', 472 | '-webkit-hyphenate-limit-after', 473 | '-webkit-hyphenate-limit-before', 474 | 'hyphenate-limit-chars', 475 | '-ms-hyphenate-limit-chars', 476 | 'hyphenate-limit-last', 477 | 'hyphenate-limit-lines', 478 | '-ms-hyphenate-limit-lines', 479 | '-webkit-hyphenate-limit-lines', 480 | 'hyphenate-limit-zone', 481 | '-ms-hyphenate-limit-zone', 482 | 'hyphens', 483 | '-moz-hyphens', 484 | '-ms-hyphens', 485 | '-webkit-hyphens', 486 | 'image-orientation', 487 | '-moz-image-region', 488 | 'image-rendering', 489 | 'image-resolution', 490 | '-ms-ime-align', 491 | 'ime-mode', 492 | 'initial-letter', 493 | 'initial-letter-align', 494 | '-webkit-initial-letter', 495 | 'initial-letter-wrap', 496 | 'inline-size', 497 | 'input-format', 498 | '-wap-input-format', 499 | '-wap-input-required', 500 | 'inset', 501 | 'inset-block', 502 | 'inset-block-end', 503 | 'inset-block-start', 504 | 'inset-inline', 505 | 'inset-inline-end', 506 | 'inset-inline-start', 507 | '-ms-interpolation-mode', 508 | 'isolation', 509 | 'justify-content', 510 | '-webkit-justify-content', 511 | 'justify-items', 512 | 'justify-self', 513 | '-webkit-justify-self', 514 | 'kerning', 515 | 'layout-flow', 516 | 'layout-grid', 517 | 'layout-grid-char', 518 | 'layout-grid-line', 519 | 'layout-grid-mode', 520 | 'layout-grid-type', 521 | 'left', 522 | 'letter-spacing', 523 | 'lighting-color', 524 | '-webkit-line-align', 525 | '-webkit-line-box-contain', 526 | 'line-break', 527 | '-webkit-line-break', 528 | '-webkit-line-clamp', 529 | 'line-grid', 530 | '-webkit-line-grid-snap', 531 | '-webkit-line-grid', 532 | 'line-height', 533 | 'line-height-step', 534 | 'line-increment', 535 | 'line-snap', 536 | '-webkit-line-snap', 537 | '-o-link', 538 | '-o-link-source', 539 | 'list-style', 540 | 'list-style-image', 541 | 'list-style-position', 542 | 'list-style-type', 543 | '-webkit-locale', 544 | '-webkit-logical-height', 545 | '-webkit-logical-width', 546 | 'margin', 547 | '-webkit-margin-after-collapse', 548 | '-webkit-margin-after', 549 | '-webkit-margin-before-collapse', 550 | '-webkit-margin-before', 551 | 'margin-block', 552 | 'margin-block-end', 553 | 'margin-block-start', 554 | 'margin-bottom', 555 | '-webkit-margin-bottom-collapse', 556 | '-webkit-margin-collapse', 557 | '-moz-margin-end', 558 | '-webkit-margin-end', 559 | 'margin-inline', 560 | 'margin-inline-end', 561 | 'margin-inline-start', 562 | 'margin-left', 563 | 'margin-right', 564 | '-moz-margin-start', 565 | '-webkit-margin-start', 566 | 'margin-top', 567 | '-webkit-margin-top-collapse', 568 | 'marker', 569 | 'marker-end', 570 | 'marker-knockout-left', 571 | 'marker-knockout-right', 572 | 'marker-mid', 573 | 'marker-offset', 574 | 'marker-pattern', 575 | 'marker-segment', 576 | 'marker-side', 577 | 'marker-start', 578 | 'marks', 579 | '-wap-marquee-dir', 580 | 'marquee-direction', 581 | '-webkit-marquee-direction', 582 | '-webkit-marquee-increment', 583 | 'marquee-loop', 584 | '-wap-marquee-loop', 585 | '-webkit-marquee-repetition', 586 | 'marquee-speed', 587 | '-wap-marquee-speed', 588 | '-webkit-marquee-speed', 589 | 'marquee-style', 590 | '-wap-marquee-style', 591 | '-webkit-marquee-style', 592 | '-webkit-marquee', 593 | 'mask', 594 | '-webkit-mask-attachment', 595 | 'mask-border', 596 | 'mask-border-mode', 597 | 'mask-border-outset', 598 | 'mask-border-repeat', 599 | 'mask-border-slice', 600 | 'mask-border-source', 601 | 'mask-border-width', 602 | '-webkit-mask-box-image-outset', 603 | '-webkit-mask-box-image-repeat', 604 | '-webkit-mask-box-image-slice', 605 | '-webkit-mask-box-image-source', 606 | '-webkit-mask-box-image', 607 | '-webkit-mask-box-image-width', 608 | 'mask-clip', 609 | '-webkit-mask-clip', 610 | 'mask-composite', 611 | '-webkit-mask-composite', 612 | 'mask-image', 613 | '-webkit-mask-image', 614 | 'mask-mode', 615 | 'mask-origin', 616 | '-webkit-mask-origin', 617 | 'mask-position', 618 | '-webkit-mask-position', 619 | 'mask-position-x', 620 | '-webkit-mask-position-x', 621 | 'mask-position-y', 622 | '-webkit-mask-position-y', 623 | 'mask-repeat', 624 | '-webkit-mask-repeat', 625 | '-webkit-mask-repeat-x', 626 | '-webkit-mask-repeat-y', 627 | 'mask-size', 628 | '-webkit-mask-size', 629 | 'mask-source-type', 630 | '-webkit-mask-source-type', 631 | 'mask-type', 632 | '-webkit-mask', 633 | '-webkit-match-nearest-mail-blockquote-color', 634 | 'max-block-size', 635 | 'max-height', 636 | 'max-inline-size', 637 | 'max-lines', 638 | '-webkit-max-logical-height', 639 | '-webkit-max-logical-width', 640 | 'max-width', 641 | 'max-zoom', 642 | 'min-block-size', 643 | 'min-height', 644 | 'min-inline-size', 645 | '-webkit-min-logical-height', 646 | '-webkit-min-logical-width', 647 | 'min-width', 648 | 'min-zoom', 649 | 'mix-blend-mode', 650 | 'motion', 651 | 'motion-offset', 652 | 'motion-path', 653 | 'motion-rotation', 654 | 'nav-down', 655 | 'nav-index', 656 | 'nav-left', 657 | 'nav-right', 658 | 'nav-up', 659 | '-webkit-nbsp-mode', 660 | 'object-fit', 661 | '-o-object-fit', 662 | 'object-position', 663 | '-o-object-position', 664 | 'offset', 665 | 'offset-after', 666 | 'offset-anchor', 667 | 'offset-before', 668 | 'offset-block-end', 669 | 'offset-block-start', 670 | 'offset-distance', 671 | 'offset-end', 672 | 'offset-inline-end', 673 | 'offset-inline-start', 674 | 'offset-path', 675 | 'offset-position', 676 | 'offset-rotate', 677 | 'offset-rotation', 678 | 'offset-start', 679 | 'opacity', 680 | '-moz-opacity', 681 | 'order', 682 | '-webkit-order', 683 | '-moz-orient', 684 | 'orientation', 685 | 'orphans', 686 | '-moz-osx-font-smoothing', 687 | 'outline', 688 | 'outline-color', 689 | '-moz-outline-color', 690 | '-moz-outline', 691 | 'outline-offset', 692 | '-moz-outline-offset', 693 | '-moz-outline-radius-bottomleft', 694 | '-moz-outline-radius-bottomright', 695 | '-moz-outline-radius', 696 | '-moz-outline-radius-topleft', 697 | '-moz-outline-radius-topright', 698 | 'outline-style', 699 | '-moz-outline-style', 700 | 'outline-width', 701 | '-moz-outline-width', 702 | 'overflow', 703 | 'overflow-anchor', 704 | '-webkit-overflow-scrolling', 705 | 'overflow-style', 706 | '-ms-overflow-style', 707 | 'overflow-wrap', 708 | 'overflow-x', 709 | 'overflow-y', 710 | 'padding', 711 | '-webkit-padding-after', 712 | '-webkit-padding-before', 713 | 'padding-block', 714 | 'padding-block-end', 715 | 'padding-block-start', 716 | 'padding-bottom', 717 | '-moz-padding-end', 718 | '-webkit-padding-end', 719 | 'padding-inline', 720 | 'padding-inline-end', 721 | 'padding-inline-start', 722 | 'padding-left', 723 | 'padding-right', 724 | '-moz-padding-start', 725 | '-webkit-padding-start', 726 | 'padding-top', 727 | 'page', 728 | 'page-break-after', 729 | 'page-break-before', 730 | 'page-break-inside', 731 | 'paint-order', 732 | 'pause', 733 | 'pause-after', 734 | 'pause-before', 735 | 'perspective', 736 | '-moz-perspective', 737 | '-ms-perspective', 738 | 'perspective-origin', 739 | '-moz-perspective-origin', 740 | '-ms-perspective-origin', 741 | '-webkit-perspective-origin', 742 | 'perspective-origin-x', 743 | '-webkit-perspective-origin-x', 744 | 'perspective-origin-y', 745 | '-webkit-perspective-origin-y', 746 | '-webkit-perspective', 747 | 'pitch', 748 | 'pitch-range', 749 | 'place-content', 750 | 'place-items', 751 | 'place-self', 752 | 'play-during', 753 | 'pointer-events', 754 | 'position', 755 | '-webkit-print-color-adjust', 756 | 'quotes', 757 | 'r', 758 | '-webkit-region-break-after', 759 | '-webkit-region-break-before', 760 | '-webkit-region-break-inside', 761 | 'region-fragment', 762 | '-webkit-region-fragment', 763 | '-webkit-region-overflow', 764 | 'resize', 765 | 'rest', 766 | 'rest-after', 767 | 'rest-before', 768 | 'richness', 769 | 'right', 770 | 'rotate', 771 | 'rotation', 772 | 'rotation-point', 773 | '-webkit-rtl-ordering', 774 | 'ruby-align', 775 | 'ruby-merge', 776 | 'ruby-overhang', 777 | 'ruby-position', 778 | '-webkit-ruby-position', 779 | 'running', 780 | 'rx', 781 | 'ry', 782 | 'scale', 783 | 'scroll-behavior', 784 | '-ms-scroll-chaining', 785 | '-ms-scroll-limit', 786 | '-ms-scroll-limit-x-max', 787 | '-ms-scroll-limit-x-min', 788 | '-ms-scroll-limit-y-max', 789 | '-ms-scroll-limit-y-min', 790 | 'scroll-padding', 791 | 'scroll-padding-block', 792 | 'scroll-padding-block-end', 793 | 'scroll-padding-block-start', 794 | 'scroll-padding-bottom', 795 | 'scroll-padding-inline', 796 | 'scroll-padding-inline-end', 797 | 'scroll-padding-inline-start', 798 | 'scroll-padding-left', 799 | 'scroll-padding-right', 800 | 'scroll-padding-top', 801 | '-ms-scroll-rails', 802 | 'scroll-snap-align', 803 | 'scroll-snap-coordinate', 804 | '-webkit-scroll-snap-coordinate', 805 | 'scroll-snap-destination', 806 | '-webkit-scroll-snap-destination', 807 | 'scroll-snap-margin', 808 | 'scroll-snap-margin-block', 809 | 'scroll-snap-margin-block-end', 810 | 'scroll-snap-margin-block-start', 811 | 'scroll-snap-margin-bottom', 812 | 'scroll-snap-margin-inline', 813 | 'scroll-snap-margin-inline-end', 814 | 'scroll-snap-margin-inline-start', 815 | 'scroll-snap-margin-left', 816 | 'scroll-snap-margin-right', 817 | 'scroll-snap-margin-top', 818 | 'scroll-snap-points-x', 819 | '-ms-scroll-snap-points-x', 820 | '-webkit-scroll-snap-points-x', 821 | 'scroll-snap-points-y', 822 | '-ms-scroll-snap-points-y', 823 | '-webkit-scroll-snap-points-y', 824 | 'scroll-snap-stop', 825 | 'scroll-snap-type', 826 | '-ms-scroll-snap-type', 827 | '-webkit-scroll-snap-type', 828 | 'scroll-snap-type-x', 829 | 'scroll-snap-type-y', 830 | '-ms-scroll-snap-x', 831 | '-ms-scroll-snap-y', 832 | '-ms-scroll-translation', 833 | 'scrollbar-arrow-color', 834 | 'scrollbar-base-color', 835 | 'scrollbar-dark-shadow-color', 836 | 'scrollbar-darkshadow-color', 837 | 'scrollbar-face-color', 838 | 'scrollbar-gutter', 839 | 'scrollbar-highlight-color', 840 | 'scrollbar-shadow-color', 841 | 'scrollbar-track-color', 842 | 'scrollbar3d-light-color', 843 | 'scrollbar3dlight-color', 844 | 'shape-image-threshold', 845 | '-webkit-shape-image-threshold', 846 | 'shape-inside', 847 | '-webkit-shape-inside', 848 | 'shape-margin', 849 | '-webkit-shape-margin', 850 | 'shape-outside', 851 | '-webkit-shape-outside', 852 | '-webkit-shape-padding', 853 | 'shape-rendering', 854 | 'size', 855 | 'snap-height', 856 | 'solid-color', 857 | 'solid-opacity', 858 | 'speak', 859 | 'speak-as', 860 | 'speak-header', 861 | 'speak-numeral', 862 | 'speak-punctuation', 863 | 'speech-rate', 864 | 'src', 865 | '-moz-stack-sizing', 866 | 'stop-color', 867 | 'stop-opacity', 868 | 'stress', 869 | 'string-set', 870 | 'stroke', 871 | 'stroke-align', 872 | 'stroke-alignment', 873 | 'stroke-break', 874 | 'stroke-color', 875 | 'stroke-dash-corner', 876 | 'stroke-dash-justify', 877 | 'stroke-dashadjust', 878 | 'stroke-dasharray', 879 | 'stroke-dashcorner', 880 | 'stroke-dashoffset', 881 | 'stroke-image', 882 | 'stroke-linecap', 883 | 'stroke-linejoin', 884 | 'stroke-miterlimit', 885 | 'stroke-opacity', 886 | 'stroke-origin', 887 | 'stroke-position', 888 | 'stroke-repeat', 889 | 'stroke-size', 890 | 'stroke-width', 891 | '-webkit-svg-shadow', 892 | 'tab-size', 893 | '-moz-tab-size', 894 | '-o-tab-size', 895 | '-o-table-baseline', 896 | 'table-layout', 897 | '-webkit-tap-highlight-color', 898 | 'text-align', 899 | 'text-align-all', 900 | 'text-align-last', 901 | '-moz-text-align-last', 902 | 'text-anchor', 903 | 'text-autospace', 904 | '-moz-text-blink', 905 | '-ms-text-combine-horizontal', 906 | 'text-combine-upright', 907 | '-webkit-text-combine', 908 | 'text-decoration', 909 | 'text-decoration-blink', 910 | 'text-decoration-color', 911 | '-moz-text-decoration-color', 912 | '-webkit-text-decoration-color', 913 | 'text-decoration-line', 914 | '-moz-text-decoration-line', 915 | 'text-decoration-line-through', 916 | '-webkit-text-decoration-line', 917 | 'text-decoration-none', 918 | 'text-decoration-overline', 919 | 'text-decoration-skip', 920 | '-webkit-text-decoration-skip', 921 | 'text-decoration-style', 922 | '-moz-text-decoration-style', 923 | '-webkit-text-decoration-style', 924 | 'text-decoration-underline', 925 | '-webkit-text-decoration', 926 | '-webkit-text-decorations-in-effect', 927 | 'text-emphasis', 928 | 'text-emphasis-color', 929 | '-webkit-text-emphasis-color', 930 | 'text-emphasis-position', 931 | '-webkit-text-emphasis-position', 932 | 'text-emphasis-style', 933 | '-webkit-text-emphasis-style', 934 | '-webkit-text-emphasis', 935 | '-webkit-text-fill-color', 936 | 'text-indent', 937 | 'text-justify', 938 | 'text-justify-trim', 939 | 'text-kashida', 940 | 'text-kashida-space', 941 | 'text-line-through', 942 | 'text-line-through-color', 943 | 'text-line-through-mode', 944 | 'text-line-through-style', 945 | 'text-line-through-width', 946 | 'text-orientation', 947 | '-webkit-text-orientation', 948 | 'text-overflow', 949 | 'text-overline', 950 | 'text-overline-color', 951 | 'text-overline-mode', 952 | 'text-overline-style', 953 | 'text-overline-width', 954 | 'text-rendering', 955 | '-webkit-text-security', 956 | 'text-shadow', 957 | 'text-size-adjust', 958 | '-moz-text-size-adjust', 959 | '-ms-text-size-adjust', 960 | '-webkit-text-size-adjust', 961 | 'text-space-collapse', 962 | 'text-space-trim', 963 | 'text-spacing', 964 | '-webkit-text-stroke-color', 965 | '-webkit-text-stroke', 966 | '-webkit-text-stroke-width', 967 | 'text-transform', 968 | 'text-underline', 969 | 'text-underline-color', 970 | 'text-underline-mode', 971 | 'text-underline-position', 972 | '-webkit-text-underline-position', 973 | 'text-underline-style', 974 | 'text-underline-width', 975 | 'text-wrap', 976 | '-webkit-text-zoom', 977 | 'top', 978 | 'touch-action', 979 | 'touch-action-delay', 980 | '-ms-touch-action', 981 | '-webkit-touch-callout', 982 | '-ms-touch-select', 983 | 'transform', 984 | 'transform-box', 985 | '-moz-transform', 986 | '-ms-transform', 987 | '-o-transform', 988 | 'transform-origin', 989 | '-moz-transform-origin', 990 | '-ms-transform-origin', 991 | '-o-transform-origin', 992 | '-webkit-transform-origin', 993 | 'transform-origin-x', 994 | '-webkit-transform-origin-x', 995 | 'transform-origin-y', 996 | '-webkit-transform-origin-y', 997 | 'transform-origin-z', 998 | '-webkit-transform-origin-z', 999 | 'transform-style', 1000 | '-moz-transform-style', 1001 | '-ms-transform-style', 1002 | '-webkit-transform-style', 1003 | '-webkit-transform', 1004 | 'transition', 1005 | 'transition-delay', 1006 | '-moz-transition-delay', 1007 | '-ms-transition-delay', 1008 | '-o-transition-delay', 1009 | '-webkit-transition-delay', 1010 | 'transition-duration', 1011 | '-moz-transition-duration', 1012 | '-ms-transition-duration', 1013 | '-o-transition-duration', 1014 | '-webkit-transition-duration', 1015 | '-moz-transition', 1016 | '-ms-transition', 1017 | '-o-transition', 1018 | 'transition-property', 1019 | '-moz-transition-property', 1020 | '-ms-transition-property', 1021 | '-o-transition-property', 1022 | '-webkit-transition-property', 1023 | 'transition-timing-function', 1024 | '-moz-transition-timing-function', 1025 | '-ms-transition-timing-function', 1026 | '-o-transition-timing-function', 1027 | '-webkit-transition-timing-function', 1028 | '-webkit-transition', 1029 | 'translate', 1030 | 'uc-alt-skin', 1031 | 'uc-skin', 1032 | 'unicode-bidi', 1033 | 'unicode-range', 1034 | '-webkit-user-drag', 1035 | '-moz-user-focus', 1036 | '-moz-user-input', 1037 | '-moz-user-modify', 1038 | '-webkit-user-modify', 1039 | 'user-select', 1040 | '-moz-user-select', 1041 | '-ms-user-select', 1042 | '-webkit-user-select', 1043 | 'user-zoom', 1044 | 'vector-effect', 1045 | 'vertical-align', 1046 | 'viewport-fill', 1047 | 'viewport-fill-opacity', 1048 | 'visibility', 1049 | 'voice-balance', 1050 | 'voice-duration', 1051 | 'voice-family', 1052 | 'voice-pitch', 1053 | 'voice-range', 1054 | 'voice-rate', 1055 | 'voice-stress', 1056 | 'voice-volume', 1057 | 'volume', 1058 | 'white-space', 1059 | '-webkit-widget-region', 1060 | 'widows', 1061 | 'width', 1062 | 'will-change', 1063 | '-moz-window-dragging', 1064 | '-moz-window-shadow', 1065 | 'word-break', 1066 | 'word-spacing', 1067 | 'word-wrap', 1068 | 'wrap-after', 1069 | 'wrap-before', 1070 | 'wrap-flow', 1071 | '-ms-wrap-flow', 1072 | '-webkit-wrap-flow', 1073 | 'wrap-inside', 1074 | '-ms-wrap-margin', 1075 | '-webkit-wrap-margin', 1076 | '-webkit-wrap-padding', 1077 | '-webkit-wrap-shape-inside', 1078 | '-webkit-wrap-shape-outside', 1079 | 'wrap-through', 1080 | '-ms-wrap-through', 1081 | '-webkit-wrap-through', 1082 | '-webkit-wrap', 1083 | 'writing-mode', 1084 | '-webkit-writing-mode', 1085 | 'x', 1086 | 'y', 1087 | 'z-index', 1088 | 'zoom' 1089 | ) !default; -------------------------------------------------------------------------------- /src/utilities/_enabled.scss: -------------------------------------------------------------------------------- 1 | /// Return a CSS property if the passed option is enabled 2 | /// 3 | /// @param {string|list} $option - the desired option 4 | /// @returns {*} - $true-value if option enabled, otherwise returns $false-value 5 | @function enabled($option, $true-value, $false-value: '') { 6 | $breadcrumb: (); 7 | 8 | @each $crumb in $option { 9 | $breadcrumb: join($breadcrumb, $crumb, comma); 10 | } 11 | 12 | @if value-enabled(map-get-deep($config, $breadcrumb...)) { 13 | @return $true-value; 14 | } 15 | @else { 16 | @return $false-value; 17 | } 18 | } -------------------------------------------------------------------------------- /src/utilities/_get-module-name.scss: -------------------------------------------------------------------------------- 1 | /// Get the name of a module from a namespace 2 | /// 3 | /// @param {string} $namespace 4 | @function get-module-name($namespace) { 5 | $modifier-index: str-index($namespace, $modifierGlue); 6 | $component-index: str-index($namespace, $componentGlue); 7 | 8 | $slice-index: if($component-index, $component-index, $modifier-index); 9 | 10 | @return if($slice-index, str-slice($namespace, 0, $slice-index - 1), $namespace); 11 | } -------------------------------------------------------------------------------- /src/utilities/_get-param.scss: -------------------------------------------------------------------------------- 1 | /// Get parmater from config string 2 | /// 3 | /// @param {string} $source - the string from which to retrieve param 4 | @function get-param($source) { 5 | @if str-index($source, 'component(') == 1 { 6 | $source: str-replace($source, 'component(', ''); 7 | $source: str-replace($source, ')', ''); 8 | } 9 | 10 | @else if str-index($source, 'sub-component(') == 1 { 11 | $source: str-replace($source, 'sub-component(', ''); 12 | $source: str-replace($source, ')', ''); 13 | } 14 | 15 | @else if str-index($source, 'modifier(') == 1 { 16 | $source: str-replace($source, 'modifier(', ''); 17 | $source: str-replace($source, ')', ''); 18 | } 19 | 20 | @else if str-index($source, $componentGlue) == 1 { 21 | $source: strip-glue($source, $componentGlue); 22 | } 23 | 24 | @else if str-index($source, $modifierGlue) == 1 { 25 | $source: strip-glue($source, $modifierGlue); 26 | } 27 | 28 | @if type-of($source) == 'string' { 29 | $source: str-replace($source, "'", ''); 30 | } 31 | 32 | @return $source; 33 | } -------------------------------------------------------------------------------- /src/utilities/_merge-css-maps.scss: -------------------------------------------------------------------------------- 1 | /// Merge maps containing module/component CSS 2 | /// 3 | /// @param {map} $source 4 | /// @param {map} $target 5 | @function merge-css-maps($source, $target) { 6 | $content: map-merge-deep($source, $target); 7 | 8 | @if str-index(inspect($content), 'null') == null { 9 | @each $property, $value in $content { 10 | $dup-param: null; 11 | 12 | @if str-index($property, $modifierGlue) == 1 { 13 | $dup-param: $property; 14 | } 15 | 16 | @each $property, $value in $content { 17 | @if str-index($property, 'modifier(') == 1 and $dup-param { 18 | @if get-param($property) == get-param($dup-param) { 19 | $merge-dup-param: map-merge-deep(map-get($content, $property), map-get($content, $dup-param)); 20 | $content: map-set($content, $dup-param, $merge-dup-param); 21 | $content: map-remove($content, $property); 22 | } 23 | } 24 | } 25 | } 26 | } 27 | 28 | @return $content; 29 | } -------------------------------------------------------------------------------- /src/utilities/_module-tree.scss: -------------------------------------------------------------------------------- 1 | /// Create a namespace tree from a passed selector 2 | /// 3 | /// @param {list} $selector - The selector from which to create the module tree 4 | @function module-tree($selector) { 5 | $parent-module: $module; 6 | 7 | // Remove any modifers 8 | $selectors: remove-modifiers($selector); 9 | 10 | // Remove any junk characters 11 | $selectors: remove-junk($selectors); 12 | 13 | // Spoof our selectors into a list 14 | $selectors: str-replace($selectors, ' ', ', '); 15 | $selectors: selector-parse($selectors); 16 | 17 | @return $selectors; 18 | } -------------------------------------------------------------------------------- /src/utilities/_option.scss: -------------------------------------------------------------------------------- 1 | /// Return the value of a module's option 2 | /// 3 | /// @alias map-get-deep 4 | @function option($args...) { 5 | @return map-get-deep($args...); 6 | } -------------------------------------------------------------------------------- /src/utilities/_parse-cq.scss: -------------------------------------------------------------------------------- 1 | /// Parse CQ 2 | /// 3 | /// @param {map} $map - The map from which to parse CQ 4 | /// @param {bool} $sub-component 5 | /// @param {bool} $prevContext 6 | @mixin parse-cq($map, $sub-component: false, $prevContext: false) { 7 | @each $property, $value in $map { 8 | @if type-of($property) == 'string' { 9 | // $property defines new Modifier 10 | @if str-index($property, 'modifier(') == 1 or str-index($property, $modifierGlue) == 1 { 11 | @include modifier(get-param($property)) { 12 | @include parse-cq($value); 13 | } 14 | } 15 | 16 | // $property defines new Component 17 | @else if str-index($property, 'component(') == 1 or str-index($property, $componentGlue) == 1 { 18 | @include component(get-param($property)) { 19 | @include parse-cq($value); 20 | } 21 | } 22 | 23 | // $property defines new Component 24 | @else if str-index($property, 'sub-component(') == 1 { 25 | @include sub-component(get-param($property)) { 26 | @include parse-cq($value); 27 | } 28 | } 29 | 30 | // $property is for parent wrapper/group element 31 | @else if $property == 'group' or $property == 'wrapper' { 32 | @include wrapper($property, if($prevContext, $prevContext, $module)) { 33 | @include parse-cq($value); 34 | } 35 | } 36 | 37 | // Determine if current node is queried modifier/state 38 | @else if str-index($property, 'is-') == 1 { 39 | @include modifier(str-replace($property, 'is-', '')) { 40 | @include parse-cq($value); 41 | } 42 | } 43 | 44 | // Determine if parent module/block is queried modifier/state 45 | @else if str-index($property, '$-is-') == 1 or str-index($property, '$:') == 1 { 46 | $context: if(str-index($property, '$:') == 1, str-replace($property, '$', ''), str-replace($property, '$-is-', '')); 47 | 48 | @include context($module, $context) { 49 | @include parse-cq($value, $prevContext: ($module, $context)); 50 | } 51 | } 52 | 53 | // Determine if previously specified parent component is queried modifier/state 54 | @else if str-index($property, 'and-is-') == 1 or str-index($property, 'and:') == 1 { 55 | $context: if( 56 | str-index($property, 'and-is-'), 57 | str-replace($property, 'and-is-', ''), 58 | str-slice($property, str-index($property, ':'), str-length($property)) 59 | ); 60 | $prevContextVal: ('block': nth($prevContext, 1), 'context': nth($prevContext, 2)); 61 | $prevChunk: create-selector-from-context(map-get($prevContextVal, 'block'), map-get($prevContextVal, 'context')); 62 | $newContextVal: append(map-get($prevContextVal, 'context'), $context); 63 | $newChunk: create-selector-from-context(map-get($prevContextVal, 'block'), $newContextVal, $pipeContexts: true); 64 | 65 | $selector: (); 66 | 67 | @each $pChunk in $prevChunk { 68 | @each $chunk in selector-parse(str-replace(inspect($newChunk), ' ', ', ')) { 69 | @if str-index(inspect($chunk), $pChunk) == 1 { 70 | @each $item in & { 71 | @if str-index(inspect($item), $pChunk) { 72 | $selector: append($selector, selector-replace($item, $pChunk, $chunk), comma); 73 | } 74 | } 75 | } 76 | } 77 | } 78 | 79 | @at-root { 80 | #{$selector} { 81 | @include parse-cq($value, $prevContext: (map-get($prevContextVal, 'block'), $newContextVal)); 82 | } 83 | } 84 | } 85 | 86 | // Determine if specified parent component/module is queried modifier/state 87 | @else if str-index($property, '-is-') or (str-index($property, ':') and str-index($property, ':') > 1) { 88 | $component: if( 89 | str-index($property, ':'), 90 | str-slice($property, 1, str-index($property, ':') - 1), 91 | str-slice($property, 1, str-index($property, '-is-') - 1) 92 | ); 93 | $contextVal: if( 94 | str-index($property, ':'), 95 | str-slice($property, str-index($property, ':'), str-length($property)), 96 | str-slice($property, str-index($property, '-is-') + 4, str-length($property)) 97 | ); 98 | $block: if(str-index($component, '$') == 1, str-slice($component, 2), $module); 99 | $context: if(str-index($component, '$') == 1, ($block, $contextVal), (($block, $component), $contextVal)); 100 | 101 | @if $component == 'group' or $component == 'wrapper' { 102 | $context: ($component, ($prevContext, $contextVal), true); 103 | } 104 | 105 | @include context($context...) { 106 | @include parse-cq($value, $prevContext: $context); 107 | } 108 | } 109 | 110 | // Determine if current node is a child of the queried component/module 111 | @else if str-index($property, 'in-') == 1 { 112 | $component: str-replace($property, 'in-', ''); 113 | $context: if(str-index($component, '$') == 1, str-slice($component, 2), ($module, $component)); 114 | 115 | @include context($context) { 116 | @include parse-cq($value, $prevContext: ($context, '')); 117 | } 118 | } 119 | 120 | // $property defines pseudo-state/pseudo-element 121 | @else if str-index($property, ':') == 1 { 122 | @include pseudo-state(str-replace($property, ':', '')) { 123 | @include parse-cq($value); 124 | } 125 | } 126 | 127 | // $property defines .active styles 128 | @else if $property == 'active' { 129 | @include modifier('active') { 130 | @include parse-cq($value); 131 | } 132 | } 133 | 134 | // $property is for a component 135 | @else if type-of($value) == 'map' { 136 | @include component($property, $sub-component: $sub-component) { 137 | @include parse-cq($value, $sub-component: true, $prevContext: $property); 138 | } 139 | } 140 | 141 | // $property is a valid CSS property 142 | @else if index($css-properties, $property) { 143 | @if type-of($value) != 'map' { 144 | // for before/after pseudo elements 145 | @if $property == 'content' { 146 | $value: '"#{$value}"'; 147 | } 148 | 149 | #{$property}: $value; 150 | } 151 | } 152 | } 153 | } 154 | } -------------------------------------------------------------------------------- /src/utilities/_remove-junk.scss: -------------------------------------------------------------------------------- 1 | /// Remove junk characters from a selector string 2 | /// 3 | /// @param {string} $query 4 | @function remove-junk($query) { 5 | $query: str-replace($query, '.', ''); 6 | $query: str-replace($query, '[class*="#{$modifierGlue}', ''); 7 | $query: str-replace($query, '[class*="', ''); 8 | $query: str-replace($query, '"]', ''); 9 | 10 | @return $query; 11 | } -------------------------------------------------------------------------------- /src/utilities/_remove-modifiers.scss: -------------------------------------------------------------------------------- 1 | /// Remove modifiers from a selector 2 | /// 3 | /// @param {list} $selector - The selector from which to remove modifiers 4 | @function remove-modifiers($selector) { 5 | // convert selector to a string 6 | $selector: inspect(nth($selector, 1)); 7 | 8 | $modifier: ''; 9 | 10 | // Find out where the first modifier starts 11 | $modifier-index: str-index($selector, '"#{$modifierGlue}'); 12 | 13 | @if $modifier-index { 14 | // Strip the first part of the selector up until the first modifier 15 | $modifier: str-slice($selector, $modifier-index); 16 | // Find out where the modifier ends 17 | $modifier-end: str-index($modifier, '"]'); 18 | // Isolate the modifier 19 | $modifier: str-slice($modifier, 0, $modifier-end); 20 | // Remove the modifier from the selector 21 | $selector: str-replace($selector, $modifier, ''); 22 | // Remove junk characters 23 | $selector: str-replace($selector, '[class*=]', ''); 24 | // Recurse the function to eliminate any remainig modifiers 25 | $selector: remove-modifiers($selector); 26 | } 27 | 28 | @return $selector; 29 | } -------------------------------------------------------------------------------- /src/utilities/_selector-to-map.scss: -------------------------------------------------------------------------------- 1 | /// Convert a selector into a map of modules, components and modifiers 2 | /// 3 | /// @param {string} $selector 4 | @function selector-to-map($selector) { 5 | $module-map: ( 6 | 'module' : null, 7 | 'component': null, 8 | 'modifiers': null 9 | ); 10 | 11 | // Prepare selector for defragmentation 12 | $cleaned-selector: inspect(nth($selector, length($selector))); 13 | $cleaned-selector: selector-parse(str-replace($cleaned-selector, ' ', ', ')); 14 | $cleaned-selector: nth($cleaned-selector, length($cleaned-selector)); 15 | $cleaned-selector: remove-junk(inspect($cleaned-selector)); 16 | 17 | // Get and set module name 18 | $module-map: map-set($module-map, 'module', get-module-name($cleaned-selector)); 19 | 20 | // Get and set component name @TODO 21 | // $component-name: get-component($cleaned-selector); 22 | 23 | // Get and set modifiers @TODO 24 | // $modifiers: get-modifiers($cleaned-selector); 25 | 26 | @return $module-map; 27 | } -------------------------------------------------------------------------------- /src/utilities/_setting.scss: -------------------------------------------------------------------------------- 1 | /// Alias function to option() 2 | /// 3 | /// @param {map} $map 4 | /// @param {arglist} $keys 5 | @function setting($map, $keys...) { 6 | @return option($map, $keys...); 7 | } -------------------------------------------------------------------------------- /src/utilities/_strip-glue.scss: -------------------------------------------------------------------------------- 1 | /// Strip the glue (-- , __) from a string 2 | /// 3 | /// @param {string} $string 4 | /// @param {string} $glue 5 | @function strip-glue($string, $glue) { 6 | $placeholder: random(99999); 7 | 8 | $clean-string: str-replace($string, $string, $placeholder + $string); 9 | $clean-string: str-replace($clean-string, $placeholder + $glue, ''); 10 | 11 | @return $clean-string; 12 | } -------------------------------------------------------------------------------- /src/utilities/_theme.scss: -------------------------------------------------------------------------------- 1 | /// Get a value from $theme if it exists 2 | /// 3 | /// @param {arglist} $args 4 | @function theme($args...) { 5 | @if variable-exists('theme') and map-get-deep($theme, $args...) { 6 | @return map-get-deep($theme, $args...); 7 | } 8 | 9 | @else { 10 | @return ('theme', $args); 11 | } 12 | } -------------------------------------------------------------------------------- /src/utilities/_this.scss: -------------------------------------------------------------------------------- 1 | /// Get a value from the current module's configuration 2 | /// 3 | /// @param {arglist} $options 4 | @function this($options...) { 5 | $value: ''; 6 | 7 | @if (variable-exists('smart-config')) { 8 | $value: option($smart-config, $options...); 9 | } 10 | 11 | @else if (variable-exists('config')) { 12 | $value: option($config, $options...); 13 | } 14 | 15 | @else { 16 | @warn 'no config can be found for #{$module}'; 17 | } 18 | 19 | $debug: true; 20 | 21 | @if (variable-exists('sassConfigParser') and $sassConfigParser) { 22 | $value: call(get-function($sassConfigParser), $value); 23 | } 24 | 25 | $this: &; 26 | 27 | @if length($this) > 0 { 28 | @if str-index(inspect(nth($this, 1)), '%') == 1 { 29 | $debug: false; 30 | } 31 | } 32 | 33 | @if $debug and not $value and $value != false { 34 | @warn '#{$options} not found in #{$module} config'; 35 | } 36 | 37 | @return $value; 38 | } -------------------------------------------------------------------------------- /src/utilities/_value-enabled.scss: -------------------------------------------------------------------------------- 1 | /// Determine if a passed value should be considered 'enabled' 2 | /// 3 | /// @param {*} $value - the value to check 4 | /// @returns {*} - whether or not the option is enabled 5 | @function value-enabled($value) { 6 | // If the value is a map 7 | @if type-of($value) == 'map' { 8 | // Does the map contain the 'enabled' key? 9 | @if map-has-key($value, 'enabled') { 10 | @return map-get($value, 'enabled'); 11 | } 12 | @else { 13 | @return $value; 14 | } 15 | } 16 | // If the value is a list 17 | @else if type-of($value) == 'list' { 18 | // Is the first value a bool? 19 | @if type-of(nth($value, 1)) == 'bool' { 20 | @return nth($value, 1); 21 | } 22 | @else { 23 | @return $value; 24 | } 25 | } 26 | @else { 27 | @return $value; 28 | } 29 | } -------------------------------------------------------------------------------- /stylelint.config.js: -------------------------------------------------------------------------------- 1 | "use strict" 2 | 3 | module.exports = { 4 | "rules": { 5 | "at-rule-empty-line-before": [ "always", { 6 | except: [], 7 | ignore: [ 8 | "after-comment", 9 | "inside-block", 10 | "blockless-after-same-name-blockless", 11 | "blockless-after-blockless" 12 | ], 13 | } ], 14 | "at-rule-name-case": "lower", 15 | "at-rule-name-space-after": "always-single-line", 16 | "at-rule-semicolon-newline-after": "always", 17 | "block-closing-brace-newline-after": "always", 18 | "block-closing-brace-newline-before": "always-multi-line", 19 | "block-closing-brace-space-before": "always-single-line", 20 | "block-opening-brace-newline-after": "always-multi-line", 21 | "block-opening-brace-space-after": "always-single-line", 22 | "block-opening-brace-space-before": "always", 23 | "color-hex-case": "lower", 24 | "color-hex-length": "short", 25 | "comment-empty-line-before": [ "always", { 26 | except: ["first-nested"], 27 | ignore: ["stylelint-commands"], 28 | } ], 29 | "comment-whitespace-inside": "always", 30 | "custom-property-empty-line-before": [ "always", { 31 | except: [ 32 | "after-custom-property", 33 | "first-nested", 34 | ], 35 | ignore: [ 36 | "after-comment", 37 | "inside-single-line-block", 38 | ], 39 | } ], 40 | "declaration-bang-space-after": "never", 41 | "declaration-bang-space-before": "always", 42 | "declaration-block-semicolon-newline-after": "always-multi-line", 43 | "declaration-block-semicolon-space-after": "always-single-line", 44 | "declaration-block-semicolon-space-before": "never", 45 | "declaration-block-single-line-max-declarations": 1, 46 | "declaration-block-trailing-semicolon": "always", 47 | "declaration-colon-newline-after": "always-multi-line", 48 | "declaration-colon-space-after": "always-single-line", 49 | "declaration-colon-space-before": "never", 50 | "declaration-empty-line-before": [ "always", { 51 | except: [ 52 | "after-comment", 53 | "after-declaration", 54 | "first-nested" 55 | ], 56 | ignore: [ 57 | "after-comment", 58 | "inside-single-line-block", 59 | ], 60 | } ], 61 | "function-comma-space-after": "always-single-line", 62 | "function-comma-space-before": "never", 63 | "function-max-empty-lines": 0, 64 | "function-name-case": "lower", 65 | "function-parentheses-space-inside": "never-single-line", 66 | "indentation": 2, 67 | "length-zero-no-unit": true, 68 | "max-empty-lines": 1, 69 | "media-feature-colon-space-after": "always", 70 | "media-feature-colon-space-before": "never", 71 | "media-feature-name-case": "lower", 72 | "media-feature-parentheses-space-inside": "never", 73 | "media-feature-range-operator-space-after": "always", 74 | "media-feature-range-operator-space-before": "always", 75 | "media-query-list-comma-newline-after": "always-multi-line", 76 | "media-query-list-comma-space-after": "always-single-line", 77 | "media-query-list-comma-space-before": "never", 78 | "no-eol-whitespace": true, 79 | "number-leading-zero": "always", 80 | "number-no-trailing-zeros": true, 81 | "property-case": "lower", 82 | "rule-empty-line-before": [ "always", { 83 | except: ["first-nested"], 84 | ignore: ["after-comment"], 85 | } ], 86 | "selector-attribute-brackets-space-inside": "never", 87 | "selector-attribute-operator-space-after": "never", 88 | "selector-attribute-operator-space-before": "never", 89 | "selector-combinator-space-after": "always", 90 | "selector-combinator-space-before": "always", 91 | "selector-descendant-combinator-no-non-space": true, 92 | "selector-list-comma-space-before": "never", 93 | "selector-max-empty-lines": 0, 94 | "selector-pseudo-class-case": "lower", 95 | "selector-pseudo-class-parentheses-space-inside": "never", 96 | "selector-pseudo-element-case": "lower", 97 | "selector-pseudo-element-colon-notation": "double", 98 | "selector-type-case": "lower", 99 | "unit-case": "lower", 100 | "value-list-comma-newline-after": "always-multi-line", 101 | "value-list-comma-space-after": "always-single-line", 102 | "value-list-comma-space-before": "never", 103 | "value-list-max-empty-lines": 0, 104 | }, 105 | } -------------------------------------------------------------------------------- /test/mixins/_module.scss: -------------------------------------------------------------------------------- 1 | ///**************************************************************** 2 | /// One-Nexus - A toolkit for architecting and constructing 3 | /// front-end user-interfaces - https://github.com/esr360/One-Nexus 4 | /// 5 | /// @author [@esr360](http://twitter.com/esr360) 6 | ///**************************************************************** 7 | 8 | @include describe('Module') { 9 | $result: ''; 10 | 11 | @include it('Outputs static and chained selectors when only first param is passed') { 12 | @include module('foo') { 13 | $result: #{&}; 14 | } 15 | @include assert-equal( 16 | $result, '.foo, [class*="foo--"]' 17 | ); 18 | } 19 | 20 | @include it('Outputs expected selectors when multiple modules passed') { 21 | @include module(('foo', 'bar')) { 22 | $result: #{&}; 23 | } 24 | @include assert-equal( 25 | $result, '.foo, [class*="foo--"], .bar, [class*="bar--"]' 26 | ); 27 | } 28 | 29 | @include it('Outputs expected selectors when nested within another module') { 30 | @include module('foo') { 31 | @include module('bar') { 32 | $result: #{&}; 33 | } 34 | } 35 | @include assert-equal( 36 | $result, '.foo .bar, .foo [class*="bar--"], [class*="foo--"] .bar, [class*="foo--"] [class*="bar--"]' 37 | ); 38 | } 39 | 40 | @include it('Surpresses output when $disable-output is true') { 41 | $disable-output: true !global; 42 | 43 | @include assert { 44 | @include output { 45 | @include module('foo') { 46 | height: 100px; 47 | } 48 | } 49 | 50 | @include expect {} 51 | } 52 | 53 | $disable-output: false !global; 54 | } 55 | 56 | // @include it('Outputs CSS from config') { 57 | // @include assert('You can also describe the assertion...') { 58 | // @include output { 59 | // width: 14em + 2; 60 | // } 61 | // @include expect { 62 | // width: 16em; 63 | // } 64 | // } 65 | // } 66 | } -------------------------------------------------------------------------------- /test/tests.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const sassTrue = require('sass-true'); 3 | const sassFile = path.join(__dirname, 'tests.scss'); 4 | 5 | sassTrue.runSass({ file: sassFile }, { describe, it }); -------------------------------------------------------------------------------- /test/tests.scss: -------------------------------------------------------------------------------- 1 | // Import testing framework 2 | @import '../node_modules/sass-true/sass/true'; 3 | 4 | // Import the project 5 | @import '../src/cell'; 6 | 7 | // Import the test files 8 | @import 'utilities/config'; 9 | @import 'utilities/option'; 10 | @import 'utilities/setting'; 11 | @import 'utilities/this'; 12 | @import 'mixins/module'; -------------------------------------------------------------------------------- /test/utilities/_config.scss: -------------------------------------------------------------------------------- 1 | @include test-module('config') { 2 | @include test('merge a module`s default configuration with any custom values') { 3 | $default: ( 4 | 'breakpoints': ( 5 | 'break-1': 420px, 6 | 'break-2': 720px, 7 | 'break-3': 960px 8 | ) 9 | ); 10 | 11 | $custom: ( 12 | 'breakpoints': ( 13 | 'break-2': 800px, 14 | 'break-4': 1200px 15 | ) 16 | ); 17 | 18 | $actual: create-config($default, $custom); 19 | 20 | $expected: ( 21 | 'extendOptions': true, 22 | 'breakpoints': ( 23 | 'break-1': 420px, 24 | 'break-2': 800px, 25 | 'break-3': 960px, 26 | 'break-4': 1200px 27 | ) 28 | ); 29 | 30 | @include assert-equal($actual, $expected, 'should return the updated configuration'); 31 | } 32 | } -------------------------------------------------------------------------------- /test/utilities/_option.scss: -------------------------------------------------------------------------------- 1 | @include test-module('option') { 2 | @include test('get a nested option from a module`s config') { 3 | $map: ( 4 | 'foo' : ('bar' : 'baz') 5 | ); 6 | 7 | $actual: option($map, 'foo', 'bar'); 8 | $expected: 'baz'; 9 | 10 | @include assert-equal($actual, $expected, 'should return the expected nested value'); 11 | } 12 | } -------------------------------------------------------------------------------- /test/utilities/_setting.scss: -------------------------------------------------------------------------------- 1 | @include test-module('setting') { 2 | @include test('get a nested setting from a module`s config') { 3 | $map: ( 4 | 'foo' : ('bar' : true) 5 | ); 6 | 7 | $actual: setting($map, 'foo', 'bar'); 8 | $expected: true; 9 | 10 | @include assert-equal($actual, $expected, 'should return the expected nested value'); 11 | } 12 | } -------------------------------------------------------------------------------- /test/utilities/_this.scss: -------------------------------------------------------------------------------- 1 | @mixin foo($custom: ()) { 2 | $foo: create-config(( 3 | 'foo' : ('bar' : false) 4 | ), $custom); 5 | } 6 | 7 | @include test-module('this') { 8 | @include test('get a value from the current module`s configuration') { 9 | @include foo(( 10 | 'foo' : ('bar' : true) 11 | )); 12 | 13 | $actual: this('foo', 'bar'); 14 | $expected: true; 15 | 16 | @include assert-equal($actual, $expected, 'should return the expected value'); 17 | } 18 | } --------------------------------------------------------------------------------