diff --git a/.gitignore b/.gitignore index bbbfe88..b80a1f5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,10 @@ node_modules -bower_components coverage .DS_Store _site .sass-cache .jekyll-metadata *.scssc + +# https://github.com/sindresorhus/ama/issues/479#issuecomment-310661514 +package-lock.json diff --git a/README.md b/README.md index e90d8d2..4748d88 100644 --- a/README.md +++ b/README.md @@ -3,28 +3,23 @@ Categorize, sort, and filter a responsive grid of items. ```bash -npm install shufflejs --save +npm install shufflejs ``` -Shuffle is also available on bower as `shufflejs`. - ## Docs and Demos [All found here][homepage] -### Usage (with CommonJS) +### Usage (with ES6) ```js -var Shuffle = require('shufflejs'); +import Shuffle from 'shufflejs'; -var myShuffle = new Shuffle(document.getElementById('grid'), { +const shuffleInstance = new Shuffle(document.getElementById('grid'), { itemSelector: '.js-item', sizer: '.js-shuffle-sizer' }); ``` -## Shuffle 4.0 -Shuffle 4 removes jQuery as a dependency and is written in ES6. - ## Inspiration This project was inspired by [Isotope](http://isotope.metafizzy.co/) and [Packery](http://packery.metafizzy.co/). diff --git a/_data/items.json b/_data/items.json deleted file mode 100644 index 024c5fd..0000000 --- a/_data/items.json +++ /dev/null @@ -1,106 +0,0 @@ -[ - { - "groups": ["photography"], - "date": "2010-09-14", - "title": "Baseball", - "img": "baseball.png", - "original": "baseball.jpg", - "cols": [3, 4, 3] - }, - { - "groups": ["wallpaper", "3d"], - "date": "2011-08-14", - "title": "Tennis", - "img": "tennis-ball.png", - "original": "tennis-ball.jpg", - "extras": ["overlay"], - "cols": [3, 8, 6] - }, - { - "groups": ["wallpaper", "3d"], - "date": "2009-05-27", - "title": "iMac", - "img": "imac.png", - "original": "imac.jpg", - "cols": [3, 4, 3] - }, - { - "groups": ["graphics"], - "date": "2012-05-14", - "title": "Master Chief", - "img": "master-chief.png", - "original": "Master_Chief_Portrait_by_Eightfold_Studios.jpg", - "description": "Shuffle.js is a package for sorting, filtering, and laying out a group of items. It’s performant, responsive, and fast. Check out the demos!", - "extras": ["h2"], - "cols": [6, 4, 3] - }, - { - "groups": ["wallpaper", "3d"], - "date": "2009-09-14", - "title": "Eightfold", - "img": "es-blue.png", - "original": "es-blue.jpg", - "cols": [3, 4, 3] - }, - { - "groups": ["photography"], - "date": "2012-03-14", - "title": "Pumpkin", - "img": "pumpkin.png", - "original": "pumpkin.jpg", - "extras": ["overlay"], - "cols": [3, 8, 6] - }, - { - "groups": ["wallpaper", "3d"], - "date": "2013-05-19", - "title": "Vestride", - "img": "vestride-red.png", - "original": "vestride-red.jpg", - "extras": ["h2"], - "cols": [3, 8, 6] - }, - { - "groups": ["graphics"], - "date": "2013-02-01", - "title": "Newegg", - "img": "newegg.png", - "original": "newegg.jpg", - "description": "Shuffle.js is a package for sorting, filtering, and laying out a group of items. It’s performant, responsive, and fast. Check out the demos!", - "extras": ["h2"], - "cols": [6, 4, 3] - }, - { - "groups": ["wallpaper"], - "date": "2000-01-01", - "title": "Arc", - "img": "eightfoldarc.png", - "original": "eightfoldarc.jpg", - "cols": [3, 4, 3] - }, - { - "groups": ["photography"], - "date": "2012-07-04", - "title": "Ground", - "img": "ground.png", - "original": "ground!.jpg", - "cols": [3, 4, 3] - }, - { - "groups": ["wallpaper"], - "date": "2011-08-12", - "title": "Grass", - "img": "grassy-hills.png", - "original": "grassy-hills.tif", - "extras": ["overlay"], - "cols": [3, 8, 6] - }, - { - "groups": ["wallpaper", "3d"], - "date": "2013-05-19", - "title": "Vestride", - "img": "vestride-classy.png", - "original": "vestride-classy.jpg", - "cols": [3, 4, 3] - } -] diff --git a/_includes/credit-jake.html b/_includes/credit-jake.html deleted file mode 100644 index fafd5a9..0000000 --- a/_includes/credit-jake.html +++ /dev/null @@ -1,5 +0,0 @@ - diff --git a/_includes/events.html b/_includes/events.html deleted file mode 100644 index 0ad51dc..0000000 --- a/_includes/events.html +++ /dev/null @@ -1,21 +0,0 @@ -

Events

-

Shuffle emits an event when a layout happens and when elements are removed. The event names are Shuffle.EventType.LAYOUT and Shuffle.EventType.REMOVED.

-

Shuffle uses the global CustomEvent to create events. A polyfill for IE<=11 is bundled with Shuffle.

- -

Get notified when a layout happens

-
-
element.addEventListener(Shuffle.EventType.LAYOUT, function () {
-  console.log('Things finished moving!');
-});
-
- - -

Do something when an item is removed

-
-
element.addEventListener(Shuffle.EventType.REMOVED, function (evt) {
-  var detail = evt.detail;
-  console.log(this, evt, detail.collection, detail.shuffle);
-});
-
- - diff --git a/_includes/nav.html b/_includes/nav.html deleted file mode 100644 index 71c6184..0000000 --- a/_includes/nav.html +++ /dev/null @@ -1,46 +0,0 @@ - - diff --git a/_includes/picture-item.html b/_includes/picture-item.html deleted file mode 100644 index 19c49ff..0000000 --- a/_includes/picture-item.html +++ /dev/null @@ -1,23 +0,0 @@ -{% comment %} Ghetto conversion to JSON {% endcomment %} -{% capture groups %}["{{ item.groups | join: '","' }}"]{% endcapture %} -{% if item.extras | size: > 0 %} - {% capture extras %} picture-item--{{ item.extras | join: " picture-item--" }}{% endcapture %} -{% else %} - {% assign extras = "" %} -{% endif %} -{% assign description = item.description %} -
-
-
-
- - -
-
-
-
{{ item.title }}
-

{{ item.groups | join: ', ' }}

-
- {% if description %}{% if description == 'longDescription' %}{% assign description = site.longDescription %}{% endif %}

{{ description }}

{% endif %} -
-
diff --git a/_scss/_buttons.scss b/_scss/_buttons.scss deleted file mode 100644 index 2c86f13..0000000 --- a/_scss/_buttons.scss +++ /dev/null @@ -1,173 +0,0 @@ - - -.btn-group { - @include clearfix(); - - .btn { - float: left; - border-radius: 0; - - &:first-child { - border-radius: 6px 0 0 6px; - } - - &:last-child { - border-radius: 0 6px 6px 0; - } - } -} - -.btn, -button { - display: inline-block; - padding: .75em .375em; - -webkit-appearance: none; - text-align: center; - color: white; - border-radius: .0625em; - border: 0; - background-color: $wetAsphalt; - transition: .2s ease-out; - - &:hover { - background-color: lighten($wetAsphalt, 12); - text-decoration: none; - } - - &.active, - &:active { - background-color: $midnightBlue; - box-shadow: inset 0 1px 2px rgba(0,0,0,.3); - } - - &:active { - transition: none; - } -} - -.btn--warning { - background-color: $carrot; - - &:hover { - background-color: lighten($carrot, 8); - } - - &.active, - &:active { - background-color: $pumpkin; - // background-color: $carrot; - } -} - -.btn--primary { - background-color: $river; - - &:hover { - background-color: lighten($river, 8); - } - - &.active, - &:active { - // background-color: $belizeHole; - background-color: $river; - } -} - -.btn--danger { - background-color: $alizarin; - - &:hover { - background-color: lighten($alizarin, 8); - } - - &.active, - &:active { - // background-color: $pomegranate; - background-color: $alizarin; - } -} - -.btn--go { - background-color: $emerald; - - &:hover { - background-color: lighten($emerald, 8); - } - - &.active, - &:active { - // background-color: $nephritis; - background-color: $emerald; - } -} - - -.filter-group .btn { - position: relative; - - $size: 20px; - // Circle and check - &.active:before, - &.active:after { - content: ''; - position: absolute; - top: 50%; - left: 50%; - width: $size; - height: $size; - margin-left: -$size / 2; - margin-top: -$size / 2; - opacity: 0; - transition: .2s; - } - - // Circle - &:before { - background-color: $gray10; - border-radius: 50%; - } - - // Check - &:after { - background-size: 60%; - background-position: center center; - background-repeat: no-repeat; - background-image: url(../img/check.svg); - } - - &.active:before, - &.active:after { - opacity: 1; - } -} - - -@media ( max-width: 47.9375em ) { - - .btn, - button { - font-size: .875em; - } -} - -@media ( max-width: 30em ) { - - .btn, - button { - font-size: .75em; - } -} - - - - - - - - - - - - - - diff --git a/_scss/_faq.scss b/_scss/_faq.scss deleted file mode 100644 index be7c9ea..0000000 --- a/_scss/_faq.scss +++ /dev/null @@ -1,73 +0,0 @@ -// FAQ - -.search-section { - margin-top: 1em; - margin-bottom: 1em; -} - -input.faq-search { - -webkit-appearance: searchfield; - box-sizing: border-box; - width: 100%; - border: 2px solid $gray40; - border-radius: 4px; - padding: 0.5em; - font-size: 1.125em; - color: $gray40; - transition: .15s; - - &::placeholder { - color: $gray40; - transition: .15s; - } - - &:hover { - outline: 0; - color: $gray30; - border-color: $gray30; - - &::placeholder { - color: $gray30; - } - } - - &:focus { - outline: 0; - color: $nephritis; - border-color: $nephritis; - - &::placeholder { - color: $nephritis; - } - } -} - - -.question { - margin: 2em 0; - overflow: hidden; - transition: .2s ease-out; -} - -.question--collapsed { - height: 0 !important; // Needs to override inline style - margin: 0; - border-width: 0; -} - -.question--collapsed + .question { - margin-top: 0; -} - -.question--unanswered { - padding-top: 1.25em; - border-top: 2px solid $emerald; -} - -.question__title { - margin-top: 0; -} - -.question__answer { - margin-bottom: 0; -} diff --git a/_scss/_main.scss b/_scss/_main.scss deleted file mode 100644 index e69de29..0000000 diff --git a/_scss/_normalize.scss b/_scss/_normalize.scss deleted file mode 100644 index b0d3f97..0000000 --- a/_scss/_normalize.scss +++ /dev/null @@ -1,424 +0,0 @@ -/*! normalize.css v4.0.0 | MIT License | github.com/necolas/normalize.css */ - -/** - * 1. Change the default font family in all browsers (opinionated). - * 2. Prevent adjustments of font size after orientation changes in IE and iOS. - */ - -html { - font-family: sans-serif; /* 1 */ - -ms-text-size-adjust: 100%; /* 2 */ - -webkit-text-size-adjust: 100%; /* 2 */ -} - -/** - * Remove the margin in all browsers (opinionated). - */ - -body { - margin: 0; -} - -/* HTML5 display definitions - ========================================================================== */ - -/** - * Add the correct display in IE 9-. - * 1. Add the correct display in Edge, IE, and Firefox. - * 2. Add the correct display in IE. - */ - -article, -aside, -details, /* 1 */ -figcaption, -figure, -footer, -header, -main, /* 2 */ -menu, -nav, -section, -summary { /* 1 */ - display: block; -} - -/** - * Add the correct display in IE 9-. - */ - -audio, -canvas, -progress, -video { - display: inline-block; -} - -/** - * Add the correct display in iOS 4-7. - */ - -audio:not([controls]) { - display: none; - height: 0; -} - -/** - * Add the correct vertical alignment in Chrome, Firefox, and Opera. - */ - -progress { - vertical-align: baseline; -} - -/** - * Add the correct display in IE 10-. - * 1. Add the correct display in IE. - */ - -template, /* 1 */ -[hidden] { - display: none; -} - -/* Links - ========================================================================== */ - -/** - * Remove the gray background on active links in IE 10. - */ - -a { - background-color: transparent; -} - -/** - * Remove the outline on focused links when they are also active or hovered - * in all browsers (opinionated). - */ - -a:active, -a:hover { - outline-width: 0; -} - -/* Text-level semantics - ========================================================================== */ - -/** - * 1. Remove the bottom border in Firefox 39-. - * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari. - */ - -abbr[title] { - border-bottom: none; /* 1 */ - text-decoration: underline; /* 2 */ - text-decoration: underline dotted; /* 2 */ -} - -/** - * Prevent the duplicate application of `bolder` by the next rule in Safari 6. - */ - -b, -strong { - font-weight: inherit; -} - -/** - * Add the correct font weight in Chrome, Edge, and Safari. - */ - -b, -strong { - font-weight: bolder; -} - -/** - * Add the correct font style in Android 4.3-. - */ - -dfn { - font-style: italic; -} - -/** - * Correct the font size and margin on `h1` elements within `section` and - * `article` contexts in Chrome, Firefox, and Safari. - */ - -h1 { - font-size: 2em; - margin: 0.67em 0; -} - -/** - * Add the correct background and color in IE 9-. - */ - -mark { - background-color: #ff0; - color: #000; -} - -/** - * Add the correct font size in all browsers. - */ - -small { - font-size: 80%; -} - -/** - * Prevent `sub` and `sup` elements from affecting the line height in - * all browsers. - */ - -sub, -sup { - font-size: 75%; - line-height: 0; - position: relative; - vertical-align: baseline; -} - -sub { - bottom: -0.25em; -} - -sup { - top: -0.5em; -} - -/* Embedded content - ========================================================================== */ - -/** - * Remove the border on images inside links in IE 10-. - */ - -img { - border-style: none; -} - -/** - * Hide the overflow in IE. - */ - -svg:not(:root) { - overflow: hidden; -} - -/* Grouping content - ========================================================================== */ - -/** - * 1. Correct the inheritance and scaling of font size in all browsers. - * 2. Correct the odd `em` font sizing in all browsers. - */ - -code, -kbd, -pre, -samp { - font-family: monospace, monospace; /* 1 */ - font-size: 1em; /* 2 */ -} - -/** - * Add the correct margin in IE 8. - */ - -figure { - margin: 1em 40px; -} - -/** - * 1. Add the correct box sizing in Firefox. - * 2. Show the overflow in Edge and IE. - */ - -hr { - box-sizing: content-box; /* 1 */ - height: 0; /* 1 */ - overflow: visible; /* 2 */ -} - -/* Forms - ========================================================================== */ - -/** - * Change font properties to `inherit` in all browsers (opinionated). - */ - -button, -input, -select, -textarea { - font: inherit; -} - -/** - * Restore the font weight unset by the previous rule. - */ - -optgroup { - font-weight: bold; -} - -/** - * Show the overflow in IE. - * 1. Show the overflow in Edge. - * 2. Show the overflow in Edge, Firefox, and IE. - */ - -button, -input, /* 1 */ -select { /* 2 */ - overflow: visible; -} - -/** - * Remove the margin in Safari. - * 1. Remove the margin in Firefox and Safari. - */ - -button, -input, -select, -textarea { /* 1 */ - margin: 0; -} - -/** - * Remove the inheritence of text transform in Edge, Firefox, and IE. - * 1. Remove the inheritence of text transform in Firefox. - */ - -button, -select { /* 1 */ - text-transform: none; -} - -/** - * Change the cursor in all browsers (opinionated). - */ - -button, -[type="button"], -[type="reset"], -[type="submit"] { - cursor: pointer; -} - -/** - * Restore the default cursor to disabled elements unset by the previous rule. - */ - -[disabled] { - cursor: default; -} - -/** - * 1. Prevent a WebKit bug where (2) destroys native `audio` and `video` - * controls in Android 4. - * 2. Correct the inability to style clickable types in iOS. - */ - -button, -html [type="button"], /* 1 */ -[type="reset"], -[type="submit"] { - -webkit-appearance: button; /* 2 */ -} - -/** - * Remove the inner border and padding in Firefox. - */ - -button::-moz-focus-inner, -input::-moz-focus-inner { - border: 0; - padding: 0; -} - -/** - * Restore the focus styles unset by the previous rule. - */ - -button:-moz-focusring, -input:-moz-focusring { - outline: 1px dotted ButtonText; -} - -/** - * Change the border, margin, and padding in all browsers (opinionated). - */ - -fieldset { - border: 1px solid #c0c0c0; - margin: 0 2px; - padding: 0.35em 0.625em 0.75em; -} - -/** - * 1. Correct the text wrapping in Edge and IE. - * 2. Correct the color inheritance from `fieldset` elements in IE. - * 3. Remove the padding so developers are not caught out when they zero out - * `fieldset` elements in all browsers. - */ - -legend { - box-sizing: border-box; /* 1 */ - color: inherit; /* 2 */ - display: table; /* 1 */ - max-width: 100%; /* 1 */ - padding: 0; /* 3 */ - white-space: normal; /* 1 */ -} - -/** - * Remove the default vertical scrollbar in IE. - */ - -textarea { - overflow: auto; -} - -/** - * 1. Add the correct box sizing in IE 10-. - * 2. Remove the padding in IE 10-. - */ - -[type="checkbox"], -[type="radio"] { - box-sizing: border-box; /* 1 */ - padding: 0; /* 2 */ -} - -/** - * Correct the cursor style of increment and decrement buttons in Chrome. - */ - -[type="number"]::-webkit-inner-spin-button, -[type="number"]::-webkit-outer-spin-button { - height: auto; -} - -/** - * Correct the odd appearance of search inputs in Chrome and Safari. - */ - -[type="search"] { - -webkit-appearance: textfield; -} - -/** - * Remove the inner padding and cancel buttons in Chrome on OS X and - * Safari on OS X. - */ - -[type="search"]::-webkit-search-cancel-button, -[type="search"]::-webkit-search-decoration { - -webkit-appearance: none; -} diff --git a/_scss/_site-nav.scss b/_scss/_site-nav.scss deleted file mode 100644 index 085c1be..0000000 --- a/_scss/_site-nav.scss +++ /dev/null @@ -1,71 +0,0 @@ -.site-nav { - - .site-nav__title { - color: $clouds; - } - - .site-nav__title--first { - margin-top: 0; - } - - .btn { - width: 100%; - } - - .site-nav__tray { - transition: .2s; - overflow: hidden; - height: 300px; - background-color: $wetAsphalt; - } - - .site-nav__tray-inner { - padding-top: 30px; - padding-bottom: 30px; - } - - &.collapsed .site-nav__tray { - height: 0; - } - - .site-nav__band { - position: relative; - - &::before { - content: ''; - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 4px; - background: $wetAsphalt; - } - } - -} - -.site-footer { - margin-top: 2em; - padding: 1em 0; - background-color: $wetAsphalt; -} - -.has-code-block .code-block pre { - margin-bottom: 0; -} - -.has-code-block + .site-footer { - margin-top: 0; -} - -.site-footer__credit { - margin: 0; - text-align: right; -} - -@include breakpoint(sm, true) { - - .site-nav .btn { - margin-bottom: 5px; - } -} diff --git a/_scss/_type.scss b/_scss/_type.scss deleted file mode 100644 index 15a66aa..0000000 --- a/_scss/_type.scss +++ /dev/null @@ -1,138 +0,0 @@ -body { - font-family: 'Lato', 'Helvetica Neue', Helvetica, sans-serif; - color: $gray30; -} - -// Links -a { - text-decoration: none; - - &, - &:visited { - color: $river; - } - - &:hover { - text-decoration: underline; - } - - &:active { - color: $emerald; - } -} - -h2, -h3, -h4, -h5, -h6 { - color: $wetAsphalt; -} - - -// Headers -h1 { - margin: 20px 0; - font-weight: 300; - font-size: 4em; - line-height: 1; - color: $emerald; -} - -h2 { - position: relative; - font-size: 2.5em; - margin-bottom: 18px; - - // Bottom border BEHIND the descenders! - &::after { - content: ''; - position: absolute; - bottom: 0.1em; - left: 0; - z-index: -1; - width: 100%; - height: 2px; - background-color: $emerald; - transform: translateZ(0); - } -} - -h3 { - margin: .6667em 0 0.5em; - font-size: 1.5em; -} - -h4 { - font-size: 1.25em; -} - -@include breakpoint(sm, true) { - h1 { - font-size: 8vw; - margin: 3vw 0; - } - h2 { - font-size: 6vw; - margin: 2vw 0; - } -} - -h1 > a, -h2 > a, -h3 > a { - display: none; -} - -h1:hover > a, -h2:hover > a, -h3:hover > a { - position: absolute; - display: block; - top: 0; - left: -40px; - height: 50px; - width: 50px; - background: url('../img/link.svg') no-repeat; - overflow: hidden; - text-indent: -999em; -} - -.unstyled { - list-style-type: none; - padding: 0; - margin: 0; -} - - -.light-text-dark-box { - - p { - color: $clouds; - } - - a { - color: $clouds; - - &:hover { - color: white; - } - } -} - -:not(pre) > code { - padding: 0; - padding-top: 0.2em; - padding-bottom: 0.2em; - margin: 0; - font-size: 85%; - color: get-color(black); - background-color: rgba(0,0,0,0.04); - border-radius: 3px; - - &::before, - &::after { - letter-spacing: -0.2em; - content: "\00a0"; - } -} diff --git a/_scss/style.scss b/_scss/style.scss deleted file mode 100644 index 10837aa..0000000 --- a/_scss/style.scss +++ /dev/null @@ -1,12 +0,0 @@ -@import "variables"; -@import "mixins"; -@import "normalize"; -@import "global"; -@import "type"; -@import "grid"; -@import "site-nav"; -@import "demo-list"; -@import "faq"; -@import "buttons"; -@import "helpers"; -@import "compound-filters"; diff --git a/bower.json b/bower.json deleted file mode 100644 index b64efee..0000000 --- a/bower.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "name": "shufflejs", - "homepage": "https://github.com/Vestride/Shuffle", - "authors": [ - "Glen Cheney " - ], - "description": "Categorize, sort, and filter a responsive grid of items", - "main": "dist/shuffle.js", - "moduleType": [ - "amd", - "globals" - ], - "keywords": [ - "gallery", - "shuffle", - "layout", - "masonry", - "filter", - "sort", - "responsive", - "grid", - "mobile", - "tiles" - ], - "license": "MIT", - "ignore": [ - "**/.*", - "**/_*", - "css", - "img", - "js", - "node_modules", - "bower_components", - "gulp", - "gulpfile.js", - "favicon.png", - "index.html", - "robots.txt", - "test", - "tests", - "webpack.config.js", - "webpack.config.min.js" - ] -} diff --git a/css/shuffle-styles.css b/css/shuffle-styles.css deleted file mode 100644 index d504c8d..0000000 --- a/css/shuffle-styles.css +++ /dev/null @@ -1,122 +0,0 @@ -/*=============================================* Some styles to show off masonry layout -\*=============================================*/ -.picture-item { - height: 220px; - margin-top: 24px; - margin-left: 0; - /* shuffle items shouldn't have a left margin*/ } - .picture-item img { - display: block; - width: 100%; - max-width: none; - height: 100%; - -o-object-fit: cover; - object-fit: cover; } - .no-objectfit .picture-item img { - height: auto; - max-width: 100%; } - -.picture-item--h2 { - height: 464px; - /* 2x the height + 1 gutter */ } - -.picture-item__inner { - position: relative; - height: 100%; - overflow: hidden; - background: #ECF0F1; } - -.picture-item__blur { - display: none; } - -.picture-item__details, -.picture-item__description { - padding: 1em; - width: 100%; } - -.picture-item__description { - margin: 0; - padding-top: 0; - padding-right: 2em; } - -.picture-item__tags { - margin: 0; } - -@media screen and (min-width: 768px) { - .picture-item--overlay .picture-item__details { - position: absolute; - bottom: 0; - left: 0; - width: 100%; - background-color: rgba(0, 0, 0, 0.6); - color: white; - overflow: hidden; } - .picture-item--overlay .picture-item__description { - display: none; } - @supports ((-webkit-filter: blur(1px)) or (filter: blur(1px))) and ((-webkit-clip-path: inset(0 0 0 0)) or (clip-path: inset(0 0 0 0))) { - .picture-item--overlay .picture-item__blur { - position: absolute; - z-index: 1; - top: 0; - left: 0; - display: block; - -webkit-filter: blur(7px); - filter: blur(7px); - -webkit-clip-path: inset(170px 0 0 0); - clip-path: inset(170px 0 0 0); } - .picture-item--overlay .picture-item__details { - background: none; } - .picture-item--overlay .picture-item__tags, - .picture-item--overlay .picture-item__title { - position: relative; - z-index: 2; } } } - -/* - Shuffle needs either relative or absolute positioning on the container - It will set it for you, but it'll cause another style recalculation and layout. - AKA worse performance - so just set it here - */ -.my-shuffle-container { - position: relative; - overflow: hidden; } - -.my-sizer-element { - position: absolute; - opacity: 0; - visibility: hidden; } - -/* Animate in styles */ -.shuffle--animatein { - overflow: visible; } - -.shuffle--animatein .picture-item__inner { - opacity: 0; - -webkit-transform: translate(0, 220px); - transform: translate(0, 220px); } - -.shuffle--animatein .picture-item__inner--transition { - transition: all .6s ease; } - -.shuffle--animatein .picture-item.in .picture-item__inner { - opacity: 1; - -webkit-transform: translate(0, 0); - transform: translate(0, 0); } - -@media screen and (max-width: 767px) { - .picture-item { - height: auto; - margin-top: 20px; } - .picture-item.picture-item--h2 { - height: auto; } - .picture-item .picture-item__details, - .picture-item .picture-item__description { - font-size: .875em; - padding: .625em; } - .picture-item .picture-item__description { - padding-right: .875em; - padding-bottom: 1.25em; } - .filter > .row, - .filter > .row > div { - margin: 10px 0; } - .m-nofloat { - float: none; } } diff --git a/css/style.css b/css/style.css deleted file mode 100644 index 7baa6dc..0000000 --- a/css/style.css +++ /dev/null @@ -1,1460 +0,0 @@ -@charset "UTF-8"; -/*! normalize.css v4.0.0 | MIT License | github.com/necolas/normalize.css */ -/** - * 1. Change the default font family in all browsers (opinionated). - * 2. Prevent adjustments of font size after orientation changes in IE and iOS. - */ -html { - font-family: sans-serif; - /* 1 */ - -ms-text-size-adjust: 100%; - /* 2 */ - -webkit-text-size-adjust: 100%; - /* 2 */ } - -/** - * Remove the margin in all browsers (opinionated). - */ -body { - margin: 0; } - -/* HTML5 display definitions - ========================================================================== */ -/** - * Add the correct display in IE 9-. - * 1. Add the correct display in Edge, IE, and Firefox. - * 2. Add the correct display in IE. - */ -article, -aside, -details, -figcaption, -figure, -footer, -header, -main, -menu, -nav, -section, -summary { - /* 1 */ - display: block; } - -/** - * Add the correct display in IE 9-. - */ -audio, -canvas, -progress, -video { - display: inline-block; } - -/** - * Add the correct display in iOS 4-7. - */ -audio:not([controls]) { - display: none; - height: 0; } - -/** - * Add the correct vertical alignment in Chrome, Firefox, and Opera. - */ -progress { - vertical-align: baseline; } - -/** - * Add the correct display in IE 10-. - * 1. Add the correct display in IE. - */ -template, -[hidden] { - display: none; } - -/* Links - ========================================================================== */ -/** - * Remove the gray background on active links in IE 10. - */ -a { - background-color: transparent; } - -/** - * Remove the outline on focused links when they are also active or hovered - * in all browsers (opinionated). - */ -a:active, -a:hover { - outline-width: 0; } - -/* Text-level semantics - ========================================================================== */ -/** - * 1. Remove the bottom border in Firefox 39-. - * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari. - */ -abbr[title] { - border-bottom: none; - /* 1 */ - text-decoration: underline; - /* 2 */ - text-decoration: underline dotted; - /* 2 */ } - -/** - * Prevent the duplicate application of `bolder` by the next rule in Safari 6. - */ -b, -strong { - font-weight: inherit; } - -/** - * Add the correct font weight in Chrome, Edge, and Safari. - */ -b, -strong { - font-weight: bolder; } - -/** - * Add the correct font style in Android 4.3-. - */ -dfn { - font-style: italic; } - -/** - * Correct the font size and margin on `h1` elements within `section` and - * `article` contexts in Chrome, Firefox, and Safari. - */ -h1 { - font-size: 2em; - margin: 0.67em 0; } - -/** - * Add the correct background and color in IE 9-. - */ -mark { - background-color: #ff0; - color: #000; } - -/** - * Add the correct font size in all browsers. - */ -small { - font-size: 80%; } - -/** - * Prevent `sub` and `sup` elements from affecting the line height in - * all browsers. - */ -sub, -sup { - font-size: 75%; - line-height: 0; - position: relative; - vertical-align: baseline; } - -sub { - bottom: -0.25em; } - -sup { - top: -0.5em; } - -/* Embedded content - ========================================================================== */ -/** - * Remove the border on images inside links in IE 10-. - */ -img { - border-style: none; } - -/** - * Hide the overflow in IE. - */ -svg:not(:root) { - overflow: hidden; } - -/* Grouping content - ========================================================================== */ -/** - * 1. Correct the inheritance and scaling of font size in all browsers. - * 2. Correct the odd `em` font sizing in all browsers. - */ -code, -kbd, -pre, -samp { - font-family: monospace, monospace; - /* 1 */ - font-size: 1em; - /* 2 */ } - -/** - * Add the correct margin in IE 8. - */ -figure { - margin: 1em 40px; } - -/** - * 1. Add the correct box sizing in Firefox. - * 2. Show the overflow in Edge and IE. - */ -hr { - box-sizing: content-box; - /* 1 */ - height: 0; - /* 1 */ - overflow: visible; - /* 2 */ } - -/* Forms - ========================================================================== */ -/** - * Change font properties to `inherit` in all browsers (opinionated). - */ -button, -input, -select, -textarea { - font: inherit; } - -/** - * Restore the font weight unset by the previous rule. - */ -optgroup { - font-weight: bold; } - -/** - * Show the overflow in IE. - * 1. Show the overflow in Edge. - * 2. Show the overflow in Edge, Firefox, and IE. - */ -button, -input, -select { - /* 2 */ - overflow: visible; } - -/** - * Remove the margin in Safari. - * 1. Remove the margin in Firefox and Safari. - */ -button, -input, -select, -textarea { - /* 1 */ - margin: 0; } - -/** - * Remove the inheritence of text transform in Edge, Firefox, and IE. - * 1. Remove the inheritence of text transform in Firefox. - */ -button, -select { - /* 1 */ - text-transform: none; } - -/** - * Change the cursor in all browsers (opinionated). - */ -button, -[type="button"], -[type="reset"], -[type="submit"] { - cursor: pointer; } - -/** - * Restore the default cursor to disabled elements unset by the previous rule. - */ -[disabled] { - cursor: default; } - -/** - * 1. Prevent a WebKit bug where (2) destroys native `audio` and `video` - * controls in Android 4. - * 2. Correct the inability to style clickable types in iOS. - */ -button, -html [type="button"], -[type="reset"], -[type="submit"] { - -webkit-appearance: button; - /* 2 */ } - -/** - * Remove the inner border and padding in Firefox. - */ -button::-moz-focus-inner, -input::-moz-focus-inner { - border: 0; - padding: 0; } - -/** - * Restore the focus styles unset by the previous rule. - */ -button:-moz-focusring, -input:-moz-focusring { - outline: 1px dotted ButtonText; } - -/** - * Change the border, margin, and padding in all browsers (opinionated). - */ -fieldset { - border: 1px solid #c0c0c0; - margin: 0 2px; - padding: 0.35em 0.625em 0.75em; } - -/** - * 1. Correct the text wrapping in Edge and IE. - * 2. Correct the color inheritance from `fieldset` elements in IE. - * 3. Remove the padding so developers are not caught out when they zero out - * `fieldset` elements in all browsers. - */ -legend { - box-sizing: border-box; - /* 1 */ - color: inherit; - /* 2 */ - display: table; - /* 1 */ - max-width: 100%; - /* 1 */ - padding: 0; - /* 3 */ - white-space: normal; - /* 1 */ } - -/** - * Remove the default vertical scrollbar in IE. - */ -textarea { - overflow: auto; } - -/** - * 1. Add the correct box sizing in IE 10-. - * 2. Remove the padding in IE 10-. - */ -[type="checkbox"], -[type="radio"] { - box-sizing: border-box; - /* 1 */ - padding: 0; - /* 2 */ } - -/** - * Correct the cursor style of increment and decrement buttons in Chrome. - */ -[type="number"]::-webkit-inner-spin-button, -[type="number"]::-webkit-outer-spin-button { - height: auto; } - -/** - * Correct the odd appearance of search inputs in Chrome and Safari. - */ -[type="search"] { - -webkit-appearance: textfield; } - -/** - * Remove the inner padding and cancel buttons in Chrome on OS X and - * Safari on OS X. - */ -[type="search"]::-webkit-search-cancel-button, -[type="search"]::-webkit-search-decoration { - -webkit-appearance: none; } - -*, -*::before, -*::after { - box-sizing: border-box; } - -main { - overflow: hidden; } - -pre.max-height { - max-height: 30em; } - -picture { - display: block; } - -img { - display: block; - max-width: 100%; - height: auto; } - -figure { - margin: 0; } - -ul ul { - padding-left: 1.25em; - margin: 0; - list-style-type: circle; } - -li { - line-height: 1.4; } - -nav > a { - display: block; - margin: 5px 0; } - -.breathable-list li { - line-height: 1.7; } - -.filter__label { - margin: 0 0 3px; } - -.filter__search { - margin: 5px 0; } - -.sort-options { - margin-top: 10px; } - -#be-social h2 { - margin-bottom: 32px; } - -body { - font-family: 'Lato', 'Helvetica Neue', Helvetica, sans-serif; - color: #5D6D77; } - -a { - text-decoration: none; } - a, a:visited { - color: #3498DB; } - a:hover { - text-decoration: underline; } - a:active { - color: #2ECC71; } - -h2, -h3, -h4, -h5, -h6 { - color: #34495E; } - -h1 { - margin: 20px 0; - font-weight: 300; - font-size: 4em; - line-height: 1; - color: #2ECC71; } - -h2 { - position: relative; - font-size: 2.5em; - margin-bottom: 18px; } - h2::after { - content: ''; - position: absolute; - bottom: 0.1em; - left: 0; - z-index: -1; - width: 100%; - height: 2px; - background-color: #2ECC71; - -webkit-transform: translateZ(0); - transform: translateZ(0); } - -h3 { - margin: .6667em 0 0.5em; - font-size: 1.5em; } - -h4 { - font-size: 1.25em; } - -@media screen and (max-width: 767px) { - h1 { - font-size: 8vw; - margin: 3vw 0; } - h2 { - font-size: 6vw; - margin: 2vw 0; } } - -h1 > a, -h2 > a, -h3 > a { - display: none; } - -h1:hover > a, -h2:hover > a, -h3:hover > a { - position: absolute; - display: block; - top: 0; - left: -40px; - height: 50px; - width: 50px; - background: url("../img/link.svg") no-repeat; - overflow: hidden; - text-indent: -999em; } - -.unstyled { - list-style-type: none; - padding: 0; - margin: 0; } - -.light-text-dark-box p { - color: #ECF0F1; } - -.light-text-dark-box a { - color: #ECF0F1; } - .light-text-dark-box a:hover { - color: white; } - -:not(pre) > code { - padding: 0; - padding-top: 0.2em; - padding-bottom: 0.2em; - margin: 0; - font-size: 85%; - color: get-color(black); - background-color: rgba(0, 0, 0, 0.04); - border-radius: 3px; } - :not(pre) > code::before, :not(pre) > code::after { - letter-spacing: -0.2em; - content: "\00a0"; } - -.container { - padding-left: 3.5%; - padding-right: 3.5%; } - .container::before, .container::after { - content: " "; - display: table; } - .container::after { - clear: both; } - -.row { - margin-left: auto; - margin-right: auto; } - .row::before, .row::after { - content: " "; - display: table; } - .row::after { - clear: both; } - .row .row { - margin-left: -8px; - margin-right: -8px; } - .row--centered { - display: -webkit-box; - display: -ms-flexbox; - display: flex; - -ms-flex-wrap: wrap; - flex-wrap: wrap; - -webkit-box-pack: center; - -ms-flex-pack: center; - justify-content: center; } - -.aspect { - position: relative; - width: 100%; - height: 0; - overflow: hidden; - padding-bottom: 100%; } - -.aspect--16x9 { - padding-bottom: 56.25%; } - -.aspect--9x16 { - padding-bottom: 177.77778%; } - -.aspect--4x3 { - padding-bottom: 75%; } - -.aspect--3x4 { - padding-bottom: 133.33333%; } - -.aspect--3x2 { - padding-bottom: 66.66667%; } - -.aspect--3x1 { - padding-bottom: 33.33333%; } - -.aspect--2x3 { - padding-bottom: 150%; } - -.aspect--2x1 { - padding-bottom: 50%; } - -.aspect--1x2 { - padding-bottom: 200%; } - -.aspect--1x1 { - padding-bottom: 100%; } - -.aspect--none { - height: auto; - padding-bottom: 0; - overflow: visible; } - .aspect--none > .aspect__inner { - position: static; } - -.aspect > div, -.aspect__inner { - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; } - -.col-1\@xs, .col-2\@xs, .col-3\@xs, .col-4\@xs, .col-5\@xs, .col-6\@xs, .col-7\@xs, .col-8\@xs, .col-9\@xs, .col-10\@xs, .col-11\@xs, .col-12\@xs, .col-1\@sm, .col-2\@sm, .col-3\@sm, .col-4\@sm, .col-5\@sm, .col-6\@sm, .col-7\@sm, .col-8\@sm, .col-9\@sm, .col-10\@sm, .col-11\@sm, .col-12\@sm, .col-1\@md, .col-2\@md, .col-3\@md, .col-4\@md, .col-5\@md, .col-6\@md, .col-7\@md, .col-8\@md, .col-9\@md, .col-10\@md, .col-11\@md, .col-12\@md, .col-1\@lg, .col-2\@lg, .col-3\@lg, .col-4\@lg, .col-5\@lg, .col-6\@lg, .col-7\@lg, .col-8\@lg, .col-9\@lg, .col-10\@lg, .col-11\@lg, .col-12\@lg { - position: relative; - box-sizing: border-box; - min-height: 1px; - padding-left: 8px; - padding-right: 8px; } - -.col-1\@xs, .col-2\@xs, .col-3\@xs, .col-4\@xs, .col-5\@xs, .col-6\@xs, .col-7\@xs, .col-8\@xs, .col-9\@xs, .col-10\@xs, .col-11\@xs, .col-12\@xs { - float: left; } - -.aspect--16x9\@xs { - padding-bottom: 56.25%; } - -.aspect--9x16\@xs { - padding-bottom: 177.77778%; } - -.aspect--4x3\@xs { - padding-bottom: 75%; } - -.aspect--3x4\@xs { - padding-bottom: 133.33333%; } - -.aspect--3x2\@xs { - padding-bottom: 66.66667%; } - -.aspect--3x1\@xs { - padding-bottom: 33.33333%; } - -.aspect--2x3\@xs { - padding-bottom: 150%; } - -.aspect--2x1\@xs { - padding-bottom: 50%; } - -.aspect--1x2\@xs { - padding-bottom: 200%; } - -.aspect--1x1\@xs { - padding-bottom: 100%; } - -.aspect--none\@xs { - height: auto; - padding-bottom: 0; - overflow: visible; } - .aspect--none\@xs > .aspect__inner { - position: static; } - -.col-1\@xs { - width: 16.66667%; } - -.col-2\@xs { - width: 33.33333%; } - -.col-3\@xs { - width: 50%; } - -.col-4\@xs { - width: 66.66667%; } - -.col-5\@xs { - width: 83.33333%; } - -.col-6\@xs { - width: 100%; } - -.col-pull-0\@xs { - right: auto; } - -.col-pull-1\@xs { - right: 16.66667%; } - -.col-pull-2\@xs { - right: 33.33333%; } - -.col-pull-3\@xs { - right: 50%; } - -.col-pull-4\@xs { - right: 66.66667%; } - -.col-pull-5\@xs { - right: 83.33333%; } - -.col-pull-6\@xs { - right: 100%; } - -.col-push-0\@xs { - left: auto; } - -.col-push-1\@xs { - left: 16.66667%; } - -.col-push-2\@xs { - left: 33.33333%; } - -.col-push-3\@xs { - left: 50%; } - -.col-push-4\@xs { - left: 66.66667%; } - -.col-push-5\@xs { - left: 83.33333%; } - -.col-push-6\@xs { - left: 100%; } - -.col-offset-0\@xs { - margin-left: 0%; } - -.col-offset-1\@xs { - margin-left: 16.66667%; } - -.col-offset-2\@xs { - margin-left: 33.33333%; } - -.col-offset-3\@xs { - margin-left: 50%; } - -.col-offset-4\@xs { - margin-left: 66.66667%; } - -.col-offset-5\@xs { - margin-left: 83.33333%; } - -.col-offset-6\@xs { - margin-left: 100%; } - -@media screen and (min-width: 768px) { - .col-1\@sm, .col-2\@sm, .col-3\@sm, .col-4\@sm, .col-5\@sm, .col-6\@sm, .col-7\@sm, .col-8\@sm, .col-9\@sm, .col-10\@sm, .col-11\@sm, .col-12\@sm { - float: left; } - .aspect--16x9\@sm { - padding-bottom: 56.25%; } - .aspect--9x16\@sm { - padding-bottom: 177.77778%; } - .aspect--4x3\@sm { - padding-bottom: 75%; } - .aspect--3x4\@sm { - padding-bottom: 133.33333%; } - .aspect--3x2\@sm { - padding-bottom: 66.66667%; } - .aspect--3x1\@sm { - padding-bottom: 33.33333%; } - .aspect--2x3\@sm { - padding-bottom: 150%; } - .aspect--2x1\@sm { - padding-bottom: 50%; } - .aspect--1x2\@sm { - padding-bottom: 200%; } - .aspect--1x1\@sm { - padding-bottom: 100%; } - .aspect--none\@sm { - height: auto; - padding-bottom: 0; - overflow: visible; } - .aspect--none\@sm > .aspect__inner { - position: static; } - .col-1\@sm { - width: 8.33333%; } - .col-2\@sm { - width: 16.66667%; } - .col-3\@sm { - width: 25%; } - .col-4\@sm { - width: 33.33333%; } - .col-5\@sm { - width: 41.66667%; } - .col-6\@sm { - width: 50%; } - .col-7\@sm { - width: 58.33333%; } - .col-8\@sm { - width: 66.66667%; } - .col-9\@sm { - width: 75%; } - .col-10\@sm { - width: 83.33333%; } - .col-11\@sm { - width: 91.66667%; } - .col-12\@sm { - width: 100%; } - .col-pull-0\@sm { - right: auto; } - .col-pull-1\@sm { - right: 8.33333%; } - .col-pull-2\@sm { - right: 16.66667%; } - .col-pull-3\@sm { - right: 25%; } - .col-pull-4\@sm { - right: 33.33333%; } - .col-pull-5\@sm { - right: 41.66667%; } - .col-pull-6\@sm { - right: 50%; } - .col-pull-7\@sm { - right: 58.33333%; } - .col-pull-8\@sm { - right: 66.66667%; } - .col-pull-9\@sm { - right: 75%; } - .col-pull-10\@sm { - right: 83.33333%; } - .col-pull-11\@sm { - right: 91.66667%; } - .col-pull-12\@sm { - right: 100%; } - .col-push-0\@sm { - left: auto; } - .col-push-1\@sm { - left: 8.33333%; } - .col-push-2\@sm { - left: 16.66667%; } - .col-push-3\@sm { - left: 25%; } - .col-push-4\@sm { - left: 33.33333%; } - .col-push-5\@sm { - left: 41.66667%; } - .col-push-6\@sm { - left: 50%; } - .col-push-7\@sm { - left: 58.33333%; } - .col-push-8\@sm { - left: 66.66667%; } - .col-push-9\@sm { - left: 75%; } - .col-push-10\@sm { - left: 83.33333%; } - .col-push-11\@sm { - left: 91.66667%; } - .col-push-12\@sm { - left: 100%; } - .col-offset-0\@sm { - margin-left: 0%; } - .col-offset-1\@sm { - margin-left: 8.33333%; } - .col-offset-2\@sm { - margin-left: 16.66667%; } - .col-offset-3\@sm { - margin-left: 25%; } - .col-offset-4\@sm { - margin-left: 33.33333%; } - .col-offset-5\@sm { - margin-left: 41.66667%; } - .col-offset-6\@sm { - margin-left: 50%; } - .col-offset-7\@sm { - margin-left: 58.33333%; } - .col-offset-8\@sm { - margin-left: 66.66667%; } - .col-offset-9\@sm { - margin-left: 75%; } - .col-offset-10\@sm { - margin-left: 83.33333%; } - .col-offset-11\@sm { - margin-left: 91.66667%; } - .col-offset-12\@sm { - margin-left: 100%; } - .container { - padding-left: 7%; - padding-right: 7%; } - .row { - max-width: 1200px; } } - -@media screen and (min-width: 1024px) { - .col-1\@md, .col-2\@md, .col-3\@md, .col-4\@md, .col-5\@md, .col-6\@md, .col-7\@md, .col-8\@md, .col-9\@md, .col-10\@md, .col-11\@md, .col-12\@md { - float: left; } - .aspect--16x9\@md { - padding-bottom: 56.25%; } - .aspect--9x16\@md { - padding-bottom: 177.77778%; } - .aspect--4x3\@md { - padding-bottom: 75%; } - .aspect--3x4\@md { - padding-bottom: 133.33333%; } - .aspect--3x2\@md { - padding-bottom: 66.66667%; } - .aspect--3x1\@md { - padding-bottom: 33.33333%; } - .aspect--2x3\@md { - padding-bottom: 150%; } - .aspect--2x1\@md { - padding-bottom: 50%; } - .aspect--1x2\@md { - padding-bottom: 200%; } - .aspect--1x1\@md { - padding-bottom: 100%; } - .aspect--none\@md { - height: auto; - padding-bottom: 0; - overflow: visible; } - .aspect--none\@md > .aspect__inner { - position: static; } - .col-1\@md { - width: 8.33333%; } - .col-2\@md { - width: 16.66667%; } - .col-3\@md { - width: 25%; } - .col-4\@md { - width: 33.33333%; } - .col-5\@md { - width: 41.66667%; } - .col-6\@md { - width: 50%; } - .col-7\@md { - width: 58.33333%; } - .col-8\@md { - width: 66.66667%; } - .col-9\@md { - width: 75%; } - .col-10\@md { - width: 83.33333%; } - .col-11\@md { - width: 91.66667%; } - .col-12\@md { - width: 100%; } - .col-pull-0\@md { - right: auto; } - .col-pull-1\@md { - right: 8.33333%; } - .col-pull-2\@md { - right: 16.66667%; } - .col-pull-3\@md { - right: 25%; } - .col-pull-4\@md { - right: 33.33333%; } - .col-pull-5\@md { - right: 41.66667%; } - .col-pull-6\@md { - right: 50%; } - .col-pull-7\@md { - right: 58.33333%; } - .col-pull-8\@md { - right: 66.66667%; } - .col-pull-9\@md { - right: 75%; } - .col-pull-10\@md { - right: 83.33333%; } - .col-pull-11\@md { - right: 91.66667%; } - .col-pull-12\@md { - right: 100%; } - .col-push-0\@md { - left: auto; } - .col-push-1\@md { - left: 8.33333%; } - .col-push-2\@md { - left: 16.66667%; } - .col-push-3\@md { - left: 25%; } - .col-push-4\@md { - left: 33.33333%; } - .col-push-5\@md { - left: 41.66667%; } - .col-push-6\@md { - left: 50%; } - .col-push-7\@md { - left: 58.33333%; } - .col-push-8\@md { - left: 66.66667%; } - .col-push-9\@md { - left: 75%; } - .col-push-10\@md { - left: 83.33333%; } - .col-push-11\@md { - left: 91.66667%; } - .col-push-12\@md { - left: 100%; } - .col-offset-0\@md { - margin-left: 0%; } - .col-offset-1\@md { - margin-left: 8.33333%; } - .col-offset-2\@md { - margin-left: 16.66667%; } - .col-offset-3\@md { - margin-left: 25%; } - .col-offset-4\@md { - margin-left: 33.33333%; } - .col-offset-5\@md { - margin-left: 41.66667%; } - .col-offset-6\@md { - margin-left: 50%; } - .col-offset-7\@md { - margin-left: 58.33333%; } - .col-offset-8\@md { - margin-left: 66.66667%; } - .col-offset-9\@md { - margin-left: 75%; } - .col-offset-10\@md { - margin-left: 83.33333%; } - .col-offset-11\@md { - margin-left: 91.66667%; } - .col-offset-12\@md { - margin-left: 100%; } } - -.code-block { - position: relative; - overflow: visible; - margin-left: calc(-3.5vw - 8px); - margin-right: calc(-3.5vw - 8px); } - .code-block pre { - position: relative; - z-index: 1; - min-height: 56px; - padding-top: 1em; - padding-bottom: 1em; - padding-left: calc(3.5vw + 8px); - padding-right: calc(3.5vw + 8px); - margin: .5em 0; } - -@media screen and (min-width: 768px) { - .code-block { - margin-left: calc(-7vw - 8px); - margin-right: calc(-7vw - 8px); } - .code-block pre { - position: relative; - z-index: 1; - padding-left: calc(7vw + 8px); - padding-right: calc(7vw + 8px); } } - -@media (min-width: 1395px) { - .code-block { - margin-left: calc(((100vw - 1200px) / -2) - 8px); - margin-right: calc(((100vw - 1200px) / -2) - 8px); } - .code-block pre { - padding-left: calc(((100vw - 1200px) / 2) + 8px); - padding-right: calc(((100vw - 1200px) / 2) + 8px); } } - -.site-nav .site-nav__title { - color: #ECF0F1; } - -.site-nav .site-nav__title--first { - margin-top: 0; } - -.site-nav .btn { - width: 100%; } - -.site-nav .site-nav__tray { - transition: .2s; - overflow: hidden; - height: 300px; - background-color: #34495E; } - -.site-nav .site-nav__tray-inner { - padding-top: 30px; - padding-bottom: 30px; } - -.site-nav.collapsed .site-nav__tray { - height: 0; } - -.site-nav .site-nav__band { - position: relative; } - .site-nav .site-nav__band::before { - content: ''; - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 4px; - background: #34495E; } - -.site-footer { - margin-top: 2em; - padding: 1em 0; - background-color: #34495E; } - -.has-code-block .code-block pre { - margin-bottom: 0; } - -.has-code-block + .site-footer { - margin-top: 0; } - -.site-footer__credit { - margin: 0; - text-align: right; } - -@media screen and (max-width: 767px) { - .site-nav .btn { - margin-bottom: 5px; } } - -.demo-list .figure-wrap { - position: relative; - z-index: 1; } - -.demo-list .figure-wrap, -.demo-list .figure-wrap img { - -webkit-transform: translateZ(0); - transform: translateZ(0); - transition: .1s ease; } - -.demo-list:hover .figure-wrap { - -webkit-transform: scale3d(1, 1, 1); - transform: scale3d(1, 1, 1); } - .demo-list:hover .figure-wrap img { - -webkit-filter: grayscale(1); - filter: grayscale(1); } - -.demo-list:hover .figure-wrap:hover { - z-index: 2; - -webkit-transform: scale3d(1.05, 1.05, 1); - transform: scale3d(1.05, 1.05, 1); } - .demo-list:hover .figure-wrap:hover img { - -webkit-filter: none; - filter: none; } - -.demo-list .figure-wrap:nth-child(4n + 1) { - margin-left: 0; } - -.demo-list .figure-wrap > a { - display: block; } - -.demo-list .figure-wrap figcaption { - margin-top: .5em; - margin-bottom: 1em; } - -.demo-link-container::before { - content: '➜'; - color: #2ECC71; - margin-right: 5px; } - -span.demo-link-container::before { - margin-left: 5px; } - -@media screen and (max-width: 47.9375em) { - .demo-list + .demo-list { - margin-top: 1em; } - .figure-wrap:nth-child(odd) { - margin-left: 0; } - .figure-wrap:nth-child(n + 3) { - margin-top: 1em; } } - -.search-section { - margin-top: 1em; - margin-bottom: 1em; } - -input.faq-search { - -webkit-appearance: searchfield; - box-sizing: border-box; - width: 100%; - border: 2px solid #95A5A6; - border-radius: 4px; - padding: 0.5em; - font-size: 1.125em; - color: #95A5A6; - transition: .15s; } - input.faq-search::-webkit-input-placeholder { - color: #95A5A6; - transition: .15s; } - input.faq-search:-ms-input-placeholder { - color: #95A5A6; - transition: .15s; } - input.faq-search::placeholder { - color: #95A5A6; - transition: .15s; } - input.faq-search:hover { - outline: 0; - color: #5D6D77; - border-color: #5D6D77; } - input.faq-search:hover::-webkit-input-placeholder { - color: #5D6D77; } - input.faq-search:hover:-ms-input-placeholder { - color: #5D6D77; } - input.faq-search:hover::placeholder { - color: #5D6D77; } - input.faq-search:focus { - outline: 0; - color: #27AE60; - border-color: #27AE60; } - input.faq-search:focus::-webkit-input-placeholder { - color: #27AE60; } - input.faq-search:focus:-ms-input-placeholder { - color: #27AE60; } - input.faq-search:focus::placeholder { - color: #27AE60; } - -.question { - margin: 2em 0; - overflow: hidden; - transition: .2s ease-out; } - -.question--collapsed { - height: 0 !important; - margin: 0; - border-width: 0; } - -.question--collapsed + .question { - margin-top: 0; } - -.question--unanswered { - padding-top: 1.25em; - border-top: 2px solid #2ECC71; } - -.question__title { - margin-top: 0; } - -.question__answer { - margin-bottom: 0; } - -.btn-group::before, .btn-group::after { - content: " "; - display: table; } - -.btn-group::after { - clear: both; } - -.btn-group .btn { - float: left; - border-radius: 0; } - .btn-group .btn:first-child { - border-radius: 6px 0 0 6px; } - .btn-group .btn:last-child { - border-radius: 0 6px 6px 0; } - -.btn, -button { - display: inline-block; - padding: .75em .375em; - -webkit-appearance: none; - text-align: center; - color: white; - border-radius: .0625em; - border: 0; - background-color: #34495E; - transition: .2s ease-out; } - .btn:hover, - button:hover { - background-color: #4a6885; - text-decoration: none; } - .btn.active, .btn:active, - button.active, - button:active { - background-color: #2C3E50; - box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.3); } - .btn:active, - button:active { - transition: none; } - -.btn--warning { - background-color: #E67E22; } - .btn--warning:hover { - background-color: #ea9347; } - .btn--warning.active, .btn--warning:active { - background-color: #D35400; } - -.btn--primary { - background-color: #3498DB; } - .btn--primary:hover { - background-color: #57aae1; } - .btn--primary.active, .btn--primary:active { - background-color: #3498DB; } - -.btn--danger { - background-color: #E74C3C; } - .btn--danger:hover { - background-color: #eb6d60; } - .btn--danger.active, .btn--danger:active { - background-color: #E74C3C; } - -.btn--go { - background-color: #2ECC71; } - .btn--go:hover { - background-color: #4cd787; } - .btn--go.active, .btn--go:active { - background-color: #2ECC71; } - -.filter-group .btn { - position: relative; } - .filter-group .btn.active:before, .filter-group .btn.active:after { - content: ''; - position: absolute; - top: 50%; - left: 50%; - width: 20px; - height: 20px; - margin-left: -10px; - margin-top: -10px; - opacity: 0; - transition: .2s; } - .filter-group .btn:before { - background-color: #2C3E50; - border-radius: 50%; } - .filter-group .btn:after { - background-size: 60%; - background-position: center center; - background-repeat: no-repeat; - background-image: url(../img/check.svg); } - .filter-group .btn.active:before, .filter-group .btn.active:after { - opacity: 1; } - -@media (max-width: 47.9375em) { - .btn, - button { - font-size: .875em; } } - -@media (max-width: 30em) { - .btn, - button { - font-size: .75em; } } - -.text-center { - text-align: center; } - -.ib { - display: inline-block; } - -@media screen and (max-width: 767px) { - .hidden\@xs { - display: none; } } - -.hidden { - display: none !important; - visibility: hidden; } - -.visuallyhidden { - border: 0; - clip: rect(0 0 0 0); - height: 1px; - margin: -1px; - overflow: hidden; - padding: 0; - position: absolute; - width: 1px; } - -.clearfix, -.clearfix::after { - content: " "; - display: table; - clear: both; } - -.pull-left { - float: left; } - -.pull-right { - float: right; } - -.full-width { - width: 100%; } - -.full-height { - height: 100%; } - -.hide-text { - font: 0/0 a; - color: transparent; - text-shadow: none; - background-color: transparent; - border: 0; } - -.table-center-wrap { - display: table; - table-layout: fixed; } - -.table-center { - display: table-cell; - vertical-align: middle; } - -.compound-filter-options { - margin-top: 20px; - margin-bottom: 40px; } - -.filter-group--compound button { - width: 40px; - height: 40px; - padding: 0; } - -.filter-group--compound label { - cursor: pointer; } - -.filter-group--compound .ib + .ib { - margin-left: 8px; } - -.filter-group__label--compound { - margin: 0 0 5px; } - -.shape-shuffle-container { - position: relative; - overflow: hidden; } - -.shape { - position: relative; - margin-left: 0; - margin-top: 10px; } - .shape .shape__space { - width: 100%; - height: 100%; - background-color: black; - border-style: solid; - border-width: 0; - border-color: transparent; } - -.shape--blue .shape__space { - background-color: #3498DB; - border-bottom-color: #3498DB; } - -.shape--red .shape__space { - background-color: #E74C3C; - border-bottom-color: #E74C3C; } - -.shape--orange .shape__space { - background-color: #F39C12; - border-bottom-color: #F39C12; } - -.shape--green .shape__space { - background-color: #2ECC71; - border-bottom-color: #2ECC71; } - -.shape--circle .shape__space { - border-radius: 50%; } - -.shape--diamond .shape__space { - -webkit-transform: rotate(45deg) scale(0.70711); - transform: rotate(45deg) scale(0.70711); } - -.shape--triangle .shape__space { - padding-top: 9px; - height: 0; - width: 0; - border-width: 0 66px 114px 66px; - background-color: transparent; - margin: auto; } - -@media (min-width: 425px) { - .shape--triangle .shape__space { - padding-top: 12px; - height: 0; - width: 0; - border-width: 0 90px 156px 90px; } } - -@media (min-width: 600px) { - .shape--triangle .shape__space { - padding-top: 17.5px; - height: 0; - width: 0; - border-width: 0 131px 227px 131px; } } - -@media (min-width: 768px) { - .shape--triangle .shape__space { - padding-top: 10px; - height: 0; - width: 0; - border-width: 0 74px 128px 74px; } } - -@media (min-width: 1024px) { - .shape--triangle .shape__space { - padding-top: 13.5px; - height: 0; - width: 0; - border-width: 0 102px 177px 102px; } } - -@media (min-width: 1200px) { - .shape--triangle .shape__space { - padding-top: 18px; - height: 0; - width: 0; - border-width: 0 135px 234px 135px; } } - -@media (min-width: 1392px) { - .shape--triangle .shape__space { - padding-top: 19px; - height: 0; - width: 0; - border-width: 0 142px 246px 142px; } } diff --git a/dist/shuffle.js b/dist/shuffle.js index 4e07531..507c236 100644 --- a/dist/shuffle.js +++ b/dist/shuffle.js @@ -1,55 +1,77 @@ (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : typeof define === 'function' && define.amd ? define(factory) : - (global.shuffle = factory()); + (global.Shuffle = factory()); }(this, (function () { 'use strict'; -// Polyfill for creating CustomEvents on IE9/10/11 - -// code pulled from: -// https://github.com/d4tocchini/customevent-polyfill -// https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent#Polyfill - -try { - var ce = new window.CustomEvent('test'); - ce.preventDefault(); - if (ce.defaultPrevented !== true) { - // IE has problems with .preventDefault() on custom events - // http://stackoverflow.com/questions/23349191 - throw new Error('Could not prevent default'); - } -} catch(e) { - var CustomEvent$1 = function(event, params) { - var evt, origPrevent; - params = params || { - bubbles: false, - cancelable: false, - detail: undefined - }; - - evt = document.createEvent("CustomEvent"); - evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail); - origPrevent = evt.preventDefault; - evt.preventDefault = function () { - origPrevent.call(this); - try { - Object.defineProperty(this, 'defaultPrevented', { - get: function () { - return true; - } - }); - } catch(e) { - this.defaultPrevented = true; +function E () { + // Keep this empty so it's easier to inherit from + // (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3) +} + +E.prototype = { + on: function (name, callback, ctx) { + var e = this.e || (this.e = {}); + + (e[name] || (e[name] = [])).push({ + fn: callback, + ctx: ctx + }); + + return this; + }, + + once: function (name, callback, ctx) { + var self = this; + function listener () { + self.off(name, listener); + callback.apply(ctx, arguments); + } + + listener._ = callback; + return this.on(name, listener, ctx); + }, + + emit: function (name) { + var data = [].slice.call(arguments, 1); + var evtArr = ((this.e || (this.e = {}))[name] || []).slice(); + var i = 0; + var len = evtArr.length; + + for (i; i < len; i++) { + evtArr[i].fn.apply(evtArr[i].ctx, data); + } + + return this; + }, + + off: function (name, callback) { + var e = this.e || (this.e = {}); + var evts = e[name]; + var liveEvents = []; + + if (evts && callback) { + for (var i = 0, len = evts.length; i < len; i++) { + if (evts[i].fn !== callback && evts[i].fn._ !== callback) + liveEvents.push(evts[i]); } - }; - return evt; - }; + } - CustomEvent$1.prototype = window.Event.prototype; - window.CustomEvent = CustomEvent$1; // expose definition to window -} + // Remove event from queue to prevent memory leak + // Suggested by https://github.com/lazd + // Ref: https://github.com/scottcorgan/tiny-emitter/commit/c6ebfaa9bc973b33d110a84a307742b7cf94c953#commitcomment-5024910 + + (liveEvents.length) + ? e[name] = liveEvents + : delete e[name]; + + return this; + } +}; -var proto = Element.prototype; +var index = E; + +var proto = typeof Element !== 'undefined' ? Element.prototype : {}; var vendor = proto.matches || proto.matchesSelector || proto.webkitMatchesSelector @@ -57,7 +79,7 @@ var vendor = proto.matches || proto.msMatchesSelector || proto.oMatchesSelector; -var index = match; +var index$1 = match; /** * Match `el` to `selector`. @@ -69,6 +91,7 @@ var index = match; */ function match(el, selector) { + if (!el || el.nodeType !== 1) return false; if (vendor) return vendor.call(el, selector); var nodes = el.parentNode.querySelectorAll(selector); for (var i = 0; i < nodes.length; i++) { @@ -77,101 +100,6 @@ function match(el, selector) { return false; } -var commonjsGlobal = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; - - - - - -function createCommonjsModule(fn, module) { - return module = { exports: {} }, fn(module, module.exports), module.exports; -} - -var index$1 = createCommonjsModule(function (module) { -'use strict'; - -// there's 3 implementations written in increasing order of efficiency - -// 1 - no Set type is defined -function uniqNoSet(arr) { - var ret = []; - - for (var i = 0; i < arr.length; i++) { - if (ret.indexOf(arr[i]) === -1) { - ret.push(arr[i]); - } - } - - return ret; -} - -// 2 - a simple Set type is defined -function uniqSet(arr) { - var seen = new Set(); - return arr.filter(function (el) { - if (!seen.has(el)) { - seen.add(el); - return true; - } - - return false; - }); -} - -// 3 - a standard Set type is defined and it has a forEach method -function uniqSetWithForEach(arr) { - var ret = []; - - (new Set(arr)).forEach(function (el) { - ret.push(el); - }); - - return ret; -} - -// V8 currently has a broken implementation -// https://github.com/joyent/node/issues/8449 -function doesForEachActuallyWork() { - var ret = false; - - (new Set([true])).forEach(function (el) { - ret = el; - }); - - return ret === true; -} - -if ('Set' in commonjsGlobal) { - if (typeof Set.prototype.forEach === 'function' && doesForEachActuallyWork()) { - module.exports = uniqSetWithForEach; - } else { - module.exports = uniqSet; - } -} else { - module.exports = uniqNoSet; -} -}); - -var immutable = extend; - -var hasOwnProperty = Object.prototype.hasOwnProperty; - -function extend() { - var target = {}; - - for (var i = 0; i < arguments.length; i++) { - var source = arguments[i]; - - for (var key in source) { - if (hasOwnProperty.call(source, key)) { - target[key] = source[key]; - } - } - } - - return target -} - var index$2 = throttle; /** @@ -279,6 +207,48 @@ var createClass = function () { }; }(); + + + + + + + + +var inherits = function (subClass, superClass) { + if (typeof superClass !== "function" && superClass !== null) { + throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); + } + + subClass.prototype = Object.create(superClass && superClass.prototype, { + constructor: { + value: subClass, + enumerable: false, + writable: true, + configurable: true + } + }); + if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; +}; + + + + + + + + + + + +var possibleConstructorReturn = function (self, call) { + if (!self) { + throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); + } + + return call && (typeof call === "object" || typeof call === "function") ? call : self; +}; + var Point = function () { /** @@ -310,6 +280,52 @@ var Point = function () { return Point; }(); +var Rect = function () { + /** + * Class for representing rectangular regions. + * https://github.com/google/closure-library/blob/master/closure/goog/math/rect.js + * @param {number} x Left. + * @param {number} y Top. + * @param {number} w Width. + * @param {number} h Height. + * @param {number} id Identifier + * @constructor + */ + function Rect(x, y, w, h, id) { + classCallCheck(this, Rect); + + this.id = id; + + /** @type {number} */ + this.left = x; + + /** @type {number} */ + this.top = y; + + /** @type {number} */ + this.width = w; + + /** @type {number} */ + this.height = h; + } + + /** + * Returns whether two rectangles intersect. + * @param {Rect} a A Rectangle. + * @param {Rect} b A Rectangle. + * @return {boolean} Whether a and b intersect. + */ + + + createClass(Rect, null, [{ + key: "intersects", + value: function intersects(a, b) { + return a.left < b.left + b.width && b.left < a.left + a.width && a.top < b.top + b.height && b.top < a.top + a.height; + } + }]); + return Rect; +}(); + var Classes = { BASE: 'shuffle', SHUFFLE_ITEM: 'shuffle-item', @@ -326,7 +342,19 @@ var ShuffleItem = function () { id$1 += 1; this.id = id$1; this.element = element; + + /** + * Used to separate items for layout and shrink. + */ this.isVisible = true; + + /** + * Used to determine if a transition will happen. By the time the _layout + * and _shrink methods get the ShuffleItem instances, the `isVisible` value + * has already been changed by the separation methods, so this property is + * needed to know if the item was visible/hidden before the shrink/layout. + */ + this.isHidden = false; } createClass(ShuffleItem, [{ @@ -335,6 +363,7 @@ var ShuffleItem = function () { this.isVisible = true; this.element.classList.remove(Classes.HIDDEN); this.element.classList.add(Classes.VISIBLE); + this.element.removeAttribute('aria-hidden'); } }, { key: 'hide', @@ -342,6 +371,7 @@ var ShuffleItem = function () { this.isVisible = false; this.element.classList.remove(Classes.VISIBLE); this.element.classList.add(Classes.HIDDEN); + this.element.setAttribute('aria-hidden', true); } }, { key: 'init', @@ -403,14 +433,17 @@ ShuffleItem.Css = { opacity: 1, visibility: 'visible' }, - after: {} + after: { + transitionDelay: '' + } }, HIDDEN: { before: { opacity: 0 }, after: { - visibility: 'hidden' + visibility: 'hidden', + transitionDelay: '' } } }; @@ -421,14 +454,14 @@ ShuffleItem.Scale = { }; var element = document.body || document.documentElement; -var e$1 = document.createElement('div'); -e$1.style.cssText = 'width:10px;padding:2px;box-sizing:border-box;'; -element.appendChild(e$1); +var e = document.createElement('div'); +e.style.cssText = 'width:10px;padding:2px;box-sizing:border-box;'; +element.appendChild(e); -var width = window.getComputedStyle(e$1, null).width; +var width = window.getComputedStyle(e, null).width; var ret = width === '10px'; -element.removeChild(e$1); +element.removeChild(e); /** * Retrieve the computed style for an element, parsed as a float. @@ -493,8 +526,8 @@ var defaults$1 = { // You can return `undefined` from the `by` function to revert to DOM order. function sorter(arr, options) { - var opts = immutable(defaults$1, options); - var original = [].slice.call(arr); + var opts = Object.assign({}, defaults$1, options); + var original = Array.from(arr); var revert = false; if (!arr.length) { @@ -700,7 +733,7 @@ function getItemPosition(_ref) { var shortColumnIndex = getShortColumn(setY, buffer); // Position the item - var point = new Point(Math.round(gridSize * shortColumnIndex), Math.round(setY[shortColumnIndex])); + var point = new Point(gridSize * shortColumnIndex, setY[shortColumnIndex]); // Update the columns array with the new values for each column. // e.g. before the update the columns could be [250, 0, 0, 0] for an item @@ -713,18 +746,126 @@ function getItemPosition(_ref) { return point; } -function toArray(arrayLike) { - return Array.prototype.slice.call(arrayLike); +/** + * This method attempts to center items. This method could potentially be slow + * with a large number of items because it must place items, then check every + * previous item to ensure there is no overlap. + * @param {Array.} itemRects Item data objects. + * @param {number} containerWidth Width of the containing element. + * @return {Array.} + */ +function getCenteredPositions(itemRects, containerWidth) { + var rowMap = {}; + + // Populate rows by their offset because items could jump between rows like: + // a c + // bbb + itemRects.forEach(function (itemRect) { + if (rowMap[itemRect.top]) { + // Push the point to the last row array. + rowMap[itemRect.top].push(itemRect); + } else { + // Start of a new row. + rowMap[itemRect.top] = [itemRect]; + } + }); + + // For each row, find the end of the last item, then calculate + // the remaining space by dividing it by 2. Then add that + // offset to the x position of each point. + var rects = []; + var rows = []; + var centeredRows = []; + Object.keys(rowMap).forEach(function (key) { + var itemRects = rowMap[key]; + rows.push(itemRects); + var lastItem = itemRects[itemRects.length - 1]; + var end = lastItem.left + lastItem.width; + var offset = Math.round((containerWidth - end) / 2); + + var finalRects = itemRects; + var canMove = false; + if (offset > 0) { + var newRects = []; + canMove = itemRects.every(function (r) { + var newRect = new Rect(r.left + offset, r.top, r.width, r.height, r.id); + + // Check all current rects to make sure none overlap. + var noOverlap = !rects.some(function (r) { + return Rect.intersects(newRect, r); + }); + + newRects.push(newRect); + return noOverlap; + }); + + // If none of the rectangles overlapped, the whole group can be centered. + if (canMove) { + finalRects = newRects; + } + } + + // If the items are not going to be offset, ensure that the original + // placement for this row will not overlap previous rows (row-spanning + // elements could be in the way). + if (!canMove) { + var intersectingRect = void 0; + var hasOverlap = itemRects.some(function (itemRect) { + return rects.some(function (r) { + var intersects = Rect.intersects(itemRect, r); + if (intersects) { + intersectingRect = r; + } + return intersects; + }); + }); + + // If there is any overlap, replace the overlapping row with the original. + if (hasOverlap) { + var rowIndex = centeredRows.findIndex(function (items) { + return items.includes(intersectingRect); + }); + centeredRows.splice(rowIndex, 1, rows[rowIndex]); + } + } + + rects = rects.concat(finalRects); + centeredRows.push(finalRects); + }); + + // Reduce array of arrays to a single array of points. + // https://stackoverflow.com/a/10865042/373422 + // Then reset sort back to how the items were passed to this method. + // Remove the wrapper object with index, map to a Point. + return [].concat.apply([], centeredRows) // eslint-disable-line prefer-spread + .sort(function (a, b) { + return a.id - b.id; + }).map(function (itemRect) { + return new Point(itemRect.left, itemRect.top); + }); +} + +/** + * Hyphenates a javascript style string to a css one. For example: + * MozBoxSizing -> -moz-box-sizing. + * @param {string} str The string to hyphenate. + * @return {string} The hyphenated string. + */ +function hyphenate(str) { + return str.replace(/([A-Z])/g, function (str, m1) { + return "-" + m1.toLowerCase(); + }); } -function arrayIncludes(array, obj) { - return array.indexOf(obj) > -1; +function arrayUnique(x) { + return Array.from(new Set(x)); } // Used for unique instance variables var id = 0; -var Shuffle = function () { +var Shuffle = function (_TinyEmitter) { + inherits(Shuffle, _TinyEmitter); /** * Categorize, sort, and filter a responsive grid of items. @@ -737,31 +878,33 @@ var Shuffle = function () { var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; classCallCheck(this, Shuffle); - this.options = immutable(Shuffle.options, options); + var _this = possibleConstructorReturn(this, (Shuffle.__proto__ || Object.getPrototypeOf(Shuffle)).call(this)); + + _this.options = Object.assign({}, Shuffle.options, options); - this.useSizer = false; - this.lastSort = {}; - this.group = Shuffle.ALL_ITEMS; - this.lastFilter = Shuffle.ALL_ITEMS; - this.isEnabled = true; - this.isDestroyed = false; - this.isInitialized = false; - this._transitions = []; - this.isTransitioning = false; - this._queue = []; + _this.lastSort = {}; + _this.group = Shuffle.ALL_ITEMS; + _this.lastFilter = Shuffle.ALL_ITEMS; + _this.isEnabled = true; + _this.isDestroyed = false; + _this.isInitialized = false; + _this._transitions = []; + _this.isTransitioning = false; + _this._queue = []; - var el = this._getElementOption(element); + var el = _this._getElementOption(element); if (!el) { throw new TypeError('Shuffle needs to be initialized with an element.'); } - this.element = el; - this.id = 'shuffle_' + id; + _this.element = el; + _this.id = 'shuffle_' + id; id += 1; - this._init(); - this.isInitialized = true; + _this._init(); + _this.isInitialized = true; + return _this; } createClass(Shuffle, [{ @@ -771,20 +914,27 @@ var Shuffle = function () { this.options.sizer = this._getElementOption(this.options.sizer); - if (this.options.sizer) { - this.useSizer = true; - } - // Add class and invalidate styles this.element.classList.add(Shuffle.Classes.BASE); // Set initial css for each item - this._initItems(); + this._initItems(this.items); // Bind resize events this._onResize = this._getResizeFunction(); window.addEventListener('resize', this._onResize); + // If the page has not already emitted the `load` event, call layout on load. + // This avoids layout issues caused by images and fonts loading after the + // instance has been initialized. + if (document.readyState !== 'complete') { + var layout = this.layout.bind(this); + window.addEventListener('load', function onLoad() { + window.removeEventListener('load', onLoad); + layout(); + }); + } + // Get container css all in one request. Causes reflow var containerCss = window.getComputedStyle(this.element, null); var containerWidth = Shuffle.getSize(this.element).width; @@ -804,13 +954,13 @@ var Shuffle = function () { // First, however, a synchronous layout must be caused for the previous // styles to be applied without transitions. this.element.offsetWidth; // eslint-disable-line no-unused-expressions - this._setTransitions(); + this.setItemTransitions(this.items); this.element.style.transition = 'height ' + this.options.speed + 'ms ' + this.options.easing; } /** * Returns a throttled and proxied function for the resize handler. - * @return {Function} + * @return {function} * @private */ @@ -870,11 +1020,11 @@ var Shuffle = function () { /** * Filter the elements by a category. - * @param {string} [category] Category to filter by. If it's given, the last - * category will be used to filter the items. + * @param {string|string[]|function(Element):boolean} [category] Category to + * filter by. If it's given, the last category will be used to filter the items. * @param {Array} [collection] Optionally filter a collection. Defaults to * all the items. - * @return {!{visible: Array, hidden: Array}} + * @return {{visible: ShuffleItem[], hidden: ShuffleItem[]}} * @private */ @@ -903,16 +1053,16 @@ var Shuffle = function () { /** * Returns an object containing the visible and hidden elements. - * @param {string|Function} category Category or function to filter by. - * @param {Array.} items A collection of items to filter. - * @return {!{visible: Array, hidden: Array}} + * @param {string|string[]|function(Element):boolean} category Category or function to filter by. + * @param {ShuffleItem[]} items A collection of items to filter. + * @return {{visible: ShuffleItem[], hidden: ShuffleItem[]}} * @private */ }, { key: '_getFilteredSets', value: function _getFilteredSets(category, items) { - var _this = this; + var _this2 = this; var visible = []; var hidden = []; @@ -925,7 +1075,7 @@ var Shuffle = function () { // whether to hide it or not. } else { items.forEach(function (item) { - if (_this._doesPassFilter(category, item.element)) { + if (_this2._doesPassFilter(category, item.element)) { visible.push(item); } else { hidden.push(item); @@ -941,7 +1091,7 @@ var Shuffle = function () { /** * Test an item to see if it passes a category. - * @param {string|Function} category Category or function to filter by. + * @param {string|string[]|function():boolean} category Category or function to filter by. * @param {Element} element An element to test. * @return {boolean} Whether it passes the category/filter. * @private @@ -959,7 +1109,7 @@ var Shuffle = function () { var keys = this.options.delimeter ? attr.split(this.options.delimeter) : JSON.parse(attr); function testCategory(category) { - return arrayIncludes(keys, category); + return keys.includes(category); } if (Array.isArray(category)) { @@ -969,7 +1119,7 @@ var Shuffle = function () { return category.every(testCategory); } - return arrayIncludes(keys, category); + return keys.includes(category); } /** @@ -995,15 +1145,13 @@ var Shuffle = function () { /** * Set the initial css for each item - * @param {Array.} [items] Optionally specifiy at set to initialize. + * @param {ShuffleItem[]} items Set to initialize. * @private */ }, { key: '_initItems', - value: function _initItems() { - var items = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.items; - + value: function _initItems(items) { items.forEach(function (item) { item.init(); }); @@ -1011,14 +1159,13 @@ var Shuffle = function () { /** * Remove element reference and styles. + * @param {ShuffleItem[]} items Set to dispose. * @private */ }, { key: '_disposeItems', - value: function _disposeItems() { - var items = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.items; - + value: function _disposeItems(items) { items.forEach(function (item) { item.dispose(); }); @@ -1038,32 +1185,37 @@ var Shuffle = function () { /** * Sets css transform transition on a group of elements. This is not executed * at the same time as `item.init` so that transitions don't occur upon - * initialization of Shuffle. - * @param {Array.} items Shuffle items to set transitions on. - * @private + * initialization of a new Shuffle instance. + * @param {ShuffleItem[]} items Shuffle items to set transitions on. + * @protected */ }, { - key: '_setTransitions', - value: function _setTransitions() { - var items = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.items; - + key: 'setItemTransitions', + value: function setItemTransitions(items) { var speed = this.options.speed; var easing = this.options.easing; + var positionProps = this.options.useTransforms ? ['transform'] : ['top', 'left']; - var str = this.options.useTransforms ? 'transform ' + speed + 'ms ' + easing + ', opacity ' + speed + 'ms ' + easing : 'top ' + speed + 'ms ' + easing + ', left ' + speed + 'ms ' + easing + ', opacity ' + speed + 'ms ' + easing; + // Allow users to transtion other properties if they exist in the `before` + // css mapping of the shuffle item. + var properties = positionProps.concat(Object.keys(ShuffleItem.Css.HIDDEN.before).map(function (k) { + return hyphenate(k); + })).join(); items.forEach(function (item) { - item.element.style.transition = str; + item.element.style.transitionDuration = speed + 'ms'; + item.element.style.transitionTimingFunction = easing; + item.element.style.transitionProperty = properties; }); } }, { key: '_getItems', value: function _getItems() { - var _this2 = this; + var _this3 = this; - return toArray(this.element.children).filter(function (el) { - return index(el, _this2.options.itemSelector); + return Array.from(this.element.children).filter(function (el) { + return index$1(el, _this3.options.itemSelector); }).map(function (el) { return new ShuffleItem(el); }); @@ -1072,15 +1224,17 @@ var Shuffle = function () { /** * When new elements are added to the shuffle container, update the array of * items because that is the order `_layout` calls them. + * @param {ShuffleItem[]} items Items to track. + * @return {Shuffle[]} */ }, { - key: '_updateItemsOrder', - value: function _updateItemsOrder() { - var children = this.element.children; - this.items = sorter(this.items, { + key: '_mergeNewItems', + value: function _mergeNewItems(items) { + var children = Array.from(this.element.children); + return sorter(this.items.concat(items), { by: function by(element) { - return Array.prototype.indexOf.call(children, element); + return children.indexOf(element); } }); } @@ -1117,7 +1271,7 @@ var Shuffle = function () { size = this.options.columnWidth(containerWidth); // columnWidth option isn't a function, are they using a sizing element? - } else if (this.useSizer) { + } else if (this.options.sizer) { size = Shuffle.getSize(this.options.sizer).width; // if not, how about the explicitly set option? @@ -1154,7 +1308,7 @@ var Shuffle = function () { var size = void 0; if (typeof this.options.gutterWidth === 'function') { size = this.options.gutterWidth(containerWidth); - } else if (this.useSizer) { + } else if (this.options.sizer) { size = getNumberStyle(this.options.sizer, 'marginLeft'); } else { size = this.options.gutterWidth; @@ -1224,24 +1378,22 @@ var Shuffle = function () { } /** - * @return {boolean} Whether the event was prevented or not. + * Emit an event from this instance. + * @param {string} name Event name. + * @param {Object} [data={}] Optional object data. */ }, { key: '_dispatch', value: function _dispatch(name) { - var details = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + var data = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; if (this.isDestroyed) { - return false; + return; } - details.shuffle = this; - return !this.element.dispatchEvent(new CustomEvent(name, { - bubbles: true, - cancelable: false, - detail: details - })); + data.shuffle = this; + this.emit(name, data); } /** @@ -1262,44 +1414,41 @@ var Shuffle = function () { /** * Loops through each item that should be shown and calculates the x, y position. - * @param {Array.} items Array of items that will be shown/layed + * @param {ShuffleItem[]} items Array of items that will be shown/layed * out in order in their array. */ }, { key: '_layout', value: function _layout(items) { - var _this3 = this; + var _this4 = this; - var count = 0; - items.forEach(function (item) { - var currPos = item.point; - var currScale = item.scale; - var itemSize = Shuffle.getSize(item.element, true); - var pos = _this3._getItemPosition(itemSize); + var itemPositions = this._getNextPositions(items); + var count = 0; + items.forEach(function (item, i) { function callback() { - item.element.style.transitionDelay = ''; item.applyCss(ShuffleItem.Css.VISIBLE.after); } // If the item will not change its position, do not add it to the render // queue. Transitions don't fire when setting a property to the same value. - if (Point.equals(currPos, pos) && currScale === ShuffleItem.Scale.VISIBLE) { + if (Point.equals(item.point, itemPositions[i]) && !item.isHidden) { item.applyCss(ShuffleItem.Css.VISIBLE.before); callback(); return; } - item.point = pos; + item.point = itemPositions[i]; item.scale = ShuffleItem.Scale.VISIBLE; + item.isHidden = false; - // Use xtend here to clone the object so that the `before` object isn't - // modified when the transition delay is added. - var styles = immutable(ShuffleItem.Css.VISIBLE.before); - styles.transitionDelay = _this3._getStaggerAmount(count) + 'ms'; + // Clone the object so that the `before` object isn't modified when the + // transition delay is added. + var styles = _this4.getStylesForTransition(item, ShuffleItem.Css.VISIBLE.before); + styles.transitionDelay = _this4._getStaggerAmount(count) + 'ms'; - _this3._queue.push({ + _this4._queue.push({ item: item, styles: styles, callback: callback @@ -1309,6 +1458,38 @@ var Shuffle = function () { }); } + /** + * Return an array of Point instances representing the future positions of + * each item. + * @param {ShuffleItem[]} items Array of sorted shuffle items. + * @return {Point[]} + * @private + */ + + }, { + key: '_getNextPositions', + value: function _getNextPositions(items) { + var _this5 = this; + + // If position data is going to be changed, add the item's size to the + // transformer to allow for calculations. + if (this.options.isCentered) { + var itemsData = items.map(function (item, i) { + var itemSize = Shuffle.getSize(item.element, true); + var point = _this5._getItemPosition(itemSize); + return new Rect(point.x, point.y, itemSize.width, itemSize.height, i); + }); + + return this.getTransformedPositions(itemsData, this.containerWidth); + } + + // If no transforms are going to happen, simply return an array of the + // future points of each item. + return items.map(function (item) { + return _this5._getItemPosition(Shuffle.getSize(item.element, true)); + }); + } + /** * Determine the location of the next item, based on its size. * @param {{width: number, height: number}} itemSize Object with width and height. @@ -1329,16 +1510,30 @@ var Shuffle = function () { }); } + /** + * Mutate positions before they're applied. + * @param {Rect[]} itemRects Item data objects. + * @param {number} containerWidth Width of the containing element. + * @return {Point[]} + * @protected + */ + + }, { + key: 'getTransformedPositions', + value: function getTransformedPositions(itemRects, containerWidth) { + return getCenteredPositions(itemRects, containerWidth); + } + /** * Hides the elements that don't match our filter. - * @param {Array.} collection Collection to shrink. + * @param {ShuffleItem[]} collection Collection to shrink. * @private */ }, { key: '_shrink', value: function _shrink() { - var _this4 = this; + var _this6 = this; var collection = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this._getConcealedItems(); @@ -1354,18 +1549,19 @@ var Shuffle = function () { // The callback is executed here because it is not guaranteed to be called // after the transitionend event because the transitionend could be // canceled if another animation starts. - if (item.scale === ShuffleItem.Scale.HIDDEN) { + if (item.isHidden) { item.applyCss(ShuffleItem.Css.HIDDEN.before); callback(); return; } item.scale = ShuffleItem.Scale.HIDDEN; + item.isHidden = true; - var styles = immutable(ShuffleItem.Css.HIDDEN.before); - styles.transitionDelay = _this4._getStaggerAmount(count) + 'ms'; + var styles = _this6.getStylesForTransition(item, ShuffleItem.Css.HIDDEN.before); + styles.transitionDelay = _this6._getStaggerAmount(count) + 'ms'; - _this4._queue.push({ + _this6._queue.push({ item: item, styles: styles, callback: callback @@ -1388,42 +1584,29 @@ var Shuffle = function () { return; } - // Will need to check height in the future if it's layed out horizontaly - var containerWidth = Shuffle.getSize(this.element).width; - - // containerWidth hasn't changed, don't do anything - if (containerWidth === this.containerWidth) { - return; - } - this.update(); } /** * Returns styles which will be applied to the an item for a transition. - * @param {Object} obj Transition options. + * @param {ShuffleItem} item Item to get styles for. Should have updated + * scale and point properties. + * @param {Object} styleObject Extra styles that will be used in the transition. * @return {!Object} Transforms for transitions, left/top for animate. - * @private + * @protected */ }, { - key: '_getStylesForTransition', - value: function _getStylesForTransition(_ref2) { - var item = _ref2.item, - styles = _ref2.styles; - - if (!styles.transitionDelay) { - styles.transitionDelay = '0ms'; - } - - var x = item.point.x; - var y = item.point.y; + key: 'getStylesForTransition', + value: function getStylesForTransition(item, styleObject) { + // Clone the object to avoid mutating the original. + var styles = Object.assign({}, styleObject); if (this.options.useTransforms) { - styles.transform = 'translate(' + x + 'px, ' + y + 'px) scale(' + item.scale + ')'; + styles.transform = 'translate(' + item.point.x + 'px, ' + item.point.y + 'px) scale(' + item.scale + ')'; } else { - styles.left = x + 'px'; - styles.top = y + 'px'; + styles.left = item.point.x + 'px'; + styles.top = item.point.y + 'px'; } return styles; @@ -1433,8 +1616,8 @@ var Shuffle = function () { * Listen for the transition end on an element and execute the itemCallback * when it finishes. * @param {Element} element Element to listen on. - * @param {Function} itemCallback Callback for the item. - * @param {Function} done Callback to notify `parallel` that this one is done. + * @param {function} itemCallback Callback for the item. + * @param {function} done Callback to notify `parallel` that this one is done. */ }, { @@ -1452,17 +1635,17 @@ var Shuffle = function () { * Return a function which will set CSS styles and call the `done` function * when (if) the transition finishes. * @param {Object} opts Transition object. - * @return {Function} A function to be called with a `done` function. + * @return {function} A function to be called with a `done` function. */ }, { key: '_getTransitionFunction', value: function _getTransitionFunction(opts) { - var _this5 = this; + var _this7 = this; return function (done) { - opts.item.applyCss(_this5._getStylesForTransition(opts)); - _this5._whenTransitionDone(opts.item.element, opts.callback, done); + opts.item.applyCss(opts.styles); + _this7._whenTransitionDone(opts.item.element, opts.callback, done); }; } @@ -1486,13 +1669,13 @@ var Shuffle = function () { this._startTransitions(this._queue); } else if (hasQueue) { this._styleImmediately(this._queue); - this._dispatchLayout(); + this._dispatch(Shuffle.EventType.LAYOUT); // A call to layout happened, but none of the newly visible items will // change position or the transition duration is zero, which will not trigger // the transitionend event. } else { - this._dispatchLayout(); + this._dispatch(Shuffle.EventType.LAYOUT); } // Remove everything in the style queue @@ -1501,20 +1684,20 @@ var Shuffle = function () { /** * Wait for each transition to finish, the emit the layout event. - * @param {Array.} transitions Array of transition objects. + * @param {Object[]} transitions Array of transition objects. */ }, { key: '_startTransitions', value: function _startTransitions(transitions) { - var _this6 = this; + var _this8 = this; // Set flag that shuffle is currently in motion. this.isTransitioning = true; // Create an array of functions to be called. var callbacks = transitions.map(function (obj) { - return _this6._getTransitionFunction(obj); + return _this8._getTransitionFunction(obj); }); index$3(callbacks, this._movementFinished.bind(this)); @@ -1534,15 +1717,13 @@ var Shuffle = function () { /** * Apply styles without a transition. - * @param {Array.} objects Array of transition objects. + * @param {Object[]} objects Array of transition objects. * @private */ }, { key: '_styleImmediately', value: function _styleImmediately(objects) { - var _this7 = this; - if (objects.length) { var elements = objects.map(function (obj) { return obj.item.element; @@ -1550,7 +1731,7 @@ var Shuffle = function () { Shuffle._skipTransitions(elements, function () { objects.forEach(function (obj) { - obj.item.applyCss(_this7._getStylesForTransition(obj)); + obj.item.applyCss(obj.styles); obj.callback(); }); }); @@ -1561,17 +1742,12 @@ var Shuffle = function () { value: function _movementFinished() { this._transitions.length = 0; this.isTransitioning = false; - this._dispatchLayout(); - } - }, { - key: '_dispatchLayout', - value: function _dispatchLayout() { this._dispatch(Shuffle.EventType.LAYOUT); } /** * The magic. This is what makes the plugin 'shuffle' - * @param {string|Function|Array.} [category] Category to filter by. + * @param {string|string[]|function(Element):boolean} [category] Category to filter by. * Can be a function, string, or array of strings. * @param {Object} [sortObj] A sort object which can sort the visible set */ @@ -1601,13 +1777,13 @@ var Shuffle = function () { /** * Gets the visible elements, sorts them, and passes them to layout. - * @param {Object} opts the options object for the sorted plugin + * @param {Object} [sortOptions] The options object to pass to `sorter`. */ }, { key: 'sort', value: function sort() { - var opts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.lastSort; + var sortOptions = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.lastSort; if (!this.isEnabled) { return; @@ -1615,8 +1791,7 @@ var Shuffle = function () { this._resetCols(); - var items = this._getFilteredItems(); - items = sorter(items, opts); + var items = sorter(this._getFilteredItems(), sortOptions); this._layout(items); @@ -1627,18 +1802,19 @@ var Shuffle = function () { // Adjust the height of the container. this._setContainerSize(); - this.lastSort = opts; + this.lastSort = sortOptions; } /** * Reposition everything. - * @param {boolean} isOnlyLayout If true, column and gutter widths won't be - * recalculated. + * @param {boolean} [isOnlyLayout=false] If true, column and gutter widths won't be recalculated. */ }, { key: 'update', - value: function update(isOnlyLayout) { + value: function update() { + var isOnlyLayout = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; + if (this.isEnabled) { if (!isOnlyLayout) { // Get updated colCount @@ -1665,25 +1841,51 @@ var Shuffle = function () { /** * New items have been appended to shuffle. Mix them in with the current * filter or sort status. - * @param {Array.} newItems Collection of new items. + * @param {Element[]} newItems Collection of new items. */ }, { key: 'add', value: function add(newItems) { - var items = index$1(newItems).map(function (el) { + var _this9 = this; + + var items = arrayUnique(newItems).map(function (el) { return new ShuffleItem(el); }); // Add classes and set initial positions. this._initItems(items); + // Determine which items will go with the current filter. + this._resetCols(); + var newItemSet = this._filter(this.lastFilter, items); + var willBeVisible = this._mergeNewItems(newItemSet.visible); + var sortedVisibleItems = sorter(willBeVisible, this.lastSort); + + // Layout all items again so that new items get positions. + // Synchonously apply positions. + var itemPositions = this._getNextPositions(sortedVisibleItems); + sortedVisibleItems.forEach(function (item, i) { + if (newItemSet.visible.includes(item)) { + item.point = itemPositions[i]; + item.scale = ShuffleItem.Scale.HIDDEN; + item.isHidden = true; + item.applyCss(ShuffleItem.Css.HIDDEN.before); + item.applyCss(ShuffleItem.Css.HIDDEN.after); + item.applyCss(_this9.getStylesForTransition(item, {})); + } + }); + + // Cause layout so that the styles above are applied. + this.element.offsetWidth; // eslint-disable-line no-unused-expressions + // Add transition to each item. - this._setTransitions(items); + this.setItemTransitions(items); // Update the list of items. - this.items = this.items.concat(items); - this._updateItemsOrder(); + this.items = this._mergeNewItems(items); + + // Update layout/visibility of new and old items. this.filter(this.lastFilter); } @@ -1704,47 +1906,48 @@ var Shuffle = function () { }, { key: 'enable', - value: function enable(isUpdateLayout) { + value: function enable() { + var isUpdateLayout = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true; + this.isEnabled = true; - if (isUpdateLayout !== false) { + if (isUpdateLayout) { this.update(); } } /** - * Remove 1 or more shuffle items - * @param {Array.} elements An array containing one or more + * Remove 1 or more shuffle items. + * @param {Element[]} elements An array containing one or more * elements in shuffle - * @return {Shuffle} The shuffle object + * @return {Shuffle} The shuffle instance. */ }, { key: 'remove', value: function remove(elements) { - var _this8 = this; + var _this10 = this; if (!elements.length) { return; } - var collection = index$1(elements); + var collection = arrayUnique(elements); var oldItems = collection.map(function (element) { - return _this8.getItemByElement(element); + return _this10.getItemByElement(element); }).filter(function (item) { return !!item; }); var handleLayout = function handleLayout() { - _this8.element.removeEventListener(Shuffle.EventType.LAYOUT, handleLayout); - _this8._disposeItems(oldItems); + _this10._disposeItems(oldItems); // Remove the collection in the callback collection.forEach(function (element) { element.parentNode.removeChild(element); }); - _this8._dispatch(Shuffle.EventType.REMOVED, { collection: collection }); + _this10._dispatch(Shuffle.EventType.REMOVED, { collection: collection }); }; // Hide collection first. @@ -1760,29 +1963,55 @@ var Shuffle = function () { // Update the list of items here because `remove` could be called again // with an item that is in the process of being removed. this.items = this.items.filter(function (item) { - return !arrayIncludes(oldItems, item); + return !oldItems.includes(item); }); this._updateItemCount(); - this.element.addEventListener(Shuffle.EventType.LAYOUT, handleLayout); + this.once(Shuffle.EventType.LAYOUT, handleLayout); } /** * Retrieve a shuffle item by its element. * @param {Element} element Element to look for. - * @return {?ShuffleItem} A shuffle item or null if it's not found. + * @return {?ShuffleItem} A shuffle item or undefined if it's not found. */ }, { key: 'getItemByElement', value: function getItemByElement(element) { - for (var i = this.items.length - 1; i >= 0; i--) { - if (this.items[i].element === element) { - return this.items[i]; - } - } + return this.items.find(function (item) { + return item.element === element; + }); + } - return null; + /** + * Dump the elements currently stored and reinitialize all child elements which + * match the `itemSelector`. + */ + + }, { + key: 'resetItems', + value: function resetItems() { + var _this11 = this; + + // Remove refs to current items. + this._disposeItems(this.items); + this.isInitialized = false; + + // Find new items in the DOM. + this.items = this._getItems(); + + // Set initial styles on the new items. + this._initItems(this.items); + + this.once(Shuffle.EventType.LAYOUT, function () { + // Add transition to each item. + _this11.setItemTransitions(_this11.items); + _this11.isInitialized = true; + }); + + // Lay out all items. + this.filter(this.lastFilter); } /** @@ -1800,17 +2029,19 @@ var Shuffle = function () { this.element.removeAttribute('style'); // Reset individual item styles - this._disposeItems(); + this._disposeItems(this.items); + + this.items.length = 0; + this._transitions.length = 0; // Null DOM references - this.items = null; this.options.sizer = null; this.element = null; - this._transitions = null; // Set a flag so if a debounced resize has been triggered, // it can first check if it is actually isDestroyed and not doing anything this.isDestroyed = true; + this.isEnabled = false; } /** @@ -1832,13 +2063,15 @@ var Shuffle = function () { * follow the W3C spec here. * * @param {Element} element The element. - * @param {boolean} [includeMargins] Whether to include margins. Default is false. + * @param {boolean} [includeMargins=false] Whether to include margins. * @return {{width: number, height: number}} The width and height. */ }], [{ key: 'getSize', - value: function getSize(element, includeMargins) { + value: function getSize(element) { + var includeMargins = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; + // Store the styles so that they can be used by others without asking for it again. var styles = window.getComputedStyle(element, null); var width = getNumberStyle(element, 'width', styles); @@ -1861,8 +2094,8 @@ var Shuffle = function () { /** * Change a property or execute a function which will not have a transition - * @param {Array.} elements DOM elements that won't be transitioned. - * @param {Function} callback A function which will be called while transition + * @param {Element[]} elements DOM elements that won't be transitioned. + * @param {function} callback A function which will be called while transition * is set to 0ms. * @private */ @@ -1890,7 +2123,7 @@ var Shuffle = function () { callback(); - // Cause reflow. + // Cause forced synchronous layout. elements[0].offsetWidth; // eslint-disable-line no-unused-expressions // Put the duration back @@ -1901,16 +2134,14 @@ var Shuffle = function () { } }]); return Shuffle; -}(); +}(index); Shuffle.ShuffleItem = ShuffleItem; Shuffle.ALL_ITEMS = 'all'; Shuffle.FILTER_ATTRIBUTE_KEY = 'groups'; -/** - * @enum {string} - */ +/** @enum {string} */ Shuffle.EventType = { LAYOUT: 'shuffle:layout', REMOVED: 'shuffle:removed' @@ -1919,9 +2150,7 @@ Shuffle.EventType = { /** @enum {string} */ Shuffle.Classes = Classes; -/** - * @enum {string} - */ +/** @enum {string} */ Shuffle.FilterMode = { ANY: 'any', ALL: 'all' @@ -1936,7 +2165,7 @@ Shuffle.options = { speed: 250, // CSS easing function to use. - easing: 'ease', + easing: 'cubic-bezier(0.4, 0.0, 0.2, 1)', // e.g. '.picture-item'. itemSelector: '*', @@ -1980,7 +2209,7 @@ Shuffle.options = { staggerAmount: 15, // Maximum stagger delay in milliseconds. - staggerAmountMax: 250, + staggerAmountMax: 150, // Whether to use transforms or absolute positioning. useTransforms: true, @@ -1988,15 +2217,21 @@ Shuffle.options = { // Affects using an array with filter. e.g. `filter(['one', 'two'])`. With "any", // the element passes the test if any of its groups are in the array. With "all", // the element only passes if all groups are in the array. - filterMode: Shuffle.FilterMode.ANY + filterMode: Shuffle.FilterMode.ANY, + + // Attempt to center grid items in each row. + isCentered: false }; +Shuffle.Point = Point; +Shuffle.Rect = Rect; + // Expose for testing. Hack at your own risk. -Shuffle.__Point = Point; Shuffle.__sorter = sorter; Shuffle.__getColumnSpan = getColumnSpan; Shuffle.__getAvailablePositions = getAvailablePositions; Shuffle.__getShortColumn = getShortColumn; +Shuffle.__getCenteredPositions = getCenteredPositions; return Shuffle; diff --git a/dist/shuffle.js.map b/dist/shuffle.js.map index ec20f0c..63a4e04 100644 --- a/dist/shuffle.js.map +++ b/dist/shuffle.js.map @@ -1 +1 @@ -{"version":3,"file":"shuffle.js","sources":["../node_modules/custom-event-polyfill/custom-event-polyfill.js","../node_modules/matches-selector/index.js","../node_modules/array-uniq/index.js","../node_modules/xtend/immutable.js","../node_modules/throttleit/index.js","../node_modules/array-parallel/index.js","../src/get-number.js","../src/point.js","../src/classes.js","../src/shuffle-item.js","../src/computed-size.js","../src/get-number-style.js","../src/sorter.js","../src/on-transition-end.js","../src/array-max.js","../src/array-min.js","../src/layout.js","../src/shuffle.js"],"sourcesContent":["// Polyfill for creating CustomEvents on IE9/10/11\n\n// code pulled from:\n// https://github.com/d4tocchini/customevent-polyfill\n// https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent#Polyfill\n\ntry {\n var ce = new window.CustomEvent('test');\n ce.preventDefault();\n if (ce.defaultPrevented !== true) {\n // IE has problems with .preventDefault() on custom events\n // http://stackoverflow.com/questions/23349191\n throw new Error('Could not prevent default');\n }\n} catch(e) {\n var CustomEvent = function(event, params) {\n var evt, origPrevent;\n params = params || {\n bubbles: false,\n cancelable: false,\n detail: undefined\n };\n\n evt = document.createEvent(\"CustomEvent\");\n evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail);\n origPrevent = evt.preventDefault;\n evt.preventDefault = function () {\n origPrevent.call(this);\n try {\n Object.defineProperty(this, 'defaultPrevented', {\n get: function () {\n return true;\n }\n });\n } catch(e) {\n this.defaultPrevented = true;\n }\n };\n return evt;\n };\n\n CustomEvent.prototype = window.Event.prototype;\n window.CustomEvent = CustomEvent; // expose definition to window\n}\n","'use strict';\n\nvar proto = Element.prototype;\nvar vendor = proto.matches\n || proto.matchesSelector\n || proto.webkitMatchesSelector\n || proto.mozMatchesSelector\n || proto.msMatchesSelector\n || proto.oMatchesSelector;\n\nmodule.exports = match;\n\n/**\n * Match `el` to `selector`.\n *\n * @param {Element} el\n * @param {String} selector\n * @return {Boolean}\n * @api public\n */\n\nfunction match(el, selector) {\n if (vendor) return vendor.call(el, selector);\n var nodes = el.parentNode.querySelectorAll(selector);\n for (var i = 0; i < nodes.length; i++) {\n if (nodes[i] == el) return true;\n }\n return false;\n}","'use strict';\n\n// there's 3 implementations written in increasing order of efficiency\n\n// 1 - no Set type is defined\nfunction uniqNoSet(arr) {\n\tvar ret = [];\n\n\tfor (var i = 0; i < arr.length; i++) {\n\t\tif (ret.indexOf(arr[i]) === -1) {\n\t\t\tret.push(arr[i]);\n\t\t}\n\t}\n\n\treturn ret;\n}\n\n// 2 - a simple Set type is defined\nfunction uniqSet(arr) {\n\tvar seen = new Set();\n\treturn arr.filter(function (el) {\n\t\tif (!seen.has(el)) {\n\t\t\tseen.add(el);\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t});\n}\n\n// 3 - a standard Set type is defined and it has a forEach method\nfunction uniqSetWithForEach(arr) {\n\tvar ret = [];\n\n\t(new Set(arr)).forEach(function (el) {\n\t\tret.push(el);\n\t});\n\n\treturn ret;\n}\n\n// V8 currently has a broken implementation\n// https://github.com/joyent/node/issues/8449\nfunction doesForEachActuallyWork() {\n\tvar ret = false;\n\n\t(new Set([true])).forEach(function (el) {\n\t\tret = el;\n\t});\n\n\treturn ret === true;\n}\n\nif ('Set' in global) {\n\tif (typeof Set.prototype.forEach === 'function' && doesForEachActuallyWork()) {\n\t\tmodule.exports = uniqSetWithForEach;\n\t} else {\n\t\tmodule.exports = uniqSet;\n\t}\n} else {\n\tmodule.exports = uniqNoSet;\n}\n","module.exports = extend\n\nvar hasOwnProperty = Object.prototype.hasOwnProperty;\n\nfunction extend() {\n var target = {}\n\n for (var i = 0; i < arguments.length; i++) {\n var source = arguments[i]\n\n for (var key in source) {\n if (hasOwnProperty.call(source, key)) {\n target[key] = source[key]\n }\n }\n }\n\n return target\n}\n","module.exports = throttle;\n\n/**\n * Returns a new function that, when invoked, invokes `func` at most once per `wait` milliseconds.\n *\n * @param {Function} func Function to wrap.\n * @param {Number} wait Number of milliseconds that must elapse between `func` invocations.\n * @return {Function} A new function that wraps the `func` function passed in.\n */\n\nfunction throttle (func, wait) {\n var ctx, args, rtn, timeoutID; // caching\n var last = 0;\n\n return function throttled () {\n ctx = this;\n args = arguments;\n var delta = new Date() - last;\n if (!timeoutID)\n if (delta >= wait) call();\n else timeoutID = setTimeout(call, wait - delta);\n return rtn;\n };\n\n function call () {\n timeoutID = 0;\n last = +new Date();\n rtn = func.apply(ctx, args);\n ctx = null;\n args = null;\n }\n}\n","module.exports = function parallel(fns, context, callback) {\n if (!callback) {\n if (typeof context === 'function') {\n callback = context\n context = null\n } else {\n callback = noop\n }\n }\n\n var pending = fns && fns.length\n if (!pending) return callback(null, []);\n\n var finished = false\n var results = new Array(pending)\n\n fns.forEach(context ? function (fn, i) {\n fn.call(context, maybeDone(i))\n } : function (fn, i) {\n fn(maybeDone(i))\n })\n\n function maybeDone(i) {\n return function (err, result) {\n if (finished) return;\n\n if (err) {\n callback(err, results)\n finished = true\n return\n }\n\n results[i] = result\n\n if (!--pending) callback(null, results);\n }\n }\n}\n\nfunction noop() {}\n","/**\n * Always returns a numeric value, given a value. Logic from jQuery's `isNumeric`.\n * @param {*} value Possibly numeric value.\n * @return {number} `value` or zero if `value` isn't numeric.\n */\nexport default function getNumber(value) {\n return parseFloat(value) || 0;\n}\n","import getNumber from './get-number';\n\nclass Point {\n\n /**\n * Represents a coordinate pair.\n * @param {number} [x=0] X.\n * @param {number} [y=0] Y.\n */\n constructor(x, y) {\n this.x = getNumber(x);\n this.y = getNumber(y);\n }\n\n /**\n * Whether two points are equal.\n * @param {Point} a Point A.\n * @param {Point} b Point B.\n * @return {boolean}\n */\n static equals(a, b) {\n return a.x === b.x && a.y === b.y;\n }\n}\n\nexport default Point;\n","export default {\n BASE: 'shuffle',\n SHUFFLE_ITEM: 'shuffle-item',\n VISIBLE: 'shuffle-item--visible',\n HIDDEN: 'shuffle-item--hidden',\n};\n","import Point from './point';\nimport Classes from './classes';\n\nlet id = 0;\n\nclass ShuffleItem {\n constructor(element) {\n id += 1;\n this.id = id;\n this.element = element;\n this.isVisible = true;\n }\n\n show() {\n this.isVisible = true;\n this.element.classList.remove(Classes.HIDDEN);\n this.element.classList.add(Classes.VISIBLE);\n }\n\n hide() {\n this.isVisible = false;\n this.element.classList.remove(Classes.VISIBLE);\n this.element.classList.add(Classes.HIDDEN);\n }\n\n init() {\n this.addClasses([Classes.SHUFFLE_ITEM, Classes.VISIBLE]);\n this.applyCss(ShuffleItem.Css.INITIAL);\n this.scale = ShuffleItem.Scale.VISIBLE;\n this.point = new Point();\n }\n\n addClasses(classes) {\n classes.forEach((className) => {\n this.element.classList.add(className);\n });\n }\n\n removeClasses(classes) {\n classes.forEach((className) => {\n this.element.classList.remove(className);\n });\n }\n\n applyCss(obj) {\n Object.keys(obj).forEach((key) => {\n this.element.style[key] = obj[key];\n });\n }\n\n dispose() {\n this.removeClasses([\n Classes.HIDDEN,\n Classes.VISIBLE,\n Classes.SHUFFLE_ITEM,\n ]);\n\n this.element.removeAttribute('style');\n this.element = null;\n }\n}\n\nShuffleItem.Css = {\n INITIAL: {\n position: 'absolute',\n top: 0,\n left: 0,\n visibility: 'visible',\n 'will-change': 'transform',\n },\n VISIBLE: {\n before: {\n opacity: 1,\n visibility: 'visible',\n },\n after: {},\n },\n HIDDEN: {\n before: {\n opacity: 0,\n },\n after: {\n visibility: 'hidden',\n },\n },\n};\n\nShuffleItem.Scale = {\n VISIBLE: 1,\n HIDDEN: 0.001,\n};\n\nexport default ShuffleItem;\n","const element = document.body || document.documentElement;\nconst e = document.createElement('div');\ne.style.cssText = 'width:10px;padding:2px;box-sizing:border-box;';\nelement.appendChild(e);\n\nconst width = window.getComputedStyle(e, null).width;\nconst ret = width === '10px';\n\nelement.removeChild(e);\n\nexport default ret;\n","import getNumber from './get-number';\nimport COMPUTED_SIZE_INCLUDES_PADDING from './computed-size';\n\n/**\n * Retrieve the computed style for an element, parsed as a float.\n * @param {Element} element Element to get style for.\n * @param {string} style Style property.\n * @param {CSSStyleDeclaration} [styles] Optionally include clean styles to\n * use instead of asking for them again.\n * @return {number} The parsed computed value or zero if that fails because IE\n * will return 'auto' when the element doesn't have margins instead of\n * the computed style.\n */\nexport default function getNumberStyle(element, style,\n styles = window.getComputedStyle(element, null)) {\n let value = getNumber(styles[style]);\n\n // Support IE<=11 and W3C spec.\n if (!COMPUTED_SIZE_INCLUDES_PADDING && style === 'width') {\n value += getNumber(styles.paddingLeft) +\n getNumber(styles.paddingRight) +\n getNumber(styles.borderLeftWidth) +\n getNumber(styles.borderRightWidth);\n } else if (!COMPUTED_SIZE_INCLUDES_PADDING && style === 'height') {\n value += getNumber(styles.paddingTop) +\n getNumber(styles.paddingBottom) +\n getNumber(styles.borderTopWidth) +\n getNumber(styles.borderBottomWidth);\n }\n\n return value;\n}\n","import xtend from 'xtend';\n\n/**\n * Fisher-Yates shuffle.\n * http://stackoverflow.com/a/962890/373422\n * https://bost.ocks.org/mike/shuffle/\n * @param {Array} array Array to shuffle.\n * @return {Array} Randomly sorted array.\n */\nfunction randomize(array) {\n let n = array.length;\n\n while (n) {\n n -= 1;\n const i = Math.floor(Math.random() * (n + 1));\n const temp = array[i];\n array[i] = array[n];\n array[n] = temp;\n }\n\n return array;\n}\n\nconst defaults = {\n // Use array.reverse() to reverse the results\n reverse: false,\n\n // Sorting function\n by: null,\n\n // If true, this will skip the sorting and return a randomized order in the array\n randomize: false,\n\n // Determines which property of each item in the array is passed to the\n // sorting method.\n key: 'element',\n};\n\n// You can return `undefined` from the `by` function to revert to DOM order.\nexport default function sorter(arr, options) {\n const opts = xtend(defaults, options);\n const original = [].slice.call(arr);\n let revert = false;\n\n if (!arr.length) {\n return [];\n }\n\n if (opts.randomize) {\n return randomize(arr);\n }\n\n // Sort the elements by the opts.by function.\n // If we don't have opts.by, default to DOM order\n if (typeof opts.by === 'function') {\n arr.sort((a, b) => {\n // Exit early if we already know we want to revert\n if (revert) {\n return 0;\n }\n\n const valA = opts.by(a[opts.key]);\n const valB = opts.by(b[opts.key]);\n\n // If both values are undefined, use the DOM order\n if (valA === undefined && valB === undefined) {\n revert = true;\n return 0;\n }\n\n if (valA < valB || valA === 'sortFirst' || valB === 'sortLast') {\n return -1;\n }\n\n if (valA > valB || valA === 'sortLast' || valB === 'sortFirst') {\n return 1;\n }\n\n return 0;\n });\n }\n\n // Revert to the original array if necessary\n if (revert) {\n return original;\n }\n\n if (opts.reverse) {\n arr.reverse();\n }\n\n return arr;\n}\n","const transitions = {};\nconst eventName = 'transitionend';\nlet count = 0;\n\nfunction uniqueId() {\n count += 1;\n return eventName + count;\n}\n\nexport function cancelTransitionEnd(id) {\n if (transitions[id]) {\n transitions[id].element.removeEventListener(eventName, transitions[id].listener);\n transitions[id] = null;\n return true;\n }\n\n return false;\n}\n\nexport function onTransitionEnd(element, callback) {\n const id = uniqueId();\n const listener = (evt) => {\n if (evt.currentTarget === evt.target) {\n cancelTransitionEnd(id);\n callback(evt);\n }\n };\n\n element.addEventListener(eventName, listener);\n\n transitions[id] = { element, listener };\n\n return id;\n}\n","export default function arrayMax(array) {\n return Math.max.apply(Math, array); // eslint-disable-line prefer-spread\n}\n","export default function arrayMin(array) {\n return Math.min.apply(Math, array); // eslint-disable-line prefer-spread\n}\n","import Point from './point';\nimport arrayMax from './array-max';\nimport arrayMin from './array-min';\n\n/**\n * Determine the number of columns an items spans.\n * @param {number} itemWidth Width of the item.\n * @param {number} columnWidth Width of the column (includes gutter).\n * @param {number} columns Total number of columns\n * @param {number} threshold A buffer value for the size of the column to fit.\n * @return {number}\n */\nexport function getColumnSpan(itemWidth, columnWidth, columns, threshold) {\n let columnSpan = itemWidth / columnWidth;\n\n // If the difference between the rounded column span number and the\n // calculated column span number is really small, round the number to\n // make it fit.\n if (Math.abs(Math.round(columnSpan) - columnSpan) < threshold) {\n // e.g. columnSpan = 4.0089945390298745\n columnSpan = Math.round(columnSpan);\n }\n\n // Ensure the column span is not more than the amount of columns in the whole layout.\n return Math.min(Math.ceil(columnSpan), columns);\n}\n\n/**\n * Retrieves the column set to use for placement.\n * @param {number} columnSpan The number of columns this current item spans.\n * @param {number} columns The total columns in the grid.\n * @return {Array.} An array of numbers represeting the column set.\n */\nexport function getAvailablePositions(positions, columnSpan, columns) {\n // The item spans only one column.\n if (columnSpan === 1) {\n return positions;\n }\n\n // The item spans more than one column, figure out how many different\n // places it could fit horizontally.\n // The group count is the number of places within the positions this block\n // could fit, ignoring the current positions of items.\n // Imagine a 2 column brick as the second item in a 4 column grid with\n // 10px height each. Find the places it would fit:\n // [20, 10, 10, 0]\n // | | |\n // * * *\n //\n // Then take the places which fit and get the bigger of the two:\n // max([20, 10]), max([10, 10]), max([10, 0]) = [20, 10, 0]\n //\n // Next, find the first smallest number (the short column).\n // [20, 10, 0]\n // |\n // *\n //\n // And that's where it should be placed!\n //\n // Another example where the second column's item extends past the first:\n // [10, 20, 10, 0] => [20, 20, 10] => 10\n const available = [];\n\n // For how many possible positions for this item there are.\n for (let i = 0; i <= columns - columnSpan; i++) {\n // Find the bigger value for each place it could fit.\n available.push(arrayMax(positions.slice(i, i + columnSpan)));\n }\n\n return available;\n}\n\n/**\n * Find index of short column, the first from the left where this item will go.\n *\n * @param {Array.} positions The array to search for the smallest number.\n * @param {number} buffer Optional buffer which is very useful when the height\n * is a percentage of the width.\n * @return {number} Index of the short column.\n */\nexport function getShortColumn(positions, buffer) {\n const minPosition = arrayMin(positions);\n for (let i = 0, len = positions.length; i < len; i++) {\n if (positions[i] >= minPosition - buffer && positions[i] <= minPosition + buffer) {\n return i;\n }\n }\n\n return 0;\n}\n\n/**\n * Determine the location of the next item, based on its size.\n * @param {Object} itemSize Object with width and height.\n * @param {Array.} positions Positions of the other current items.\n * @param {number} gridSize The column width or row height.\n * @param {number} total The total number of columns or rows.\n * @param {number} threshold Buffer value for the column to fit.\n * @param {number} buffer Vertical buffer for the height of items.\n * @return {Point}\n */\nexport function getItemPosition({ itemSize, positions, gridSize, total, threshold, buffer }) {\n const span = getColumnSpan(itemSize.width, gridSize, total, threshold);\n const setY = getAvailablePositions(positions, span, total);\n const shortColumnIndex = getShortColumn(setY, buffer);\n\n // Position the item\n const point = new Point(\n Math.round(gridSize * shortColumnIndex),\n Math.round(setY[shortColumnIndex]));\n\n // Update the columns array with the new values for each column.\n // e.g. before the update the columns could be [250, 0, 0, 0] for an item\n // which spans 2 columns. After it would be [250, itemHeight, itemHeight, 0].\n const setHeight = setY[shortColumnIndex] + itemSize.height;\n for (let i = 0; i < span; i++) {\n positions[shortColumnIndex + i] = setHeight;\n }\n\n return point;\n}\n","import 'custom-event-polyfill';\nimport matches from 'matches-selector';\nimport arrayUnique from 'array-uniq';\nimport xtend from 'xtend';\nimport throttle from 'throttleit';\nimport parallel from 'array-parallel';\nimport Point from './point';\nimport ShuffleItem from './shuffle-item';\nimport Classes from './classes';\nimport getNumberStyle from './get-number-style';\nimport sorter from './sorter';\nimport { onTransitionEnd, cancelTransitionEnd } from './on-transition-end';\nimport { getItemPosition, getColumnSpan, getAvailablePositions, getShortColumn } from './layout';\nimport arrayMax from './array-max';\n\nfunction toArray(arrayLike) {\n return Array.prototype.slice.call(arrayLike);\n}\n\nfunction arrayIncludes(array, obj) {\n return array.indexOf(obj) > -1;\n}\n\n// Used for unique instance variables\nlet id = 0;\n\nclass Shuffle {\n\n /**\n * Categorize, sort, and filter a responsive grid of items.\n *\n * @param {Element} element An element which is the parent container for the grid items.\n * @param {Object} [options=Shuffle.options] Options object.\n * @constructor\n */\n constructor(element, options = {}) {\n this.options = xtend(Shuffle.options, options);\n\n this.useSizer = false;\n this.lastSort = {};\n this.group = Shuffle.ALL_ITEMS;\n this.lastFilter = Shuffle.ALL_ITEMS;\n this.isEnabled = true;\n this.isDestroyed = false;\n this.isInitialized = false;\n this._transitions = [];\n this.isTransitioning = false;\n this._queue = [];\n\n const el = this._getElementOption(element);\n\n if (!el) {\n throw new TypeError('Shuffle needs to be initialized with an element.');\n }\n\n this.element = el;\n this.id = 'shuffle_' + id;\n id += 1;\n\n this._init();\n this.isInitialized = true;\n }\n\n _init() {\n this.items = this._getItems();\n\n this.options.sizer = this._getElementOption(this.options.sizer);\n\n if (this.options.sizer) {\n this.useSizer = true;\n }\n\n // Add class and invalidate styles\n this.element.classList.add(Shuffle.Classes.BASE);\n\n // Set initial css for each item\n this._initItems();\n\n // Bind resize events\n this._onResize = this._getResizeFunction();\n window.addEventListener('resize', this._onResize);\n\n // Get container css all in one request. Causes reflow\n const containerCss = window.getComputedStyle(this.element, null);\n const containerWidth = Shuffle.getSize(this.element).width;\n\n // Add styles to the container if it doesn't have them.\n this._validateStyles(containerCss);\n\n // We already got the container's width above, no need to cause another\n // reflow getting it again... Calculate the number of columns there will be\n this._setColumns(containerWidth);\n\n // Kick off!\n this.filter(this.options.group, this.options.initialSort);\n\n // The shuffle items haven't had transitions set on them yet so the user\n // doesn't see the first layout. Set them now that the first layout is done.\n // First, however, a synchronous layout must be caused for the previous\n // styles to be applied without transitions.\n this.element.offsetWidth; // eslint-disable-line no-unused-expressions\n this._setTransitions();\n this.element.style.transition = 'height ' + this.options.speed + 'ms ' + this.options.easing;\n }\n\n /**\n * Returns a throttled and proxied function for the resize handler.\n * @return {Function}\n * @private\n */\n _getResizeFunction() {\n const resizeFunction = this._handleResize.bind(this);\n return this.options.throttle ?\n this.options.throttle(resizeFunction, this.options.throttleTime) :\n resizeFunction;\n }\n\n /**\n * Retrieve an element from an option.\n * @param {string|jQuery|Element} option The option to check.\n * @return {?Element} The plain element or null.\n * @private\n */\n _getElementOption(option) {\n // If column width is a string, treat is as a selector and search for the\n // sizer element within the outermost container\n if (typeof option === 'string') {\n return this.element.querySelector(option);\n\n // Check for an element\n } else if (option && option.nodeType && option.nodeType === 1) {\n return option;\n\n // Check for jQuery object\n } else if (option && option.jquery) {\n return option[0];\n }\n\n return null;\n }\n\n /**\n * Ensures the shuffle container has the css styles it needs applied to it.\n * @param {Object} styles Key value pairs for position and overflow.\n * @private\n */\n _validateStyles(styles) {\n // Position cannot be static.\n if (styles.position === 'static') {\n this.element.style.position = 'relative';\n }\n\n // Overflow has to be hidden.\n if (styles.overflow !== 'hidden') {\n this.element.style.overflow = 'hidden';\n }\n }\n\n /**\n * Filter the elements by a category.\n * @param {string} [category] Category to filter by. If it's given, the last\n * category will be used to filter the items.\n * @param {Array} [collection] Optionally filter a collection. Defaults to\n * all the items.\n * @return {!{visible: Array, hidden: Array}}\n * @private\n */\n _filter(category = this.lastFilter, collection = this.items) {\n const set = this._getFilteredSets(category, collection);\n\n // Individually add/remove hidden/visible classes\n this._toggleFilterClasses(set);\n\n // Save the last filter in case elements are appended.\n this.lastFilter = category;\n\n // This is saved mainly because providing a filter function (like searching)\n // will overwrite the `lastFilter` property every time its called.\n if (typeof category === 'string') {\n this.group = category;\n }\n\n return set;\n }\n\n /**\n * Returns an object containing the visible and hidden elements.\n * @param {string|Function} category Category or function to filter by.\n * @param {Array.} items A collection of items to filter.\n * @return {!{visible: Array, hidden: Array}}\n * @private\n */\n _getFilteredSets(category, items) {\n let visible = [];\n const hidden = [];\n\n // category === 'all', add visible class to everything\n if (category === Shuffle.ALL_ITEMS) {\n visible = items;\n\n // Loop through each item and use provided function to determine\n // whether to hide it or not.\n } else {\n items.forEach((item) => {\n if (this._doesPassFilter(category, item.element)) {\n visible.push(item);\n } else {\n hidden.push(item);\n }\n });\n }\n\n return {\n visible,\n hidden,\n };\n }\n\n /**\n * Test an item to see if it passes a category.\n * @param {string|Function} category Category or function to filter by.\n * @param {Element} element An element to test.\n * @return {boolean} Whether it passes the category/filter.\n * @private\n */\n _doesPassFilter(category, element) {\n if (typeof category === 'function') {\n return category.call(element, element, this);\n }\n\n // Check each element's data-groups attribute against the given category.\n const attr = element.getAttribute('data-' + Shuffle.FILTER_ATTRIBUTE_KEY);\n const keys = this.options.delimeter ?\n attr.split(this.options.delimeter) :\n JSON.parse(attr);\n\n function testCategory(category) {\n return arrayIncludes(keys, category);\n }\n\n if (Array.isArray(category)) {\n if (this.options.filterMode === Shuffle.FilterMode.ANY) {\n return category.some(testCategory);\n }\n return category.every(testCategory);\n }\n\n return arrayIncludes(keys, category);\n }\n\n /**\n * Toggles the visible and hidden class names.\n * @param {{visible, hidden}} Object with visible and hidden arrays.\n * @private\n */\n _toggleFilterClasses({ visible, hidden }) {\n visible.forEach((item) => {\n item.show();\n });\n\n hidden.forEach((item) => {\n item.hide();\n });\n }\n\n /**\n * Set the initial css for each item\n * @param {Array.} [items] Optionally specifiy at set to initialize.\n * @private\n */\n _initItems(items = this.items) {\n items.forEach((item) => {\n item.init();\n });\n }\n\n /**\n * Remove element reference and styles.\n * @private\n */\n _disposeItems(items = this.items) {\n items.forEach((item) => {\n item.dispose();\n });\n }\n\n /**\n * Updates the visible item count.\n * @private\n */\n _updateItemCount() {\n this.visibleItems = this._getFilteredItems().length;\n }\n\n /**\n * Sets css transform transition on a group of elements. This is not executed\n * at the same time as `item.init` so that transitions don't occur upon\n * initialization of Shuffle.\n * @param {Array.} items Shuffle items to set transitions on.\n * @private\n */\n _setTransitions(items = this.items) {\n const speed = this.options.speed;\n const easing = this.options.easing;\n\n const str = this.options.useTransforms ?\n `transform ${speed}ms ${easing}, opacity ${speed}ms ${easing}` :\n `top ${speed}ms ${easing}, left ${speed}ms ${easing}, opacity ${speed}ms ${easing}`;\n\n items.forEach((item) => {\n item.element.style.transition = str;\n });\n }\n\n _getItems() {\n return toArray(this.element.children)\n .filter(el => matches(el, this.options.itemSelector))\n .map(el => new ShuffleItem(el));\n }\n\n /**\n * When new elements are added to the shuffle container, update the array of\n * items because that is the order `_layout` calls them.\n */\n _updateItemsOrder() {\n const children = this.element.children;\n this.items = sorter(this.items, {\n by(element) {\n return Array.prototype.indexOf.call(children, element);\n },\n });\n }\n\n _getFilteredItems() {\n return this.items.filter(item => item.isVisible);\n }\n\n _getConcealedItems() {\n return this.items.filter(item => !item.isVisible);\n }\n\n /**\n * Returns the column size, based on column width and sizer options.\n * @param {number} containerWidth Size of the parent container.\n * @param {number} gutterSize Size of the gutters.\n * @return {number}\n * @private\n */\n _getColumnSize(containerWidth, gutterSize) {\n let size;\n\n // If the columnWidth property is a function, then the grid is fluid\n if (typeof this.options.columnWidth === 'function') {\n size = this.options.columnWidth(containerWidth);\n\n // columnWidth option isn't a function, are they using a sizing element?\n } else if (this.useSizer) {\n size = Shuffle.getSize(this.options.sizer).width;\n\n // if not, how about the explicitly set option?\n } else if (this.options.columnWidth) {\n size = this.options.columnWidth;\n\n // or use the size of the first item\n } else if (this.items.length > 0) {\n size = Shuffle.getSize(this.items[0].element, true).width;\n\n // if there's no items, use size of container\n } else {\n size = containerWidth;\n }\n\n // Don't let them set a column width of zero.\n if (size === 0) {\n size = containerWidth;\n }\n\n return size + gutterSize;\n }\n\n /**\n * Returns the gutter size, based on gutter width and sizer options.\n * @param {number} containerWidth Size of the parent container.\n * @return {number}\n * @private\n */\n _getGutterSize(containerWidth) {\n let size;\n if (typeof this.options.gutterWidth === 'function') {\n size = this.options.gutterWidth(containerWidth);\n } else if (this.useSizer) {\n size = getNumberStyle(this.options.sizer, 'marginLeft');\n } else {\n size = this.options.gutterWidth;\n }\n\n return size;\n }\n\n /**\n * Calculate the number of columns to be used. Gets css if using sizer element.\n * @param {number} [containerWidth] Optionally specify a container width if\n * it's already available.\n */\n _setColumns(containerWidth = Shuffle.getSize(this.element).width) {\n const gutter = this._getGutterSize(containerWidth);\n const columnWidth = this._getColumnSize(containerWidth, gutter);\n let calculatedColumns = (containerWidth + gutter) / columnWidth;\n\n // Widths given from getStyles are not precise enough...\n if (Math.abs(Math.round(calculatedColumns) - calculatedColumns) <\n this.options.columnThreshold) {\n // e.g. calculatedColumns = 11.998876\n calculatedColumns = Math.round(calculatedColumns);\n }\n\n this.cols = Math.max(Math.floor(calculatedColumns), 1);\n this.containerWidth = containerWidth;\n this.colWidth = columnWidth;\n }\n\n /**\n * Adjust the height of the grid\n */\n _setContainerSize() {\n this.element.style.height = this._getContainerSize() + 'px';\n }\n\n /**\n * Based on the column heights, it returns the biggest one.\n * @return {number}\n * @private\n */\n _getContainerSize() {\n return arrayMax(this.positions);\n }\n\n /**\n * Get the clamped stagger amount.\n * @param {number} index Index of the item to be staggered.\n * @return {number}\n */\n _getStaggerAmount(index) {\n return Math.min(index * this.options.staggerAmount, this.options.staggerAmountMax);\n }\n\n /**\n * @return {boolean} Whether the event was prevented or not.\n */\n _dispatch(name, details = {}) {\n if (this.isDestroyed) {\n return false;\n }\n\n details.shuffle = this;\n return !this.element.dispatchEvent(new CustomEvent(name, {\n bubbles: true,\n cancelable: false,\n detail: details,\n }));\n }\n\n /**\n * Zeros out the y columns array, which is used to determine item placement.\n * @private\n */\n _resetCols() {\n let i = this.cols;\n this.positions = [];\n while (i) {\n i -= 1;\n this.positions.push(0);\n }\n }\n\n /**\n * Loops through each item that should be shown and calculates the x, y position.\n * @param {Array.} items Array of items that will be shown/layed\n * out in order in their array.\n */\n _layout(items) {\n let count = 0;\n items.forEach((item) => {\n const currPos = item.point;\n const currScale = item.scale;\n const itemSize = Shuffle.getSize(item.element, true);\n const pos = this._getItemPosition(itemSize);\n\n function callback() {\n item.element.style.transitionDelay = '';\n item.applyCss(ShuffleItem.Css.VISIBLE.after);\n }\n\n // If the item will not change its position, do not add it to the render\n // queue. Transitions don't fire when setting a property to the same value.\n if (Point.equals(currPos, pos) && currScale === ShuffleItem.Scale.VISIBLE) {\n item.applyCss(ShuffleItem.Css.VISIBLE.before);\n callback();\n return;\n }\n\n item.point = pos;\n item.scale = ShuffleItem.Scale.VISIBLE;\n\n // Use xtend here to clone the object so that the `before` object isn't\n // modified when the transition delay is added.\n const styles = xtend(ShuffleItem.Css.VISIBLE.before);\n styles.transitionDelay = this._getStaggerAmount(count) + 'ms';\n\n this._queue.push({\n item,\n styles,\n callback,\n });\n\n count += 1;\n });\n }\n\n /**\n * Determine the location of the next item, based on its size.\n * @param {{width: number, height: number}} itemSize Object with width and height.\n * @return {Point}\n * @private\n */\n _getItemPosition(itemSize) {\n return getItemPosition({\n itemSize,\n positions: this.positions,\n gridSize: this.colWidth,\n total: this.cols,\n threshold: this.options.columnThreshold,\n buffer: this.options.buffer,\n });\n }\n\n /**\n * Hides the elements that don't match our filter.\n * @param {Array.} collection Collection to shrink.\n * @private\n */\n _shrink(collection = this._getConcealedItems()) {\n let count = 0;\n collection.forEach((item) => {\n function callback() {\n item.applyCss(ShuffleItem.Css.HIDDEN.after);\n }\n\n // Continuing would add a transitionend event listener to the element, but\n // that listener would not execute because the transform and opacity would\n // stay the same.\n // The callback is executed here because it is not guaranteed to be called\n // after the transitionend event because the transitionend could be\n // canceled if another animation starts.\n if (item.scale === ShuffleItem.Scale.HIDDEN) {\n item.applyCss(ShuffleItem.Css.HIDDEN.before);\n callback();\n return;\n }\n\n item.scale = ShuffleItem.Scale.HIDDEN;\n\n const styles = xtend(ShuffleItem.Css.HIDDEN.before);\n styles.transitionDelay = this._getStaggerAmount(count) + 'ms';\n\n this._queue.push({\n item,\n styles,\n callback,\n });\n\n count += 1;\n });\n }\n\n /**\n * Resize handler.\n * @private\n */\n _handleResize() {\n // If shuffle is disabled, destroyed, don't do anything\n if (!this.isEnabled || this.isDestroyed) {\n return;\n }\n\n // Will need to check height in the future if it's layed out horizontaly\n const containerWidth = Shuffle.getSize(this.element).width;\n\n // containerWidth hasn't changed, don't do anything\n if (containerWidth === this.containerWidth) {\n return;\n }\n\n this.update();\n }\n\n /**\n * Returns styles which will be applied to the an item for a transition.\n * @param {Object} obj Transition options.\n * @return {!Object} Transforms for transitions, left/top for animate.\n * @private\n */\n _getStylesForTransition({ item, styles }) {\n if (!styles.transitionDelay) {\n styles.transitionDelay = '0ms';\n }\n\n const x = item.point.x;\n const y = item.point.y;\n\n if (this.options.useTransforms) {\n styles.transform = `translate(${x}px, ${y}px) scale(${item.scale})`;\n } else {\n styles.left = x + 'px';\n styles.top = y + 'px';\n }\n\n return styles;\n }\n\n /**\n * Listen for the transition end on an element and execute the itemCallback\n * when it finishes.\n * @param {Element} element Element to listen on.\n * @param {Function} itemCallback Callback for the item.\n * @param {Function} done Callback to notify `parallel` that this one is done.\n */\n _whenTransitionDone(element, itemCallback, done) {\n const id = onTransitionEnd(element, (evt) => {\n itemCallback();\n done(null, evt);\n });\n\n this._transitions.push(id);\n }\n\n /**\n * Return a function which will set CSS styles and call the `done` function\n * when (if) the transition finishes.\n * @param {Object} opts Transition object.\n * @return {Function} A function to be called with a `done` function.\n */\n _getTransitionFunction(opts) {\n return (done) => {\n opts.item.applyCss(this._getStylesForTransition(opts));\n this._whenTransitionDone(opts.item.element, opts.callback, done);\n };\n }\n\n /**\n * Execute the styles gathered in the style queue. This applies styles to elements,\n * triggering transitions.\n * @private\n */\n _processQueue() {\n if (this.isTransitioning) {\n this._cancelMovement();\n }\n\n const hasSpeed = this.options.speed > 0;\n const hasQueue = this._queue.length > 0;\n\n if (hasQueue && hasSpeed && this.isInitialized) {\n this._startTransitions(this._queue);\n } else if (hasQueue) {\n this._styleImmediately(this._queue);\n this._dispatchLayout();\n\n // A call to layout happened, but none of the newly visible items will\n // change position or the transition duration is zero, which will not trigger\n // the transitionend event.\n } else {\n this._dispatchLayout();\n }\n\n // Remove everything in the style queue\n this._queue.length = 0;\n }\n\n /**\n * Wait for each transition to finish, the emit the layout event.\n * @param {Array.} transitions Array of transition objects.\n */\n _startTransitions(transitions) {\n // Set flag that shuffle is currently in motion.\n this.isTransitioning = true;\n\n // Create an array of functions to be called.\n const callbacks = transitions.map(obj => this._getTransitionFunction(obj));\n\n parallel(callbacks, this._movementFinished.bind(this));\n }\n\n _cancelMovement() {\n // Remove the transition end event for each listener.\n this._transitions.forEach(cancelTransitionEnd);\n\n // Reset the array.\n this._transitions.length = 0;\n\n // Show it's no longer active.\n this.isTransitioning = false;\n }\n\n /**\n * Apply styles without a transition.\n * @param {Array.} objects Array of transition objects.\n * @private\n */\n _styleImmediately(objects) {\n if (objects.length) {\n const elements = objects.map(obj => obj.item.element);\n\n Shuffle._skipTransitions(elements, () => {\n objects.forEach((obj) => {\n obj.item.applyCss(this._getStylesForTransition(obj));\n obj.callback();\n });\n });\n }\n }\n\n _movementFinished() {\n this._transitions.length = 0;\n this.isTransitioning = false;\n this._dispatchLayout();\n }\n\n _dispatchLayout() {\n this._dispatch(Shuffle.EventType.LAYOUT);\n }\n\n /**\n * The magic. This is what makes the plugin 'shuffle'\n * @param {string|Function|Array.} [category] Category to filter by.\n * Can be a function, string, or array of strings.\n * @param {Object} [sortObj] A sort object which can sort the visible set\n */\n filter(category, sortObj) {\n if (!this.isEnabled) {\n return;\n }\n\n if (!category || (category && category.length === 0)) {\n category = Shuffle.ALL_ITEMS; // eslint-disable-line no-param-reassign\n }\n\n this._filter(category);\n\n // Shrink each hidden item\n this._shrink();\n\n // How many visible elements?\n this._updateItemCount();\n\n // Update transforms on visible elements so they will animate to their new positions.\n this.sort(sortObj);\n }\n\n /**\n * Gets the visible elements, sorts them, and passes them to layout.\n * @param {Object} opts the options object for the sorted plugin\n */\n sort(opts = this.lastSort) {\n if (!this.isEnabled) {\n return;\n }\n\n this._resetCols();\n\n let items = this._getFilteredItems();\n items = sorter(items, opts);\n\n this._layout(items);\n\n // `_layout` always happens after `_shrink`, so it's safe to process the style\n // queue here with styles from the shrink method.\n this._processQueue();\n\n // Adjust the height of the container.\n this._setContainerSize();\n\n this.lastSort = opts;\n }\n\n /**\n * Reposition everything.\n * @param {boolean} isOnlyLayout If true, column and gutter widths won't be\n * recalculated.\n */\n update(isOnlyLayout) {\n if (this.isEnabled) {\n if (!isOnlyLayout) {\n // Get updated colCount\n this._setColumns();\n }\n\n // Layout items\n this.sort();\n }\n }\n\n /**\n * Use this instead of `update()` if you don't need the columns and gutters updated\n * Maybe an image inside `shuffle` loaded (and now has a height), which means calculations\n * could be off.\n */\n layout() {\n this.update(true);\n }\n\n /**\n * New items have been appended to shuffle. Mix them in with the current\n * filter or sort status.\n * @param {Array.} newItems Collection of new items.\n */\n add(newItems) {\n const items = arrayUnique(newItems).map(el => new ShuffleItem(el));\n\n // Add classes and set initial positions.\n this._initItems(items);\n\n // Add transition to each item.\n this._setTransitions(items);\n\n // Update the list of items.\n this.items = this.items.concat(items);\n this._updateItemsOrder();\n this.filter(this.lastFilter);\n }\n\n /**\n * Disables shuffle from updating dimensions and layout on resize\n */\n disable() {\n this.isEnabled = false;\n }\n\n /**\n * Enables shuffle again\n * @param {boolean} [isUpdateLayout=true] if undefined, shuffle will update columns and gutters\n */\n enable(isUpdateLayout) {\n this.isEnabled = true;\n if (isUpdateLayout !== false) {\n this.update();\n }\n }\n\n /**\n * Remove 1 or more shuffle items\n * @param {Array.} elements An array containing one or more\n * elements in shuffle\n * @return {Shuffle} The shuffle object\n */\n remove(elements) {\n if (!elements.length) {\n return;\n }\n\n const collection = arrayUnique(elements);\n\n const oldItems = collection\n .map(element => this.getItemByElement(element))\n .filter(item => !!item);\n\n const handleLayout = () => {\n this.element.removeEventListener(Shuffle.EventType.LAYOUT, handleLayout);\n this._disposeItems(oldItems);\n\n // Remove the collection in the callback\n collection.forEach((element) => {\n element.parentNode.removeChild(element);\n });\n\n this._dispatch(Shuffle.EventType.REMOVED, { collection });\n };\n\n // Hide collection first.\n this._toggleFilterClasses({\n visible: [],\n hidden: oldItems,\n });\n\n this._shrink(oldItems);\n\n this.sort();\n\n // Update the list of items here because `remove` could be called again\n // with an item that is in the process of being removed.\n this.items = this.items.filter(item => !arrayIncludes(oldItems, item));\n this._updateItemCount();\n\n this.element.addEventListener(Shuffle.EventType.LAYOUT, handleLayout);\n }\n\n /**\n * Retrieve a shuffle item by its element.\n * @param {Element} element Element to look for.\n * @return {?ShuffleItem} A shuffle item or null if it's not found.\n */\n getItemByElement(element) {\n for (let i = this.items.length - 1; i >= 0; i--) {\n if (this.items[i].element === element) {\n return this.items[i];\n }\n }\n\n return null;\n }\n\n /**\n * Destroys shuffle, removes events, styles, and classes\n */\n destroy() {\n this._cancelMovement();\n window.removeEventListener('resize', this._onResize);\n\n // Reset container styles\n this.element.classList.remove('shuffle');\n this.element.removeAttribute('style');\n\n // Reset individual item styles\n this._disposeItems();\n\n // Null DOM references\n this.items = null;\n this.options.sizer = null;\n this.element = null;\n this._transitions = null;\n\n // Set a flag so if a debounced resize has been triggered,\n // it can first check if it is actually isDestroyed and not doing anything\n this.isDestroyed = true;\n }\n\n /**\n * Returns the outer width of an element, optionally including its margins.\n *\n * There are a few different methods for getting the width of an element, none of\n * which work perfectly for all Shuffle's use cases.\n *\n * 1. getBoundingClientRect() `left` and `right` properties.\n * - Accounts for transform scaled elements, making it useless for Shuffle\n * elements which have shrunk.\n * 2. The `offsetWidth` property.\n * - This value stays the same regardless of the elements transform property,\n * however, it does not return subpixel values.\n * 3. getComputedStyle()\n * - This works great Chrome, Firefox, Safari, but IE<=11 does not include\n * padding and border when box-sizing: border-box is set, requiring a feature\n * test and extra work to add the padding back for IE and other browsers which\n * follow the W3C spec here.\n *\n * @param {Element} element The element.\n * @param {boolean} [includeMargins] Whether to include margins. Default is false.\n * @return {{width: number, height: number}} The width and height.\n */\n static getSize(element, includeMargins) {\n // Store the styles so that they can be used by others without asking for it again.\n const styles = window.getComputedStyle(element, null);\n let width = getNumberStyle(element, 'width', styles);\n let height = getNumberStyle(element, 'height', styles);\n\n if (includeMargins) {\n const marginLeft = getNumberStyle(element, 'marginLeft', styles);\n const marginRight = getNumberStyle(element, 'marginRight', styles);\n const marginTop = getNumberStyle(element, 'marginTop', styles);\n const marginBottom = getNumberStyle(element, 'marginBottom', styles);\n width += marginLeft + marginRight;\n height += marginTop + marginBottom;\n }\n\n return {\n width,\n height,\n };\n }\n\n /**\n * Change a property or execute a function which will not have a transition\n * @param {Array.} elements DOM elements that won't be transitioned.\n * @param {Function} callback A function which will be called while transition\n * is set to 0ms.\n * @private\n */\n static _skipTransitions(elements, callback) {\n const zero = '0ms';\n\n // Save current duration and delay.\n const data = elements.map((element) => {\n const style = element.style;\n const duration = style.transitionDuration;\n const delay = style.transitionDelay;\n\n // Set the duration to zero so it happens immediately\n style.transitionDuration = zero;\n style.transitionDelay = zero;\n\n return {\n duration,\n delay,\n };\n });\n\n callback();\n\n // Cause reflow.\n elements[0].offsetWidth; // eslint-disable-line no-unused-expressions\n\n // Put the duration back\n elements.forEach((element, i) => {\n element.style.transitionDuration = data[i].duration;\n element.style.transitionDelay = data[i].delay;\n });\n }\n}\n\nShuffle.ShuffleItem = ShuffleItem;\n\nShuffle.ALL_ITEMS = 'all';\nShuffle.FILTER_ATTRIBUTE_KEY = 'groups';\n\n/**\n * @enum {string}\n */\nShuffle.EventType = {\n LAYOUT: 'shuffle:layout',\n REMOVED: 'shuffle:removed',\n};\n\n/** @enum {string} */\nShuffle.Classes = Classes;\n\n/**\n * @enum {string}\n */\nShuffle.FilterMode = {\n ANY: 'any',\n ALL: 'all',\n};\n\n// Overrideable options\nShuffle.options = {\n // Initial filter group.\n group: Shuffle.ALL_ITEMS,\n\n // Transition/animation speed (milliseconds).\n speed: 250,\n\n // CSS easing function to use.\n easing: 'ease',\n\n // e.g. '.picture-item'.\n itemSelector: '*',\n\n // Element or selector string. Use an element to determine the size of columns\n // and gutters.\n sizer: null,\n\n // A static number or function that tells the plugin how wide the gutters\n // between columns are (in pixels).\n gutterWidth: 0,\n\n // A static number or function that returns a number which tells the plugin\n // how wide the columns are (in pixels).\n columnWidth: 0,\n\n // If your group is not json, and is comma delimeted, you could set delimeter\n // to ','.\n delimeter: null,\n\n // Useful for percentage based heights when they might not always be exactly\n // the same (in pixels).\n buffer: 0,\n\n // Reading the width of elements isn't precise enough and can cause columns to\n // jump between values.\n columnThreshold: 0.01,\n\n // Shuffle can be isInitialized with a sort object. It is the same object\n // given to the sort method.\n initialSort: null,\n\n // By default, shuffle will throttle resize events. This can be changed or\n // removed.\n throttle,\n\n // How often shuffle can be called on resize (in milliseconds).\n throttleTime: 300,\n\n // Transition delay offset for each item in milliseconds.\n staggerAmount: 15,\n\n // Maximum stagger delay in milliseconds.\n staggerAmountMax: 250,\n\n // Whether to use transforms or absolute positioning.\n useTransforms: true,\n\n // Affects using an array with filter. e.g. `filter(['one', 'two'])`. With \"any\",\n // the element passes the test if any of its groups are in the array. With \"all\",\n // the element only passes if all groups are in the array.\n filterMode: Shuffle.FilterMode.ANY,\n};\n\n// Expose for testing. Hack at your own risk.\nShuffle.__Point = Point;\nShuffle.__sorter = sorter;\nShuffle.__getColumnSpan = getColumnSpan;\nShuffle.__getAvailablePositions = getAvailablePositions;\nShuffle.__getShortColumn = getShortColumn;\n\nexport default Shuffle;\n"],"names":["CustomEvent","global","getNumber","value","parseFloat","Point","x","y","a","b","id","ShuffleItem","element","isVisible","classList","remove","Classes","HIDDEN","add","VISIBLE","addClasses","SHUFFLE_ITEM","applyCss","Css","INITIAL","scale","Scale","point","classes","forEach","className","obj","keys","key","style","removeClasses","removeAttribute","document","body","documentElement","e","createElement","cssText","appendChild","width","window","getComputedStyle","ret","removeChild","getNumberStyle","styles","COMPUTED_SIZE_INCLUDES_PADDING","paddingLeft","paddingRight","borderLeftWidth","borderRightWidth","paddingTop","paddingBottom","borderTopWidth","borderBottomWidth","randomize","array","n","length","i","Math","floor","random","temp","defaults","sorter","arr","options","opts","xtend","original","slice","call","revert","by","sort","valA","valB","undefined","reverse","transitions","eventName","count","uniqueId","cancelTransitionEnd","removeEventListener","listener","onTransitionEnd","callback","evt","currentTarget","target","addEventListener","arrayMax","max","apply","arrayMin","min","getColumnSpan","itemWidth","columnWidth","columns","threshold","columnSpan","abs","round","ceil","getAvailablePositions","positions","available","push","getShortColumn","buffer","minPosition","len","getItemPosition","itemSize","gridSize","total","span","setY","shortColumnIndex","setHeight","height","toArray","arrayLike","Array","prototype","arrayIncludes","indexOf","Shuffle","useSizer","lastSort","group","ALL_ITEMS","lastFilter","isEnabled","isDestroyed","isInitialized","_transitions","isTransitioning","_queue","el","_getElementOption","TypeError","_init","items","_getItems","sizer","BASE","_initItems","_onResize","_getResizeFunction","containerCss","containerWidth","getSize","_validateStyles","_setColumns","filter","initialSort","offsetWidth","_setTransitions","transition","speed","easing","resizeFunction","_handleResize","bind","throttle","throttleTime","option","querySelector","nodeType","jquery","position","overflow","category","collection","set","_getFilteredSets","_toggleFilterClasses","visible","hidden","item","_doesPassFilter","attr","getAttribute","FILTER_ATTRIBUTE_KEY","delimeter","split","JSON","parse","testCategory","isArray","filterMode","FilterMode","ANY","some","every","show","hide","init","dispose","visibleItems","_getFilteredItems","str","useTransforms","children","matches","itemSelector","map","gutterSize","size","gutterWidth","gutter","_getGutterSize","_getColumnSize","calculatedColumns","columnThreshold","cols","colWidth","_getContainerSize","index","staggerAmount","staggerAmountMax","name","details","shuffle","dispatchEvent","currPos","currScale","pos","_getItemPosition","transitionDelay","after","equals","before","_getStaggerAmount","_getConcealedItems","update","transform","left","top","itemCallback","done","_getStylesForTransition","_whenTransitionDone","_cancelMovement","hasSpeed","hasQueue","_startTransitions","_styleImmediately","_dispatchLayout","callbacks","_getTransitionFunction","_movementFinished","objects","elements","_skipTransitions","_dispatch","EventType","LAYOUT","sortObj","_filter","_shrink","_updateItemCount","_resetCols","_layout","_processQueue","_setContainerSize","isOnlyLayout","newItems","arrayUnique","concat","_updateItemsOrder","isUpdateLayout","oldItems","getItemByElement","handleLayout","_disposeItems","parentNode","REMOVED","includeMargins","marginLeft","marginRight","marginTop","marginBottom","zero","data","duration","transitionDuration","delay","__Point","__sorter","__getColumnSpan","__getAvailablePositions","__getShortColumn"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"shuffle.js","sources":["../node_modules/tiny-emitter/index.js","../node_modules/matches-selector/index.js","../node_modules/throttleit/index.js","../node_modules/array-parallel/index.js","../src/get-number.js","../src/point.js","../src/rect.js","../src/classes.js","../src/shuffle-item.js","../src/computed-size.js","../src/get-number-style.js","../src/sorter.js","../src/on-transition-end.js","../src/array-max.js","../src/array-min.js","../src/layout.js","../src/hyphenate.js","../src/shuffle.js"],"sourcesContent":["function E () {\n // Keep this empty so it's easier to inherit from\n // (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3)\n}\n\nE.prototype = {\n on: function (name, callback, ctx) {\n var e = this.e || (this.e = {});\n\n (e[name] || (e[name] = [])).push({\n fn: callback,\n ctx: ctx\n });\n\n return this;\n },\n\n once: function (name, callback, ctx) {\n var self = this;\n function listener () {\n self.off(name, listener);\n callback.apply(ctx, arguments);\n };\n\n listener._ = callback\n return this.on(name, listener, ctx);\n },\n\n emit: function (name) {\n var data = [].slice.call(arguments, 1);\n var evtArr = ((this.e || (this.e = {}))[name] || []).slice();\n var i = 0;\n var len = evtArr.length;\n\n for (i; i < len; i++) {\n evtArr[i].fn.apply(evtArr[i].ctx, data);\n }\n\n return this;\n },\n\n off: function (name, callback) {\n var e = this.e || (this.e = {});\n var evts = e[name];\n var liveEvents = [];\n\n if (evts && callback) {\n for (var i = 0, len = evts.length; i < len; i++) {\n if (evts[i].fn !== callback && evts[i].fn._ !== callback)\n liveEvents.push(evts[i]);\n }\n }\n\n // Remove event from queue to prevent memory leak\n // Suggested by https://github.com/lazd\n // Ref: https://github.com/scottcorgan/tiny-emitter/commit/c6ebfaa9bc973b33d110a84a307742b7cf94c953#commitcomment-5024910\n\n (liveEvents.length)\n ? e[name] = liveEvents\n : delete e[name];\n\n return this;\n }\n};\n\nmodule.exports = E;\n","'use strict';\n\nvar proto = typeof Element !== 'undefined' ? Element.prototype : {};\nvar vendor = proto.matches\n || proto.matchesSelector\n || proto.webkitMatchesSelector\n || proto.mozMatchesSelector\n || proto.msMatchesSelector\n || proto.oMatchesSelector;\n\nmodule.exports = match;\n\n/**\n * Match `el` to `selector`.\n *\n * @param {Element} el\n * @param {String} selector\n * @return {Boolean}\n * @api public\n */\n\nfunction match(el, selector) {\n if (!el || el.nodeType !== 1) return false;\n if (vendor) return vendor.call(el, selector);\n var nodes = el.parentNode.querySelectorAll(selector);\n for (var i = 0; i < nodes.length; i++) {\n if (nodes[i] == el) return true;\n }\n return false;\n}\n","module.exports = throttle;\n\n/**\n * Returns a new function that, when invoked, invokes `func` at most once per `wait` milliseconds.\n *\n * @param {Function} func Function to wrap.\n * @param {Number} wait Number of milliseconds that must elapse between `func` invocations.\n * @return {Function} A new function that wraps the `func` function passed in.\n */\n\nfunction throttle (func, wait) {\n var ctx, args, rtn, timeoutID; // caching\n var last = 0;\n\n return function throttled () {\n ctx = this;\n args = arguments;\n var delta = new Date() - last;\n if (!timeoutID)\n if (delta >= wait) call();\n else timeoutID = setTimeout(call, wait - delta);\n return rtn;\n };\n\n function call () {\n timeoutID = 0;\n last = +new Date();\n rtn = func.apply(ctx, args);\n ctx = null;\n args = null;\n }\n}\n","module.exports = function parallel(fns, context, callback) {\n if (!callback) {\n if (typeof context === 'function') {\n callback = context\n context = null\n } else {\n callback = noop\n }\n }\n\n var pending = fns && fns.length\n if (!pending) return callback(null, []);\n\n var finished = false\n var results = new Array(pending)\n\n fns.forEach(context ? function (fn, i) {\n fn.call(context, maybeDone(i))\n } : function (fn, i) {\n fn(maybeDone(i))\n })\n\n function maybeDone(i) {\n return function (err, result) {\n if (finished) return;\n\n if (err) {\n callback(err, results)\n finished = true\n return\n }\n\n results[i] = result\n\n if (!--pending) callback(null, results);\n }\n }\n}\n\nfunction noop() {}\n","/**\n * Always returns a numeric value, given a value. Logic from jQuery's `isNumeric`.\n * @param {*} value Possibly numeric value.\n * @return {number} `value` or zero if `value` isn't numeric.\n */\nexport default function getNumber(value) {\n return parseFloat(value) || 0;\n}\n","import getNumber from './get-number';\n\nclass Point {\n\n /**\n * Represents a coordinate pair.\n * @param {number} [x=0] X.\n * @param {number} [y=0] Y.\n */\n constructor(x, y) {\n this.x = getNumber(x);\n this.y = getNumber(y);\n }\n\n /**\n * Whether two points are equal.\n * @param {Point} a Point A.\n * @param {Point} b Point B.\n * @return {boolean}\n */\n static equals(a, b) {\n return a.x === b.x && a.y === b.y;\n }\n}\n\nexport default Point;\n","export default class Rect {\n /**\n * Class for representing rectangular regions.\n * https://github.com/google/closure-library/blob/master/closure/goog/math/rect.js\n * @param {number} x Left.\n * @param {number} y Top.\n * @param {number} w Width.\n * @param {number} h Height.\n * @param {number} id Identifier\n * @constructor\n */\n constructor(x, y, w, h, id) {\n this.id = id;\n\n /** @type {number} */\n this.left = x;\n\n /** @type {number} */\n this.top = y;\n\n /** @type {number} */\n this.width = w;\n\n /** @type {number} */\n this.height = h;\n }\n\n /**\n * Returns whether two rectangles intersect.\n * @param {Rect} a A Rectangle.\n * @param {Rect} b A Rectangle.\n * @return {boolean} Whether a and b intersect.\n */\n static intersects(a, b) {\n return (\n a.left < b.left + b.width && b.left < a.left + a.width &&\n a.top < b.top + b.height && b.top < a.top + a.height);\n }\n}\n","export default {\n BASE: 'shuffle',\n SHUFFLE_ITEM: 'shuffle-item',\n VISIBLE: 'shuffle-item--visible',\n HIDDEN: 'shuffle-item--hidden',\n};\n","import Point from './point';\nimport Classes from './classes';\n\nlet id = 0;\n\nclass ShuffleItem {\n constructor(element) {\n id += 1;\n this.id = id;\n this.element = element;\n\n /**\n * Used to separate items for layout and shrink.\n */\n this.isVisible = true;\n\n /**\n * Used to determine if a transition will happen. By the time the _layout\n * and _shrink methods get the ShuffleItem instances, the `isVisible` value\n * has already been changed by the separation methods, so this property is\n * needed to know if the item was visible/hidden before the shrink/layout.\n */\n this.isHidden = false;\n }\n\n show() {\n this.isVisible = true;\n this.element.classList.remove(Classes.HIDDEN);\n this.element.classList.add(Classes.VISIBLE);\n this.element.removeAttribute('aria-hidden');\n }\n\n hide() {\n this.isVisible = false;\n this.element.classList.remove(Classes.VISIBLE);\n this.element.classList.add(Classes.HIDDEN);\n this.element.setAttribute('aria-hidden', true);\n }\n\n init() {\n this.addClasses([Classes.SHUFFLE_ITEM, Classes.VISIBLE]);\n this.applyCss(ShuffleItem.Css.INITIAL);\n this.scale = ShuffleItem.Scale.VISIBLE;\n this.point = new Point();\n }\n\n addClasses(classes) {\n classes.forEach((className) => {\n this.element.classList.add(className);\n });\n }\n\n removeClasses(classes) {\n classes.forEach((className) => {\n this.element.classList.remove(className);\n });\n }\n\n applyCss(obj) {\n Object.keys(obj).forEach((key) => {\n this.element.style[key] = obj[key];\n });\n }\n\n dispose() {\n this.removeClasses([\n Classes.HIDDEN,\n Classes.VISIBLE,\n Classes.SHUFFLE_ITEM,\n ]);\n\n this.element.removeAttribute('style');\n this.element = null;\n }\n}\n\nShuffleItem.Css = {\n INITIAL: {\n position: 'absolute',\n top: 0,\n left: 0,\n visibility: 'visible',\n 'will-change': 'transform',\n },\n VISIBLE: {\n before: {\n opacity: 1,\n visibility: 'visible',\n },\n after: {\n transitionDelay: '',\n },\n },\n HIDDEN: {\n before: {\n opacity: 0,\n },\n after: {\n visibility: 'hidden',\n transitionDelay: '',\n },\n },\n};\n\nShuffleItem.Scale = {\n VISIBLE: 1,\n HIDDEN: 0.001,\n};\n\nexport default ShuffleItem;\n","const element = document.body || document.documentElement;\nconst e = document.createElement('div');\ne.style.cssText = 'width:10px;padding:2px;box-sizing:border-box;';\nelement.appendChild(e);\n\nconst width = window.getComputedStyle(e, null).width;\nconst ret = width === '10px';\n\nelement.removeChild(e);\n\nexport default ret;\n","import getNumber from './get-number';\nimport COMPUTED_SIZE_INCLUDES_PADDING from './computed-size';\n\n/**\n * Retrieve the computed style for an element, parsed as a float.\n * @param {Element} element Element to get style for.\n * @param {string} style Style property.\n * @param {CSSStyleDeclaration} [styles] Optionally include clean styles to\n * use instead of asking for them again.\n * @return {number} The parsed computed value or zero if that fails because IE\n * will return 'auto' when the element doesn't have margins instead of\n * the computed style.\n */\nexport default function getNumberStyle(element, style,\n styles = window.getComputedStyle(element, null)) {\n let value = getNumber(styles[style]);\n\n // Support IE<=11 and W3C spec.\n if (!COMPUTED_SIZE_INCLUDES_PADDING && style === 'width') {\n value += getNumber(styles.paddingLeft) +\n getNumber(styles.paddingRight) +\n getNumber(styles.borderLeftWidth) +\n getNumber(styles.borderRightWidth);\n } else if (!COMPUTED_SIZE_INCLUDES_PADDING && style === 'height') {\n value += getNumber(styles.paddingTop) +\n getNumber(styles.paddingBottom) +\n getNumber(styles.borderTopWidth) +\n getNumber(styles.borderBottomWidth);\n }\n\n return value;\n}\n","/**\n * Fisher-Yates shuffle.\n * http://stackoverflow.com/a/962890/373422\n * https://bost.ocks.org/mike/shuffle/\n * @param {Array} array Array to shuffle.\n * @return {Array} Randomly sorted array.\n */\nfunction randomize(array) {\n let n = array.length;\n\n while (n) {\n n -= 1;\n const i = Math.floor(Math.random() * (n + 1));\n const temp = array[i];\n array[i] = array[n];\n array[n] = temp;\n }\n\n return array;\n}\n\nconst defaults = {\n // Use array.reverse() to reverse the results\n reverse: false,\n\n // Sorting function\n by: null,\n\n // If true, this will skip the sorting and return a randomized order in the array\n randomize: false,\n\n // Determines which property of each item in the array is passed to the\n // sorting method.\n key: 'element',\n};\n\n// You can return `undefined` from the `by` function to revert to DOM order.\nexport default function sorter(arr, options) {\n const opts = Object.assign({}, defaults, options);\n const original = Array.from(arr);\n let revert = false;\n\n if (!arr.length) {\n return [];\n }\n\n if (opts.randomize) {\n return randomize(arr);\n }\n\n // Sort the elements by the opts.by function.\n // If we don't have opts.by, default to DOM order\n if (typeof opts.by === 'function') {\n arr.sort((a, b) => {\n // Exit early if we already know we want to revert\n if (revert) {\n return 0;\n }\n\n const valA = opts.by(a[opts.key]);\n const valB = opts.by(b[opts.key]);\n\n // If both values are undefined, use the DOM order\n if (valA === undefined && valB === undefined) {\n revert = true;\n return 0;\n }\n\n if (valA < valB || valA === 'sortFirst' || valB === 'sortLast') {\n return -1;\n }\n\n if (valA > valB || valA === 'sortLast' || valB === 'sortFirst') {\n return 1;\n }\n\n return 0;\n });\n }\n\n // Revert to the original array if necessary\n if (revert) {\n return original;\n }\n\n if (opts.reverse) {\n arr.reverse();\n }\n\n return arr;\n}\n","const transitions = {};\nconst eventName = 'transitionend';\nlet count = 0;\n\nfunction uniqueId() {\n count += 1;\n return eventName + count;\n}\n\nexport function cancelTransitionEnd(id) {\n if (transitions[id]) {\n transitions[id].element.removeEventListener(eventName, transitions[id].listener);\n transitions[id] = null;\n return true;\n }\n\n return false;\n}\n\nexport function onTransitionEnd(element, callback) {\n const id = uniqueId();\n const listener = (evt) => {\n if (evt.currentTarget === evt.target) {\n cancelTransitionEnd(id);\n callback(evt);\n }\n };\n\n element.addEventListener(eventName, listener);\n\n transitions[id] = { element, listener };\n\n return id;\n}\n","export default function arrayMax(array) {\n return Math.max.apply(Math, array); // eslint-disable-line prefer-spread\n}\n","export default function arrayMin(array) {\n return Math.min.apply(Math, array); // eslint-disable-line prefer-spread\n}\n","import Point from './point';\nimport Rect from './rect';\nimport arrayMax from './array-max';\nimport arrayMin from './array-min';\n\n/**\n * Determine the number of columns an items spans.\n * @param {number} itemWidth Width of the item.\n * @param {number} columnWidth Width of the column (includes gutter).\n * @param {number} columns Total number of columns\n * @param {number} threshold A buffer value for the size of the column to fit.\n * @return {number}\n */\nexport function getColumnSpan(itemWidth, columnWidth, columns, threshold) {\n let columnSpan = itemWidth / columnWidth;\n\n // If the difference between the rounded column span number and the\n // calculated column span number is really small, round the number to\n // make it fit.\n if (Math.abs(Math.round(columnSpan) - columnSpan) < threshold) {\n // e.g. columnSpan = 4.0089945390298745\n columnSpan = Math.round(columnSpan);\n }\n\n // Ensure the column span is not more than the amount of columns in the whole layout.\n return Math.min(Math.ceil(columnSpan), columns);\n}\n\n/**\n * Retrieves the column set to use for placement.\n * @param {number} columnSpan The number of columns this current item spans.\n * @param {number} columns The total columns in the grid.\n * @return {Array.} An array of numbers represeting the column set.\n */\nexport function getAvailablePositions(positions, columnSpan, columns) {\n // The item spans only one column.\n if (columnSpan === 1) {\n return positions;\n }\n\n // The item spans more than one column, figure out how many different\n // places it could fit horizontally.\n // The group count is the number of places within the positions this block\n // could fit, ignoring the current positions of items.\n // Imagine a 2 column brick as the second item in a 4 column grid with\n // 10px height each. Find the places it would fit:\n // [20, 10, 10, 0]\n // | | |\n // * * *\n //\n // Then take the places which fit and get the bigger of the two:\n // max([20, 10]), max([10, 10]), max([10, 0]) = [20, 10, 0]\n //\n // Next, find the first smallest number (the short column).\n // [20, 10, 0]\n // |\n // *\n //\n // And that's where it should be placed!\n //\n // Another example where the second column's item extends past the first:\n // [10, 20, 10, 0] => [20, 20, 10] => 10\n const available = [];\n\n // For how many possible positions for this item there are.\n for (let i = 0; i <= columns - columnSpan; i++) {\n // Find the bigger value for each place it could fit.\n available.push(arrayMax(positions.slice(i, i + columnSpan)));\n }\n\n return available;\n}\n\n/**\n * Find index of short column, the first from the left where this item will go.\n *\n * @param {Array.} positions The array to search for the smallest number.\n * @param {number} buffer Optional buffer which is very useful when the height\n * is a percentage of the width.\n * @return {number} Index of the short column.\n */\nexport function getShortColumn(positions, buffer) {\n const minPosition = arrayMin(positions);\n for (let i = 0, len = positions.length; i < len; i++) {\n if (positions[i] >= minPosition - buffer && positions[i] <= minPosition + buffer) {\n return i;\n }\n }\n\n return 0;\n}\n\n/**\n * Determine the location of the next item, based on its size.\n * @param {Object} itemSize Object with width and height.\n * @param {Array.} positions Positions of the other current items.\n * @param {number} gridSize The column width or row height.\n * @param {number} total The total number of columns or rows.\n * @param {number} threshold Buffer value for the column to fit.\n * @param {number} buffer Vertical buffer for the height of items.\n * @return {Point}\n */\nexport function getItemPosition({ itemSize, positions, gridSize, total, threshold, buffer }) {\n const span = getColumnSpan(itemSize.width, gridSize, total, threshold);\n const setY = getAvailablePositions(positions, span, total);\n const shortColumnIndex = getShortColumn(setY, buffer);\n\n // Position the item\n const point = new Point(gridSize * shortColumnIndex, setY[shortColumnIndex]);\n\n // Update the columns array with the new values for each column.\n // e.g. before the update the columns could be [250, 0, 0, 0] for an item\n // which spans 2 columns. After it would be [250, itemHeight, itemHeight, 0].\n const setHeight = setY[shortColumnIndex] + itemSize.height;\n for (let i = 0; i < span; i++) {\n positions[shortColumnIndex + i] = setHeight;\n }\n\n return point;\n}\n\n/**\n * This method attempts to center items. This method could potentially be slow\n * with a large number of items because it must place items, then check every\n * previous item to ensure there is no overlap.\n * @param {Array.} itemRects Item data objects.\n * @param {number} containerWidth Width of the containing element.\n * @return {Array.}\n */\nexport function getCenteredPositions(itemRects, containerWidth) {\n const rowMap = {};\n\n // Populate rows by their offset because items could jump between rows like:\n // a c\n // bbb\n itemRects.forEach((itemRect) => {\n if (rowMap[itemRect.top]) {\n // Push the point to the last row array.\n rowMap[itemRect.top].push(itemRect);\n } else {\n // Start of a new row.\n rowMap[itemRect.top] = [itemRect];\n }\n });\n\n // For each row, find the end of the last item, then calculate\n // the remaining space by dividing it by 2. Then add that\n // offset to the x position of each point.\n let rects = [];\n const rows = [];\n const centeredRows = [];\n Object.keys(rowMap).forEach((key) => {\n const itemRects = rowMap[key];\n rows.push(itemRects);\n const lastItem = itemRects[itemRects.length - 1];\n const end = lastItem.left + lastItem.width;\n const offset = Math.round((containerWidth - end) / 2);\n\n let finalRects = itemRects;\n let canMove = false;\n if (offset > 0) {\n const newRects = [];\n canMove = itemRects.every((r) => {\n const newRect = new Rect(r.left + offset, r.top, r.width, r.height, r.id);\n\n // Check all current rects to make sure none overlap.\n const noOverlap = !rects.some(r => Rect.intersects(newRect, r));\n\n newRects.push(newRect);\n return noOverlap;\n });\n\n // If none of the rectangles overlapped, the whole group can be centered.\n if (canMove) {\n finalRects = newRects;\n }\n }\n\n // If the items are not going to be offset, ensure that the original\n // placement for this row will not overlap previous rows (row-spanning\n // elements could be in the way).\n if (!canMove) {\n let intersectingRect;\n const hasOverlap = itemRects.some(itemRect => rects.some((r) => {\n const intersects = Rect.intersects(itemRect, r);\n if (intersects) {\n intersectingRect = r;\n }\n return intersects;\n }));\n\n // If there is any overlap, replace the overlapping row with the original.\n if (hasOverlap) {\n const rowIndex = centeredRows.findIndex(items => items.includes(intersectingRect));\n centeredRows.splice(rowIndex, 1, rows[rowIndex]);\n }\n }\n\n rects = rects.concat(finalRects);\n centeredRows.push(finalRects);\n });\n\n // Reduce array of arrays to a single array of points.\n // https://stackoverflow.com/a/10865042/373422\n // Then reset sort back to how the items were passed to this method.\n // Remove the wrapper object with index, map to a Point.\n return [].concat.apply([], centeredRows) // eslint-disable-line prefer-spread\n .sort((a, b) => (a.id - b.id))\n .map(itemRect => new Point(itemRect.left, itemRect.top));\n}\n","/**\n * Hyphenates a javascript style string to a css one. For example:\n * MozBoxSizing -> -moz-box-sizing.\n * @param {string} str The string to hyphenate.\n * @return {string} The hyphenated string.\n */\nexport default function hyphenate(str) {\n return str.replace(/([A-Z])/g, (str, m1) => `-${m1.toLowerCase()}`);\n}\n","import TinyEmitter from 'tiny-emitter';\nimport matches from 'matches-selector';\nimport throttle from 'throttleit';\nimport parallel from 'array-parallel';\n\nimport Point from './point';\nimport Rect from './rect';\nimport ShuffleItem from './shuffle-item';\nimport Classes from './classes';\nimport getNumberStyle from './get-number-style';\nimport sorter from './sorter';\nimport { onTransitionEnd, cancelTransitionEnd } from './on-transition-end';\nimport {\n getItemPosition,\n getColumnSpan,\n getAvailablePositions,\n getShortColumn,\n getCenteredPositions,\n} from './layout';\nimport arrayMax from './array-max';\nimport hyphenate from './hyphenate';\n\nfunction arrayUnique(x) {\n return Array.from(new Set(x));\n}\n\n// Used for unique instance variables\nlet id = 0;\n\nclass Shuffle extends TinyEmitter {\n\n /**\n * Categorize, sort, and filter a responsive grid of items.\n *\n * @param {Element} element An element which is the parent container for the grid items.\n * @param {Object} [options=Shuffle.options] Options object.\n * @constructor\n */\n constructor(element, options = {}) {\n super();\n this.options = Object.assign({}, Shuffle.options, options);\n\n this.lastSort = {};\n this.group = Shuffle.ALL_ITEMS;\n this.lastFilter = Shuffle.ALL_ITEMS;\n this.isEnabled = true;\n this.isDestroyed = false;\n this.isInitialized = false;\n this._transitions = [];\n this.isTransitioning = false;\n this._queue = [];\n\n const el = this._getElementOption(element);\n\n if (!el) {\n throw new TypeError('Shuffle needs to be initialized with an element.');\n }\n\n this.element = el;\n this.id = 'shuffle_' + id;\n id += 1;\n\n this._init();\n this.isInitialized = true;\n }\n\n _init() {\n this.items = this._getItems();\n\n this.options.sizer = this._getElementOption(this.options.sizer);\n\n // Add class and invalidate styles\n this.element.classList.add(Shuffle.Classes.BASE);\n\n // Set initial css for each item\n this._initItems(this.items);\n\n // Bind resize events\n this._onResize = this._getResizeFunction();\n window.addEventListener('resize', this._onResize);\n\n // If the page has not already emitted the `load` event, call layout on load.\n // This avoids layout issues caused by images and fonts loading after the\n // instance has been initialized.\n if (document.readyState !== 'complete') {\n const layout = this.layout.bind(this);\n window.addEventListener('load', function onLoad() {\n window.removeEventListener('load', onLoad);\n layout();\n });\n }\n\n // Get container css all in one request. Causes reflow\n const containerCss = window.getComputedStyle(this.element, null);\n const containerWidth = Shuffle.getSize(this.element).width;\n\n // Add styles to the container if it doesn't have them.\n this._validateStyles(containerCss);\n\n // We already got the container's width above, no need to cause another\n // reflow getting it again... Calculate the number of columns there will be\n this._setColumns(containerWidth);\n\n // Kick off!\n this.filter(this.options.group, this.options.initialSort);\n\n // The shuffle items haven't had transitions set on them yet so the user\n // doesn't see the first layout. Set them now that the first layout is done.\n // First, however, a synchronous layout must be caused for the previous\n // styles to be applied without transitions.\n this.element.offsetWidth; // eslint-disable-line no-unused-expressions\n this.setItemTransitions(this.items);\n this.element.style.transition = `height ${this.options.speed}ms ${this.options.easing}`;\n }\n\n /**\n * Returns a throttled and proxied function for the resize handler.\n * @return {function}\n * @private\n */\n _getResizeFunction() {\n const resizeFunction = this._handleResize.bind(this);\n return this.options.throttle ?\n this.options.throttle(resizeFunction, this.options.throttleTime) :\n resizeFunction;\n }\n\n /**\n * Retrieve an element from an option.\n * @param {string|jQuery|Element} option The option to check.\n * @return {?Element} The plain element or null.\n * @private\n */\n _getElementOption(option) {\n // If column width is a string, treat is as a selector and search for the\n // sizer element within the outermost container\n if (typeof option === 'string') {\n return this.element.querySelector(option);\n\n // Check for an element\n } else if (option && option.nodeType && option.nodeType === 1) {\n return option;\n\n // Check for jQuery object\n } else if (option && option.jquery) {\n return option[0];\n }\n\n return null;\n }\n\n /**\n * Ensures the shuffle container has the css styles it needs applied to it.\n * @param {Object} styles Key value pairs for position and overflow.\n * @private\n */\n _validateStyles(styles) {\n // Position cannot be static.\n if (styles.position === 'static') {\n this.element.style.position = 'relative';\n }\n\n // Overflow has to be hidden.\n if (styles.overflow !== 'hidden') {\n this.element.style.overflow = 'hidden';\n }\n }\n\n /**\n * Filter the elements by a category.\n * @param {string|string[]|function(Element):boolean} [category] Category to\n * filter by. If it's given, the last category will be used to filter the items.\n * @param {Array} [collection] Optionally filter a collection. Defaults to\n * all the items.\n * @return {{visible: ShuffleItem[], hidden: ShuffleItem[]}}\n * @private\n */\n _filter(category = this.lastFilter, collection = this.items) {\n const set = this._getFilteredSets(category, collection);\n\n // Individually add/remove hidden/visible classes\n this._toggleFilterClasses(set);\n\n // Save the last filter in case elements are appended.\n this.lastFilter = category;\n\n // This is saved mainly because providing a filter function (like searching)\n // will overwrite the `lastFilter` property every time its called.\n if (typeof category === 'string') {\n this.group = category;\n }\n\n return set;\n }\n\n /**\n * Returns an object containing the visible and hidden elements.\n * @param {string|string[]|function(Element):boolean} category Category or function to filter by.\n * @param {ShuffleItem[]} items A collection of items to filter.\n * @return {{visible: ShuffleItem[], hidden: ShuffleItem[]}}\n * @private\n */\n _getFilteredSets(category, items) {\n let visible = [];\n const hidden = [];\n\n // category === 'all', add visible class to everything\n if (category === Shuffle.ALL_ITEMS) {\n visible = items;\n\n // Loop through each item and use provided function to determine\n // whether to hide it or not.\n } else {\n items.forEach((item) => {\n if (this._doesPassFilter(category, item.element)) {\n visible.push(item);\n } else {\n hidden.push(item);\n }\n });\n }\n\n return {\n visible,\n hidden,\n };\n }\n\n /**\n * Test an item to see if it passes a category.\n * @param {string|string[]|function():boolean} category Category or function to filter by.\n * @param {Element} element An element to test.\n * @return {boolean} Whether it passes the category/filter.\n * @private\n */\n _doesPassFilter(category, element) {\n if (typeof category === 'function') {\n return category.call(element, element, this);\n }\n\n // Check each element's data-groups attribute against the given category.\n const attr = element.getAttribute('data-' + Shuffle.FILTER_ATTRIBUTE_KEY);\n const keys = this.options.delimeter ?\n attr.split(this.options.delimeter) :\n JSON.parse(attr);\n\n function testCategory(category) {\n return keys.includes(category);\n }\n\n if (Array.isArray(category)) {\n if (this.options.filterMode === Shuffle.FilterMode.ANY) {\n return category.some(testCategory);\n }\n return category.every(testCategory);\n }\n\n return keys.includes(category);\n }\n\n /**\n * Toggles the visible and hidden class names.\n * @param {{visible, hidden}} Object with visible and hidden arrays.\n * @private\n */\n _toggleFilterClasses({ visible, hidden }) {\n visible.forEach((item) => {\n item.show();\n });\n\n hidden.forEach((item) => {\n item.hide();\n });\n }\n\n /**\n * Set the initial css for each item\n * @param {ShuffleItem[]} items Set to initialize.\n * @private\n */\n _initItems(items) {\n items.forEach((item) => {\n item.init();\n });\n }\n\n /**\n * Remove element reference and styles.\n * @param {ShuffleItem[]} items Set to dispose.\n * @private\n */\n _disposeItems(items) {\n items.forEach((item) => {\n item.dispose();\n });\n }\n\n /**\n * Updates the visible item count.\n * @private\n */\n _updateItemCount() {\n this.visibleItems = this._getFilteredItems().length;\n }\n\n /**\n * Sets css transform transition on a group of elements. This is not executed\n * at the same time as `item.init` so that transitions don't occur upon\n * initialization of a new Shuffle instance.\n * @param {ShuffleItem[]} items Shuffle items to set transitions on.\n * @protected\n */\n setItemTransitions(items) {\n const speed = this.options.speed;\n const easing = this.options.easing;\n const positionProps = this.options.useTransforms ? ['transform'] : ['top', 'left'];\n\n // Allow users to transtion other properties if they exist in the `before`\n // css mapping of the shuffle item.\n const properties = positionProps.concat(\n Object.keys(ShuffleItem.Css.HIDDEN.before).map(k => hyphenate(k)),\n ).join();\n\n items.forEach((item) => {\n item.element.style.transitionDuration = speed + 'ms';\n item.element.style.transitionTimingFunction = easing;\n item.element.style.transitionProperty = properties;\n });\n }\n\n _getItems() {\n return Array.from(this.element.children)\n .filter(el => matches(el, this.options.itemSelector))\n .map(el => new ShuffleItem(el));\n }\n\n /**\n * When new elements are added to the shuffle container, update the array of\n * items because that is the order `_layout` calls them.\n * @param {ShuffleItem[]} items Items to track.\n * @return {Shuffle[]}\n */\n _mergeNewItems(items) {\n const children = Array.from(this.element.children);\n return sorter(this.items.concat(items), {\n by(element) {\n return children.indexOf(element);\n },\n });\n }\n\n _getFilteredItems() {\n return this.items.filter(item => item.isVisible);\n }\n\n _getConcealedItems() {\n return this.items.filter(item => !item.isVisible);\n }\n\n /**\n * Returns the column size, based on column width and sizer options.\n * @param {number} containerWidth Size of the parent container.\n * @param {number} gutterSize Size of the gutters.\n * @return {number}\n * @private\n */\n _getColumnSize(containerWidth, gutterSize) {\n let size;\n\n // If the columnWidth property is a function, then the grid is fluid\n if (typeof this.options.columnWidth === 'function') {\n size = this.options.columnWidth(containerWidth);\n\n // columnWidth option isn't a function, are they using a sizing element?\n } else if (this.options.sizer) {\n size = Shuffle.getSize(this.options.sizer).width;\n\n // if not, how about the explicitly set option?\n } else if (this.options.columnWidth) {\n size = this.options.columnWidth;\n\n // or use the size of the first item\n } else if (this.items.length > 0) {\n size = Shuffle.getSize(this.items[0].element, true).width;\n\n // if there's no items, use size of container\n } else {\n size = containerWidth;\n }\n\n // Don't let them set a column width of zero.\n if (size === 0) {\n size = containerWidth;\n }\n\n return size + gutterSize;\n }\n\n /**\n * Returns the gutter size, based on gutter width and sizer options.\n * @param {number} containerWidth Size of the parent container.\n * @return {number}\n * @private\n */\n _getGutterSize(containerWidth) {\n let size;\n if (typeof this.options.gutterWidth === 'function') {\n size = this.options.gutterWidth(containerWidth);\n } else if (this.options.sizer) {\n size = getNumberStyle(this.options.sizer, 'marginLeft');\n } else {\n size = this.options.gutterWidth;\n }\n\n return size;\n }\n\n /**\n * Calculate the number of columns to be used. Gets css if using sizer element.\n * @param {number} [containerWidth] Optionally specify a container width if\n * it's already available.\n */\n _setColumns(containerWidth = Shuffle.getSize(this.element).width) {\n const gutter = this._getGutterSize(containerWidth);\n const columnWidth = this._getColumnSize(containerWidth, gutter);\n let calculatedColumns = (containerWidth + gutter) / columnWidth;\n\n // Widths given from getStyles are not precise enough...\n if (Math.abs(Math.round(calculatedColumns) - calculatedColumns) <\n this.options.columnThreshold) {\n // e.g. calculatedColumns = 11.998876\n calculatedColumns = Math.round(calculatedColumns);\n }\n\n this.cols = Math.max(Math.floor(calculatedColumns), 1);\n this.containerWidth = containerWidth;\n this.colWidth = columnWidth;\n }\n\n /**\n * Adjust the height of the grid\n */\n _setContainerSize() {\n this.element.style.height = this._getContainerSize() + 'px';\n }\n\n /**\n * Based on the column heights, it returns the biggest one.\n * @return {number}\n * @private\n */\n _getContainerSize() {\n return arrayMax(this.positions);\n }\n\n /**\n * Get the clamped stagger amount.\n * @param {number} index Index of the item to be staggered.\n * @return {number}\n */\n _getStaggerAmount(index) {\n return Math.min(index * this.options.staggerAmount, this.options.staggerAmountMax);\n }\n\n /**\n * Emit an event from this instance.\n * @param {string} name Event name.\n * @param {Object} [data={}] Optional object data.\n */\n _dispatch(name, data = {}) {\n if (this.isDestroyed) {\n return;\n }\n\n data.shuffle = this;\n this.emit(name, data);\n }\n\n /**\n * Zeros out the y columns array, which is used to determine item placement.\n * @private\n */\n _resetCols() {\n let i = this.cols;\n this.positions = [];\n while (i) {\n i -= 1;\n this.positions.push(0);\n }\n }\n\n /**\n * Loops through each item that should be shown and calculates the x, y position.\n * @param {ShuffleItem[]} items Array of items that will be shown/layed\n * out in order in their array.\n */\n _layout(items) {\n const itemPositions = this._getNextPositions(items);\n\n let count = 0;\n items.forEach((item, i) => {\n function callback() {\n item.applyCss(ShuffleItem.Css.VISIBLE.after);\n }\n\n // If the item will not change its position, do not add it to the render\n // queue. Transitions don't fire when setting a property to the same value.\n if (Point.equals(item.point, itemPositions[i]) && !item.isHidden) {\n item.applyCss(ShuffleItem.Css.VISIBLE.before);\n callback();\n return;\n }\n\n item.point = itemPositions[i];\n item.scale = ShuffleItem.Scale.VISIBLE;\n item.isHidden = false;\n\n // Clone the object so that the `before` object isn't modified when the\n // transition delay is added.\n const styles = this.getStylesForTransition(item, ShuffleItem.Css.VISIBLE.before);\n styles.transitionDelay = this._getStaggerAmount(count) + 'ms';\n\n this._queue.push({\n item,\n styles,\n callback,\n });\n\n count += 1;\n });\n }\n\n /**\n * Return an array of Point instances representing the future positions of\n * each item.\n * @param {ShuffleItem[]} items Array of sorted shuffle items.\n * @return {Point[]}\n * @private\n */\n _getNextPositions(items) {\n // If position data is going to be changed, add the item's size to the\n // transformer to allow for calculations.\n if (this.options.isCentered) {\n const itemsData = items.map((item, i) => {\n const itemSize = Shuffle.getSize(item.element, true);\n const point = this._getItemPosition(itemSize);\n return new Rect(point.x, point.y, itemSize.width, itemSize.height, i);\n });\n\n return this.getTransformedPositions(itemsData, this.containerWidth);\n }\n\n // If no transforms are going to happen, simply return an array of the\n // future points of each item.\n return items.map(item => this._getItemPosition(Shuffle.getSize(item.element, true)));\n }\n\n /**\n * Determine the location of the next item, based on its size.\n * @param {{width: number, height: number}} itemSize Object with width and height.\n * @return {Point}\n * @private\n */\n _getItemPosition(itemSize) {\n return getItemPosition({\n itemSize,\n positions: this.positions,\n gridSize: this.colWidth,\n total: this.cols,\n threshold: this.options.columnThreshold,\n buffer: this.options.buffer,\n });\n }\n\n /**\n * Mutate positions before they're applied.\n * @param {Rect[]} itemRects Item data objects.\n * @param {number} containerWidth Width of the containing element.\n * @return {Point[]}\n * @protected\n */\n getTransformedPositions(itemRects, containerWidth) {\n return getCenteredPositions(itemRects, containerWidth);\n }\n\n /**\n * Hides the elements that don't match our filter.\n * @param {ShuffleItem[]} collection Collection to shrink.\n * @private\n */\n _shrink(collection = this._getConcealedItems()) {\n let count = 0;\n collection.forEach((item) => {\n function callback() {\n item.applyCss(ShuffleItem.Css.HIDDEN.after);\n }\n\n // Continuing would add a transitionend event listener to the element, but\n // that listener would not execute because the transform and opacity would\n // stay the same.\n // The callback is executed here because it is not guaranteed to be called\n // after the transitionend event because the transitionend could be\n // canceled if another animation starts.\n if (item.isHidden) {\n item.applyCss(ShuffleItem.Css.HIDDEN.before);\n callback();\n return;\n }\n\n item.scale = ShuffleItem.Scale.HIDDEN;\n item.isHidden = true;\n\n const styles = this.getStylesForTransition(item, ShuffleItem.Css.HIDDEN.before);\n styles.transitionDelay = this._getStaggerAmount(count) + 'ms';\n\n this._queue.push({\n item,\n styles,\n callback,\n });\n\n count += 1;\n });\n }\n\n /**\n * Resize handler.\n * @private\n */\n _handleResize() {\n // If shuffle is disabled, destroyed, don't do anything\n if (!this.isEnabled || this.isDestroyed) {\n return;\n }\n\n this.update();\n }\n\n /**\n * Returns styles which will be applied to the an item for a transition.\n * @param {ShuffleItem} item Item to get styles for. Should have updated\n * scale and point properties.\n * @param {Object} styleObject Extra styles that will be used in the transition.\n * @return {!Object} Transforms for transitions, left/top for animate.\n * @protected\n */\n getStylesForTransition(item, styleObject) {\n // Clone the object to avoid mutating the original.\n const styles = Object.assign({}, styleObject);\n\n if (this.options.useTransforms) {\n styles.transform = `translate(${item.point.x}px, ${item.point.y}px) scale(${item.scale})`;\n } else {\n styles.left = item.point.x + 'px';\n styles.top = item.point.y + 'px';\n }\n\n return styles;\n }\n\n /**\n * Listen for the transition end on an element and execute the itemCallback\n * when it finishes.\n * @param {Element} element Element to listen on.\n * @param {function} itemCallback Callback for the item.\n * @param {function} done Callback to notify `parallel` that this one is done.\n */\n _whenTransitionDone(element, itemCallback, done) {\n const id = onTransitionEnd(element, (evt) => {\n itemCallback();\n done(null, evt);\n });\n\n this._transitions.push(id);\n }\n\n /**\n * Return a function which will set CSS styles and call the `done` function\n * when (if) the transition finishes.\n * @param {Object} opts Transition object.\n * @return {function} A function to be called with a `done` function.\n */\n _getTransitionFunction(opts) {\n return (done) => {\n opts.item.applyCss(opts.styles);\n this._whenTransitionDone(opts.item.element, opts.callback, done);\n };\n }\n\n /**\n * Execute the styles gathered in the style queue. This applies styles to elements,\n * triggering transitions.\n * @private\n */\n _processQueue() {\n if (this.isTransitioning) {\n this._cancelMovement();\n }\n\n const hasSpeed = this.options.speed > 0;\n const hasQueue = this._queue.length > 0;\n\n if (hasQueue && hasSpeed && this.isInitialized) {\n this._startTransitions(this._queue);\n } else if (hasQueue) {\n this._styleImmediately(this._queue);\n this._dispatch(Shuffle.EventType.LAYOUT);\n\n // A call to layout happened, but none of the newly visible items will\n // change position or the transition duration is zero, which will not trigger\n // the transitionend event.\n } else {\n this._dispatch(Shuffle.EventType.LAYOUT);\n }\n\n // Remove everything in the style queue\n this._queue.length = 0;\n }\n\n /**\n * Wait for each transition to finish, the emit the layout event.\n * @param {Object[]} transitions Array of transition objects.\n */\n _startTransitions(transitions) {\n // Set flag that shuffle is currently in motion.\n this.isTransitioning = true;\n\n // Create an array of functions to be called.\n const callbacks = transitions.map(obj => this._getTransitionFunction(obj));\n\n parallel(callbacks, this._movementFinished.bind(this));\n }\n\n _cancelMovement() {\n // Remove the transition end event for each listener.\n this._transitions.forEach(cancelTransitionEnd);\n\n // Reset the array.\n this._transitions.length = 0;\n\n // Show it's no longer active.\n this.isTransitioning = false;\n }\n\n /**\n * Apply styles without a transition.\n * @param {Object[]} objects Array of transition objects.\n * @private\n */\n _styleImmediately(objects) {\n if (objects.length) {\n const elements = objects.map(obj => obj.item.element);\n\n Shuffle._skipTransitions(elements, () => {\n objects.forEach((obj) => {\n obj.item.applyCss(obj.styles);\n obj.callback();\n });\n });\n }\n }\n\n _movementFinished() {\n this._transitions.length = 0;\n this.isTransitioning = false;\n this._dispatch(Shuffle.EventType.LAYOUT);\n }\n\n /**\n * The magic. This is what makes the plugin 'shuffle'\n * @param {string|string[]|function(Element):boolean} [category] Category to filter by.\n * Can be a function, string, or array of strings.\n * @param {Object} [sortObj] A sort object which can sort the visible set\n */\n filter(category, sortObj) {\n if (!this.isEnabled) {\n return;\n }\n\n if (!category || (category && category.length === 0)) {\n category = Shuffle.ALL_ITEMS; // eslint-disable-line no-param-reassign\n }\n\n this._filter(category);\n\n // Shrink each hidden item\n this._shrink();\n\n // How many visible elements?\n this._updateItemCount();\n\n // Update transforms on visible elements so they will animate to their new positions.\n this.sort(sortObj);\n }\n\n /**\n * Gets the visible elements, sorts them, and passes them to layout.\n * @param {Object} [sortOptions] The options object to pass to `sorter`.\n */\n sort(sortOptions = this.lastSort) {\n if (!this.isEnabled) {\n return;\n }\n\n this._resetCols();\n\n const items = sorter(this._getFilteredItems(), sortOptions);\n\n this._layout(items);\n\n // `_layout` always happens after `_shrink`, so it's safe to process the style\n // queue here with styles from the shrink method.\n this._processQueue();\n\n // Adjust the height of the container.\n this._setContainerSize();\n\n this.lastSort = sortOptions;\n }\n\n /**\n * Reposition everything.\n * @param {boolean} [isOnlyLayout=false] If true, column and gutter widths won't be recalculated.\n */\n update(isOnlyLayout = false) {\n if (this.isEnabled) {\n if (!isOnlyLayout) {\n // Get updated colCount\n this._setColumns();\n }\n\n // Layout items\n this.sort();\n }\n }\n\n /**\n * Use this instead of `update()` if you don't need the columns and gutters updated\n * Maybe an image inside `shuffle` loaded (and now has a height), which means calculations\n * could be off.\n */\n layout() {\n this.update(true);\n }\n\n /**\n * New items have been appended to shuffle. Mix them in with the current\n * filter or sort status.\n * @param {Element[]} newItems Collection of new items.\n */\n add(newItems) {\n const items = arrayUnique(newItems).map(el => new ShuffleItem(el));\n\n // Add classes and set initial positions.\n this._initItems(items);\n\n // Determine which items will go with the current filter.\n this._resetCols();\n const newItemSet = this._filter(this.lastFilter, items);\n const willBeVisible = this._mergeNewItems(newItemSet.visible);\n const sortedVisibleItems = sorter(willBeVisible, this.lastSort);\n\n // Layout all items again so that new items get positions.\n // Synchonously apply positions.\n const itemPositions = this._getNextPositions(sortedVisibleItems);\n sortedVisibleItems.forEach((item, i) => {\n if (newItemSet.visible.includes(item)) {\n item.point = itemPositions[i];\n item.scale = ShuffleItem.Scale.HIDDEN;\n item.isHidden = true;\n item.applyCss(ShuffleItem.Css.HIDDEN.before);\n item.applyCss(ShuffleItem.Css.HIDDEN.after);\n item.applyCss(this.getStylesForTransition(item, {}));\n }\n });\n\n // Cause layout so that the styles above are applied.\n this.element.offsetWidth; // eslint-disable-line no-unused-expressions\n\n // Add transition to each item.\n this.setItemTransitions(items);\n\n // Update the list of items.\n this.items = this._mergeNewItems(items);\n\n // Update layout/visibility of new and old items.\n this.filter(this.lastFilter);\n }\n\n /**\n * Disables shuffle from updating dimensions and layout on resize\n */\n disable() {\n this.isEnabled = false;\n }\n\n /**\n * Enables shuffle again\n * @param {boolean} [isUpdateLayout=true] if undefined, shuffle will update columns and gutters\n */\n enable(isUpdateLayout = true) {\n this.isEnabled = true;\n if (isUpdateLayout) {\n this.update();\n }\n }\n\n /**\n * Remove 1 or more shuffle items.\n * @param {Element[]} elements An array containing one or more\n * elements in shuffle\n * @return {Shuffle} The shuffle instance.\n */\n remove(elements) {\n if (!elements.length) {\n return;\n }\n\n const collection = arrayUnique(elements);\n\n const oldItems = collection\n .map(element => this.getItemByElement(element))\n .filter(item => !!item);\n\n const handleLayout = () => {\n this._disposeItems(oldItems);\n\n // Remove the collection in the callback\n collection.forEach((element) => {\n element.parentNode.removeChild(element);\n });\n\n this._dispatch(Shuffle.EventType.REMOVED, { collection });\n };\n\n // Hide collection first.\n this._toggleFilterClasses({\n visible: [],\n hidden: oldItems,\n });\n\n this._shrink(oldItems);\n\n this.sort();\n\n // Update the list of items here because `remove` could be called again\n // with an item that is in the process of being removed.\n this.items = this.items.filter(item => !oldItems.includes(item));\n this._updateItemCount();\n\n this.once(Shuffle.EventType.LAYOUT, handleLayout);\n }\n\n /**\n * Retrieve a shuffle item by its element.\n * @param {Element} element Element to look for.\n * @return {?ShuffleItem} A shuffle item or undefined if it's not found.\n */\n getItemByElement(element) {\n return this.items.find(item => item.element === element);\n }\n\n /**\n * Dump the elements currently stored and reinitialize all child elements which\n * match the `itemSelector`.\n */\n resetItems() {\n // Remove refs to current items.\n this._disposeItems(this.items);\n this.isInitialized = false;\n\n // Find new items in the DOM.\n this.items = this._getItems();\n\n // Set initial styles on the new items.\n this._initItems(this.items);\n\n this.once(Shuffle.EventType.LAYOUT, () => {\n // Add transition to each item.\n this.setItemTransitions(this.items);\n this.isInitialized = true;\n });\n\n // Lay out all items.\n this.filter(this.lastFilter);\n }\n\n /**\n * Destroys shuffle, removes events, styles, and classes\n */\n destroy() {\n this._cancelMovement();\n window.removeEventListener('resize', this._onResize);\n\n // Reset container styles\n this.element.classList.remove('shuffle');\n this.element.removeAttribute('style');\n\n // Reset individual item styles\n this._disposeItems(this.items);\n\n this.items.length = 0;\n this._transitions.length = 0;\n\n // Null DOM references\n this.options.sizer = null;\n this.element = null;\n\n // Set a flag so if a debounced resize has been triggered,\n // it can first check if it is actually isDestroyed and not doing anything\n this.isDestroyed = true;\n this.isEnabled = false;\n }\n\n /**\n * Returns the outer width of an element, optionally including its margins.\n *\n * There are a few different methods for getting the width of an element, none of\n * which work perfectly for all Shuffle's use cases.\n *\n * 1. getBoundingClientRect() `left` and `right` properties.\n * - Accounts for transform scaled elements, making it useless for Shuffle\n * elements which have shrunk.\n * 2. The `offsetWidth` property.\n * - This value stays the same regardless of the elements transform property,\n * however, it does not return subpixel values.\n * 3. getComputedStyle()\n * - This works great Chrome, Firefox, Safari, but IE<=11 does not include\n * padding and border when box-sizing: border-box is set, requiring a feature\n * test and extra work to add the padding back for IE and other browsers which\n * follow the W3C spec here.\n *\n * @param {Element} element The element.\n * @param {boolean} [includeMargins=false] Whether to include margins.\n * @return {{width: number, height: number}} The width and height.\n */\n static getSize(element, includeMargins = false) {\n // Store the styles so that they can be used by others without asking for it again.\n const styles = window.getComputedStyle(element, null);\n let width = getNumberStyle(element, 'width', styles);\n let height = getNumberStyle(element, 'height', styles);\n\n if (includeMargins) {\n const marginLeft = getNumberStyle(element, 'marginLeft', styles);\n const marginRight = getNumberStyle(element, 'marginRight', styles);\n const marginTop = getNumberStyle(element, 'marginTop', styles);\n const marginBottom = getNumberStyle(element, 'marginBottom', styles);\n width += marginLeft + marginRight;\n height += marginTop + marginBottom;\n }\n\n return {\n width,\n height,\n };\n }\n\n /**\n * Change a property or execute a function which will not have a transition\n * @param {Element[]} elements DOM elements that won't be transitioned.\n * @param {function} callback A function which will be called while transition\n * is set to 0ms.\n * @private\n */\n static _skipTransitions(elements, callback) {\n const zero = '0ms';\n\n // Save current duration and delay.\n const data = elements.map((element) => {\n const style = element.style;\n const duration = style.transitionDuration;\n const delay = style.transitionDelay;\n\n // Set the duration to zero so it happens immediately\n style.transitionDuration = zero;\n style.transitionDelay = zero;\n\n return {\n duration,\n delay,\n };\n });\n\n callback();\n\n // Cause forced synchronous layout.\n elements[0].offsetWidth; // eslint-disable-line no-unused-expressions\n\n // Put the duration back\n elements.forEach((element, i) => {\n element.style.transitionDuration = data[i].duration;\n element.style.transitionDelay = data[i].delay;\n });\n }\n}\n\nShuffle.ShuffleItem = ShuffleItem;\n\nShuffle.ALL_ITEMS = 'all';\nShuffle.FILTER_ATTRIBUTE_KEY = 'groups';\n\n/** @enum {string} */\nShuffle.EventType = {\n LAYOUT: 'shuffle:layout',\n REMOVED: 'shuffle:removed',\n};\n\n/** @enum {string} */\nShuffle.Classes = Classes;\n\n/** @enum {string} */\nShuffle.FilterMode = {\n ANY: 'any',\n ALL: 'all',\n};\n\n// Overrideable options\nShuffle.options = {\n // Initial filter group.\n group: Shuffle.ALL_ITEMS,\n\n // Transition/animation speed (milliseconds).\n speed: 250,\n\n // CSS easing function to use.\n easing: 'cubic-bezier(0.4, 0.0, 0.2, 1)',\n\n // e.g. '.picture-item'.\n itemSelector: '*',\n\n // Element or selector string. Use an element to determine the size of columns\n // and gutters.\n sizer: null,\n\n // A static number or function that tells the plugin how wide the gutters\n // between columns are (in pixels).\n gutterWidth: 0,\n\n // A static number or function that returns a number which tells the plugin\n // how wide the columns are (in pixels).\n columnWidth: 0,\n\n // If your group is not json, and is comma delimeted, you could set delimeter\n // to ','.\n delimeter: null,\n\n // Useful for percentage based heights when they might not always be exactly\n // the same (in pixels).\n buffer: 0,\n\n // Reading the width of elements isn't precise enough and can cause columns to\n // jump between values.\n columnThreshold: 0.01,\n\n // Shuffle can be isInitialized with a sort object. It is the same object\n // given to the sort method.\n initialSort: null,\n\n // By default, shuffle will throttle resize events. This can be changed or\n // removed.\n throttle,\n\n // How often shuffle can be called on resize (in milliseconds).\n throttleTime: 300,\n\n // Transition delay offset for each item in milliseconds.\n staggerAmount: 15,\n\n // Maximum stagger delay in milliseconds.\n staggerAmountMax: 150,\n\n // Whether to use transforms or absolute positioning.\n useTransforms: true,\n\n // Affects using an array with filter. e.g. `filter(['one', 'two'])`. With \"any\",\n // the element passes the test if any of its groups are in the array. With \"all\",\n // the element only passes if all groups are in the array.\n filterMode: Shuffle.FilterMode.ANY,\n\n // Attempt to center grid items in each row.\n isCentered: false,\n};\n\nShuffle.Point = Point;\nShuffle.Rect = Rect;\n\n// Expose for testing. Hack at your own risk.\nShuffle.__sorter = sorter;\nShuffle.__getColumnSpan = getColumnSpan;\nShuffle.__getAvailablePositions = getAvailablePositions;\nShuffle.__getShortColumn = getShortColumn;\nShuffle.__getCenteredPositions = getCenteredPositions;\n\nexport default Shuffle;\n"],"names":["getNumber","value","parseFloat","Point","x","y","a","b","Rect","w","h","id","left","top","width","height","ShuffleItem","element","isVisible","isHidden","classList","remove","Classes","HIDDEN","add","VISIBLE","removeAttribute","setAttribute","addClasses","SHUFFLE_ITEM","applyCss","Css","INITIAL","scale","Scale","point","classes","forEach","className","obj","keys","key","style","removeClasses","document","body","documentElement","e","createElement","cssText","appendChild","window","getComputedStyle","ret","removeChild","getNumberStyle","styles","COMPUTED_SIZE_INCLUDES_PADDING","paddingLeft","paddingRight","borderLeftWidth","borderRightWidth","paddingTop","paddingBottom","borderTopWidth","borderBottomWidth","randomize","array","n","length","i","Math","floor","random","temp","defaults","sorter","arr","options","opts","Object","assign","original","Array","from","revert","by","sort","valA","valB","undefined","reverse","transitions","eventName","count","uniqueId","cancelTransitionEnd","removeEventListener","listener","onTransitionEnd","callback","evt","currentTarget","target","addEventListener","arrayMax","max","apply","arrayMin","min","getColumnSpan","itemWidth","columnWidth","columns","threshold","columnSpan","abs","round","ceil","getAvailablePositions","positions","available","push","slice","getShortColumn","buffer","minPosition","len","getItemPosition","itemSize","gridSize","total","span","setY","shortColumnIndex","setHeight","getCenteredPositions","itemRects","containerWidth","rowMap","itemRect","rects","rows","centeredRows","lastItem","end","offset","finalRects","canMove","newRects","every","r","newRect","noOverlap","some","intersects","intersectingRect","hasOverlap","rowIndex","findIndex","items","includes","splice","concat","map","hyphenate","str","replace","m1","toLowerCase","arrayUnique","Set","Shuffle","lastSort","group","ALL_ITEMS","lastFilter","isEnabled","isDestroyed","isInitialized","_transitions","isTransitioning","_queue","el","_getElementOption","TypeError","_init","_getItems","sizer","BASE","_initItems","_onResize","_getResizeFunction","readyState","layout","bind","onLoad","containerCss","getSize","_validateStyles","_setColumns","filter","initialSort","offsetWidth","setItemTransitions","transition","speed","easing","resizeFunction","_handleResize","throttle","throttleTime","option","querySelector","nodeType","jquery","position","overflow","category","collection","set","_getFilteredSets","_toggleFilterClasses","visible","hidden","item","_doesPassFilter","call","attr","getAttribute","FILTER_ATTRIBUTE_KEY","delimeter","split","JSON","parse","testCategory","isArray","filterMode","FilterMode","ANY","show","hide","init","dispose","visibleItems","_getFilteredItems","positionProps","useTransforms","properties","before","k","join","transitionDuration","transitionTimingFunction","transitionProperty","children","matches","itemSelector","indexOf","gutterSize","size","gutterWidth","gutter","_getGutterSize","_getColumnSize","calculatedColumns","columnThreshold","cols","colWidth","_getContainerSize","index","staggerAmount","staggerAmountMax","name","data","shuffle","emit","itemPositions","_getNextPositions","after","equals","getStylesForTransition","transitionDelay","_getStaggerAmount","isCentered","itemsData","_getItemPosition","getTransformedPositions","_getConcealedItems","update","styleObject","transform","itemCallback","done","_whenTransitionDone","_cancelMovement","hasSpeed","hasQueue","_startTransitions","_styleImmediately","_dispatch","EventType","LAYOUT","callbacks","_getTransitionFunction","_movementFinished","objects","elements","_skipTransitions","sortObj","_filter","_shrink","_updateItemCount","sortOptions","_resetCols","_layout","_processQueue","_setContainerSize","isOnlyLayout","newItems","newItemSet","willBeVisible","_mergeNewItems","sortedVisibleItems","isUpdateLayout","oldItems","getItemByElement","handleLayout","_disposeItems","parentNode","REMOVED","once","find","includeMargins","marginLeft","marginRight","marginTop","marginBottom","zero","duration","delay","TinyEmitter","__sorter","__getColumnSpan","__getAvailablePositions","__getShortColumn","__getCenteredPositions"],"mappings":"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"} \ No newline at end of file diff --git a/dist/shuffle.min.js b/dist/shuffle.min.js index 9bbba5f..0e60474 100644 --- a/dist/shuffle.min.js +++ b/dist/shuffle.min.js @@ -1,2 +1,2 @@ -!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):t.shuffle=e()}(this,function(){"use strict";function t(t,e){if(b)return b.call(t,e);for(var i=t.parentNode.querySelectorAll(e),n=0;n=e?i():r=setTimeout(i,e-t)),o}}function n(){}function s(t){return parseFloat(t)||0}function o(t,e){var i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:window.getComputedStyle(t,null),n=s(i[e]);return N||"width"!==e?N||"height"!==e||(n+=s(i.paddingTop)+s(i.paddingBottom)+s(i.borderTopWidth)+s(i.borderBottomWidth)):n+=s(i.paddingLeft)+s(i.paddingRight)+s(i.borderLeftWidth)+s(i.borderRightWidth),n}function r(t){for(var e=t.length;e;){e-=1;var i=Math.floor(Math.random()*(e+1)),n=t[i];t[i]=t[e],t[e]=n}return t}function l(t,e){var i=w(W,e),n=[].slice.call(t),s=!1;return t.length?i.randomize?r(t):("function"==typeof i.by&&t.sort(function(t,e){if(s)return 0;var n=i.by(t[i.key]),o=i.by(e[i.key]);return void 0===n&&void 0===o?(s=!0,0):no||"sortLast"===n||"sortFirst"===o?1:0}),s?n:(i.reverse&&t.reverse(),t)):[]}function a(){return q+=1,H+q}function u(t){return!!R[t]&&(R[t].element.removeEventListener(H,R[t].listener),R[t]=null,!0)}function h(t,e){var i=a(),n=function(t){t.currentTarget===t.target&&(u(i),e(t))};return t.addEventListener(H,n),R[i]={element:t,listener:n},i}function f(t){return Math.max.apply(Math,t)}function c(t){return Math.min.apply(Math,t)}function d(t,e,i,n){var s=t/e;return Math.abs(Math.round(s)-s)=i-e&&t[n]<=i+e)return n;return 0}function v(t){for(var e=t.itemSize,i=t.positions,n=t.gridSize,s=t.total,o=t.threshold,r=t.buffer,l=d(e.width,n,s,o),a=m(i,l,s),u=p(a,r),h=new A(Math.round(n*u),Math.round(a[u])),f=a[u]+e.height,c=0;c-1}try{var _=new window.CustomEvent("test");if(_.preventDefault(),!0!==_.defaultPrevented)throw new Error("Could not prevent default")}catch(t){var E=function(t,e){var i,n;return e=e||{bubbles:!1,cancelable:!1,detail:void 0},(i=document.createEvent("CustomEvent")).initCustomEvent(t,e.bubbles,e.cancelable,e.detail),n=i.preventDefault,i.preventDefault=function(){n.call(this);try{Object.defineProperty(this,"defaultPrevented",{get:function(){return!0}})}catch(t){this.defaultPrevented=!0}},i};E.prototype=window.Event.prototype,window.CustomEvent=E}var S=Element.prototype,b=S.matches||S.matchesSelector||S.webkitMatchesSelector||S.mozMatchesSelector||S.msMatchesSelector||S.oMatchesSelector,I=t,k="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{},T=function(t,e){return e={exports:{}},t(e,e.exports),e.exports}(function(t){function e(t){for(var e=[],i=0;i1&&void 0!==arguments[1]?arguments[1]:{};D(this,t),this.options=w(t.options,i),this.useSizer=!1,this.lastSort={},this.group=t.ALL_ITEMS,this.lastFilter=t.ALL_ITEMS,this.isEnabled=!0,this.isDestroyed=!1,this.isInitialized=!1,this._transitions=[],this.isTransitioning=!1,this._queue=[];var n=this._getElementOption(e);if(!n)throw new TypeError("Shuffle needs to be initialized with an element.");this.element=n,this.id="shuffle_"+P,P+=1,this._init(),this.isInitialized=!0}return M(t,[{key:"_init",value:function(){this.items=this._getItems(),this.options.sizer=this._getElementOption(this.options.sizer),this.options.sizer&&(this.useSizer=!0),this.element.classList.add(t.Classes.BASE),this._initItems(),this._onResize=this._getResizeFunction(),window.addEventListener("resize",this._onResize);var e=window.getComputedStyle(this.element,null),i=t.getSize(this.element).width;this._validateStyles(e),this._setColumns(i),this.filter(this.options.group,this.options.initialSort),this.element.offsetWidth,this._setTransitions(),this.element.style.transition="height "+this.options.speed+"ms "+this.options.easing}},{key:"_getResizeFunction",value:function(){var t=this._handleResize.bind(this);return this.options.throttle?this.options.throttle(t,this.options.throttleTime):t}},{key:"_getElementOption",value:function(t){return"string"==typeof t?this.element.querySelector(t):t&&t.nodeType&&1===t.nodeType?t:t&&t.jquery?t[0]:null}},{key:"_validateStyles",value:function(t){"static"===t.position&&(this.element.style.position="relative"),"hidden"!==t.overflow&&(this.element.style.overflow="hidden")}},{key:"_filter",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.lastFilter,e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:this.items,i=this._getFilteredSets(t,e);return this._toggleFilterClasses(i),this.lastFilter=t,"string"==typeof t&&(this.group=t),i}},{key:"_getFilteredSets",value:function(e,i){var n=this,s=[],o=[];return e===t.ALL_ITEMS?s=i:i.forEach(function(t){n._doesPassFilter(e,t.element)?s.push(t):o.push(t)}),{visible:s,hidden:o}}},{key:"_doesPassFilter",value:function(e,i){function n(t){return g(o,t)}if("function"==typeof e)return e.call(i,i,this);var s=i.getAttribute("data-"+t.FILTER_ATTRIBUTE_KEY),o=this.options.delimeter?s.split(this.options.delimeter):JSON.parse(s);return Array.isArray(e)?this.options.filterMode===t.FilterMode.ANY?e.some(n):e.every(n):g(o,e)}},{key:"_toggleFilterClasses",value:function(t){var e=t.visible,i=t.hidden;e.forEach(function(t){t.show()}),i.forEach(function(t){t.hide()})}},{key:"_initItems",value:function(){(arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.items).forEach(function(t){t.init()})}},{key:"_disposeItems",value:function(){(arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.items).forEach(function(t){t.dispose()})}},{key:"_updateItemCount",value:function(){this.visibleItems=this._getFilteredItems().length}},{key:"_setTransitions",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.items,e=this.options.speed,i=this.options.easing,n=this.options.useTransforms?"transform "+e+"ms "+i+", opacity "+e+"ms "+i:"top "+e+"ms "+i+", left "+e+"ms "+i+", opacity "+e+"ms "+i;t.forEach(function(t){t.element.style.transition=n})}},{key:"_getItems",value:function(){var t=this;return y(this.element.children).filter(function(e){return I(e,t.options.itemSelector)}).map(function(t){return new B(t)})}},{key:"_updateItemsOrder",value:function(){var t=this.element.children;this.items=l(this.items,{by:function(e){return Array.prototype.indexOf.call(t,e)}})}},{key:"_getFilteredItems",value:function(){return this.items.filter(function(t){return t.isVisible})}},{key:"_getConcealedItems",value:function(){return this.items.filter(function(t){return!t.isVisible})}},{key:"_getColumnSize",value:function(e,i){var n=void 0;return 0===(n="function"==typeof this.options.columnWidth?this.options.columnWidth(e):this.useSizer?t.getSize(this.options.sizer).width:this.options.columnWidth?this.options.columnWidth:this.items.length>0?t.getSize(this.items[0].element,!0).width:e)&&(n=e),n+i}},{key:"_getGutterSize",value:function(t){return"function"==typeof this.options.gutterWidth?this.options.gutterWidth(t):this.useSizer?o(this.options.sizer,"marginLeft"):this.options.gutterWidth}},{key:"_setColumns",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:t.getSize(this.element).width,i=this._getGutterSize(e),n=this._getColumnSize(e,i),s=(e+i)/n;Math.abs(Math.round(s)-s)1&&void 0!==arguments[1]?arguments[1]:{};return!this.isDestroyed&&(e.shuffle=this,!this.element.dispatchEvent(new CustomEvent(t,{bubbles:!0,cancelable:!1,detail:e})))}},{key:"_resetCols",value:function(){var t=this.cols;for(this.positions=[];t;)t-=1,this.positions.push(0)}},{key:"_layout",value:function(e){var i=this,n=0;e.forEach(function(e){function s(){e.element.style.transitionDelay="",e.applyCss(B.Css.VISIBLE.after)}var o=e.point,r=e.scale,l=t.getSize(e.element,!0),a=i._getItemPosition(l);if(A.equals(o,a)&&r===B.Scale.VISIBLE)return e.applyCss(B.Css.VISIBLE.before),void s();e.point=a,e.scale=B.Scale.VISIBLE;var u=w(B.Css.VISIBLE.before);u.transitionDelay=i._getStaggerAmount(n)+"ms",i._queue.push({item:e,styles:u,callback:s}),n+=1})}},{key:"_getItemPosition",value:function(t){return v({itemSize:t,positions:this.positions,gridSize:this.colWidth,total:this.cols,threshold:this.options.columnThreshold,buffer:this.options.buffer})}},{key:"_shrink",value:function(){var t=this,e=0;(arguments.length>0&&void 0!==arguments[0]?arguments[0]:this._getConcealedItems()).forEach(function(i){function n(){i.applyCss(B.Css.HIDDEN.after)}if(i.scale===B.Scale.HIDDEN)return i.applyCss(B.Css.HIDDEN.before),void n();i.scale=B.Scale.HIDDEN;var s=w(B.Css.HIDDEN.before);s.transitionDelay=t._getStaggerAmount(e)+"ms",t._queue.push({item:i,styles:s,callback:n}),e+=1})}},{key:"_handleResize",value:function(){this.isEnabled&&!this.isDestroyed&&t.getSize(this.element).width!==this.containerWidth&&this.update()}},{key:"_getStylesForTransition",value:function(t){var e=t.item,i=t.styles;i.transitionDelay||(i.transitionDelay="0ms");var n=e.point.x,s=e.point.y;return this.options.useTransforms?i.transform="translate("+n+"px, "+s+"px) scale("+e.scale+")":(i.left=n+"px",i.top=s+"px"),i}},{key:"_whenTransitionDone",value:function(t,e,i){var n=h(t,function(t){e(),i(null,t)});this._transitions.push(n)}},{key:"_getTransitionFunction",value:function(t){var e=this;return function(i){t.item.applyCss(e._getStylesForTransition(t)),e._whenTransitionDone(t.item.element,t.callback,i)}}},{key:"_processQueue",value:function(){this.isTransitioning&&this._cancelMovement();var t=this.options.speed>0,e=this._queue.length>0;e&&t&&this.isInitialized?this._startTransitions(this._queue):e?(this._styleImmediately(this._queue),this._dispatchLayout()):this._dispatchLayout(),this._queue.length=0}},{key:"_startTransitions",value:function(t){var e=this;this.isTransitioning=!0;var i=t.map(function(t){return e._getTransitionFunction(t)});z(i,this._movementFinished.bind(this))}},{key:"_cancelMovement",value:function(){this._transitions.forEach(u),this._transitions.length=0,this.isTransitioning=!1}},{key:"_styleImmediately",value:function(e){var i=this;if(e.length){var n=e.map(function(t){return t.item.element});t._skipTransitions(n,function(){e.forEach(function(t){t.item.applyCss(i._getStylesForTransition(t)),t.callback()})})}}},{key:"_movementFinished",value:function(){this._transitions.length=0,this.isTransitioning=!1,this._dispatchLayout()}},{key:"_dispatchLayout",value:function(){this._dispatch(t.EventType.LAYOUT)}},{key:"filter",value:function(e,i){this.isEnabled&&((!e||e&&0===e.length)&&(e=t.ALL_ITEMS),this._filter(e),this._shrink(),this._updateItemCount(),this.sort(i))}},{key:"sort",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.lastSort;if(this.isEnabled){this._resetCols();var e=this._getFilteredItems();e=l(e,t),this._layout(e),this._processQueue(),this._setContainerSize(),this.lastSort=t}}},{key:"update",value:function(t){this.isEnabled&&(t||this._setColumns(),this.sort())}},{key:"layout",value:function(){this.update(!0)}},{key:"add",value:function(t){var e=T(t).map(function(t){return new B(t)});this._initItems(e),this._setTransitions(e),this.items=this.items.concat(e),this._updateItemsOrder(),this.filter(this.lastFilter)}},{key:"disable",value:function(){this.isEnabled=!1}},{key:"enable",value:function(t){this.isEnabled=!0,!1!==t&&this.update()}},{key:"remove",value:function(e){var i=this;if(e.length){var n=T(e),s=n.map(function(t){return i.getItemByElement(t)}).filter(function(t){return!!t}),o=function e(){i.element.removeEventListener(t.EventType.LAYOUT,e),i._disposeItems(s),n.forEach(function(t){t.parentNode.removeChild(t)}),i._dispatch(t.EventType.REMOVED,{collection:n})};this._toggleFilterClasses({visible:[],hidden:s}),this._shrink(s),this.sort(),this.items=this.items.filter(function(t){return!g(s,t)}),this._updateItemCount(),this.element.addEventListener(t.EventType.LAYOUT,o)}}},{key:"getItemByElement",value:function(t){for(var e=this.items.length-1;e>=0;e--)if(this.items[e].element===t)return this.items[e];return null}},{key:"destroy",value:function(){this._cancelMovement(),window.removeEventListener("resize",this._onResize),this.element.classList.remove("shuffle"),this.element.removeAttribute("style"),this._disposeItems(),this.items=null,this.options.sizer=null,this.element=null,this._transitions=null,this.isDestroyed=!0}}],[{key:"getSize",value:function(t,e){var i=window.getComputedStyle(t,null),n=o(t,"width",i),s=o(t,"height",i);return e&&(n+=o(t,"marginLeft",i)+o(t,"marginRight",i),s+=o(t,"marginTop",i)+o(t,"marginBottom",i)),{width:n,height:s}}},{key:"_skipTransitions",value:function(t,e){var i=t.map(function(t){var e=t.style,i=e.transitionDuration,n=e.transitionDelay;return e.transitionDuration="0ms",e.transitionDelay="0ms",{duration:i,delay:n}});e(),t[0].offsetWidth,t.forEach(function(t,e){t.style.transitionDuration=i[e].duration,t.style.transitionDelay=i[e].delay})}}]),t}();return U.ShuffleItem=B,U.ALL_ITEMS="all",U.FILTER_ATTRIBUTE_KEY="groups",U.EventType={LAYOUT:"shuffle:layout",REMOVED:"shuffle:removed"},U.Classes=F,U.FilterMode={ANY:"any",ALL:"all"},U.options={group:U.ALL_ITEMS,speed:250,easing:"ease",itemSelector:"*",sizer:null,gutterWidth:0,columnWidth:0,delimeter:null,buffer:0,columnThreshold:.01,initialSort:null,throttle:C,throttleTime:300,staggerAmount:15,staggerAmountMax:250,useTransforms:!0,filterMode:U.FilterMode.ANY},U.__Point=A,U.__sorter=l,U.__getColumnSpan=d,U.__getAvailablePositions=m,U.__getShortColumn=p,U}); +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):t.Shuffle=e()}(this,function(){"use strict";function t(){}function e(){}function i(t){return parseFloat(t)||0}function n(t,e){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:window.getComputedStyle(t,null),s=i(n[e]);return x||"width"!==e?x||"height"!==e||(s+=i(n.paddingTop)+i(n.paddingBottom)+i(n.borderTopWidth)+i(n.borderBottomWidth)):s+=i(n.paddingLeft)+i(n.paddingRight)+i(n.borderLeftWidth)+i(n.borderRightWidth),s}function s(t){for(var e=t.length;e;){e-=1;var i=Math.floor(Math.random()*(e+1)),n=t[i];t[i]=t[e],t[e]=n}return t}function o(t,e){var i=Object.assign({},N,e),n=Array.from(t),o=!1;return t.length?i.randomize?s(t):("function"==typeof i.by&&t.sort(function(t,e){if(o)return 0;var n=i.by(t[i.key]),s=i.by(e[i.key]);return void 0===n&&void 0===s?(o=!0,0):ns||"sortLast"===n||"sortFirst"===s?1:0}),o?n:(i.reverse&&t.reverse(),t)):[]}function r(){return B+=1,H+B}function l(t){return!!O[t]&&(O[t].element.removeEventListener(H,O[t].listener),O[t]=null,!0)}function a(t,e){var i=r(),n=function(t){t.currentTarget===t.target&&(l(i),e(t))};return t.addEventListener(H,n),O[i]={element:t,listener:n},i}function u(t){return Math.max.apply(Math,t)}function h(t){return Math.min.apply(Math,t)}function f(t,e,i,n){var s=t/e;return Math.abs(Math.round(s)-s)=i-e&&t[n]<=i+e)return n;return 0}function m(t){for(var e=t.itemSize,i=t.positions,n=t.gridSize,s=t.total,o=t.threshold,r=t.buffer,l=f(e.width,n,s,o),a=c(i,l,s),u=d(a,r),h=new C(n*u,a[u]),m=a[u]+e.height,p=0;p0){var c=[];(f=r.every(function(t){var e=new L(t.left+u,t.top,t.width,t.height,t.id),i=!n.some(function(t){return L.intersects(e,t)});return c.push(e),i}))&&(h=c)}if(!f){var d=void 0;if(r.some(function(t){return n.some(function(e){var i=L.intersects(t,e);return i&&(d=e),i})})){var m=o.findIndex(function(t){return t.includes(d)});o.splice(m,1,s[m])}}n=n.concat(h),o.push(h)}),[].concat.apply([],o).sort(function(t,e){return t.id-e.id}).map(function(t){return new C(t.left,t.top)})}function v(t){return t.replace(/([A-Z])/g,function(t,e){return"-"+e.toLowerCase()})}function y(t){return Array.from(new Set(t))}t.prototype={on:function(t,e,i){var n=this.e||(this.e={});return(n[t]||(n[t]=[])).push({fn:e,ctx:i}),this},once:function(t,e,i){function n(){s.off(t,n),e.apply(i,arguments)}var s=this;return n._=e,this.on(t,n,i)},emit:function(t){var e=[].slice.call(arguments,1),i=((this.e||(this.e={}))[t]||[]).slice(),n=0,s=i.length;for(n;n1&&void 0!==arguments[1]?arguments[1]:{};S(this,e);var n=w(this,(e.__proto__||Object.getPrototypeOf(e)).call(this));n.options=Object.assign({},e.options,i),n.lastSort={},n.group=e.ALL_ITEMS,n.lastFilter=e.ALL_ITEMS,n.isEnabled=!0,n.isDestroyed=!1,n.isInitialized=!1,n._transitions=[],n.isTransitioning=!1,n._queue=[];var s=n._getElementOption(t);if(!s)throw new TypeError("Shuffle needs to be initialized with an element.");return n.element=s,n.id="shuffle_"+W,W+=1,n._init(),n.isInitialized=!0,n}return T(e,g),k(e,[{key:"_init",value:function(){if(this.items=this._getItems(),this.options.sizer=this._getElementOption(this.options.sizer),this.element.classList.add(e.Classes.BASE),this._initItems(this.items),this._onResize=this._getResizeFunction(),window.addEventListener("resize",this._onResize),"complete"!==document.readyState){var t=this.layout.bind(this);window.addEventListener("load",function e(){window.removeEventListener("load",e),t()})}var i=window.getComputedStyle(this.element,null),n=e.getSize(this.element).width;this._validateStyles(i),this._setColumns(n),this.filter(this.options.group,this.options.initialSort),this.element.offsetWidth,this.setItemTransitions(this.items),this.element.style.transition="height "+this.options.speed+"ms "+this.options.easing}},{key:"_getResizeFunction",value:function(){var t=this._handleResize.bind(this);return this.options.throttle?this.options.throttle(t,this.options.throttleTime):t}},{key:"_getElementOption",value:function(t){return"string"==typeof t?this.element.querySelector(t):t&&t.nodeType&&1===t.nodeType?t:t&&t.jquery?t[0]:null}},{key:"_validateStyles",value:function(t){"static"===t.position&&(this.element.style.position="relative"),"hidden"!==t.overflow&&(this.element.style.overflow="hidden")}},{key:"_filter",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.lastFilter,e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:this.items,i=this._getFilteredSets(t,e);return this._toggleFilterClasses(i),this.lastFilter=t,"string"==typeof t&&(this.group=t),i}},{key:"_getFilteredSets",value:function(t,i){var n=this,s=[],o=[];return t===e.ALL_ITEMS?s=i:i.forEach(function(e){n._doesPassFilter(t,e.element)?s.push(e):o.push(e)}),{visible:s,hidden:o}}},{key:"_doesPassFilter",value:function(t,i){function n(t){return o.includes(t)}if("function"==typeof t)return t.call(i,i,this);var s=i.getAttribute("data-"+e.FILTER_ATTRIBUTE_KEY),o=this.options.delimeter?s.split(this.options.delimeter):JSON.parse(s);return Array.isArray(t)?this.options.filterMode===e.FilterMode.ANY?t.some(n):t.every(n):o.includes(t)}},{key:"_toggleFilterClasses",value:function(t){var e=t.visible,i=t.hidden;e.forEach(function(t){t.show()}),i.forEach(function(t){t.hide()})}},{key:"_initItems",value:function(t){t.forEach(function(t){t.init()})}},{key:"_disposeItems",value:function(t){t.forEach(function(t){t.dispose()})}},{key:"_updateItemCount",value:function(){this.visibleItems=this._getFilteredItems().length}},{key:"setItemTransitions",value:function(t){var e=this.options.speed,i=this.options.easing,n=(this.options.useTransforms?["transform"]:["top","left"]).concat(Object.keys(A.Css.HIDDEN.before).map(function(t){return v(t)})).join();t.forEach(function(t){t.element.style.transitionDuration=e+"ms",t.element.style.transitionTimingFunction=i,t.element.style.transitionProperty=n})}},{key:"_getItems",value:function(){var t=this;return Array.from(this.element.children).filter(function(e){return I(e,t.options.itemSelector)}).map(function(t){return new A(t)})}},{key:"_mergeNewItems",value:function(t){var e=Array.from(this.element.children);return o(this.items.concat(t),{by:function(t){return e.indexOf(t)}})}},{key:"_getFilteredItems",value:function(){return this.items.filter(function(t){return t.isVisible})}},{key:"_getConcealedItems",value:function(){return this.items.filter(function(t){return!t.isVisible})}},{key:"_getColumnSize",value:function(t,i){var n=void 0;return 0===(n="function"==typeof this.options.columnWidth?this.options.columnWidth(t):this.options.sizer?e.getSize(this.options.sizer).width:this.options.columnWidth?this.options.columnWidth:this.items.length>0?e.getSize(this.items[0].element,!0).width:t)&&(n=t),n+i}},{key:"_getGutterSize",value:function(t){return"function"==typeof this.options.gutterWidth?this.options.gutterWidth(t):this.options.sizer?n(this.options.sizer,"marginLeft"):this.options.gutterWidth}},{key:"_setColumns",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:e.getSize(this.element).width,i=this._getGutterSize(t),n=this._getColumnSize(t,i),s=(t+i)/n;Math.abs(Math.round(s)-s)1&&void 0!==arguments[1]?arguments[1]:{};this.isDestroyed||(e.shuffle=this,this.emit(t,e))}},{key:"_resetCols",value:function(){var t=this.cols;for(this.positions=[];t;)t-=1,this.positions.push(0)}},{key:"_layout",value:function(t){var e=this,i=this._getNextPositions(t),n=0;t.forEach(function(t,s){function o(){t.applyCss(A.Css.VISIBLE.after)}if(C.equals(t.point,i[s])&&!t.isHidden)return t.applyCss(A.Css.VISIBLE.before),void o();t.point=i[s],t.scale=A.Scale.VISIBLE,t.isHidden=!1;var r=e.getStylesForTransition(t,A.Css.VISIBLE.before);r.transitionDelay=e._getStaggerAmount(n)+"ms",e._queue.push({item:t,styles:r,callback:o}),n+=1})}},{key:"_getNextPositions",value:function(t){var i=this;if(this.options.isCentered){var n=t.map(function(t,n){var s=e.getSize(t.element,!0),o=i._getItemPosition(s);return new L(o.x,o.y,s.width,s.height,n)});return this.getTransformedPositions(n,this.containerWidth)}return t.map(function(t){return i._getItemPosition(e.getSize(t.element,!0))})}},{key:"_getItemPosition",value:function(t){return m({itemSize:t,positions:this.positions,gridSize:this.colWidth,total:this.cols,threshold:this.options.columnThreshold,buffer:this.options.buffer})}},{key:"getTransformedPositions",value:function(t,e){return p(t,e)}},{key:"_shrink",value:function(){var t=this,e=0;(arguments.length>0&&void 0!==arguments[0]?arguments[0]:this._getConcealedItems()).forEach(function(i){function n(){i.applyCss(A.Css.HIDDEN.after)}if(i.isHidden)return i.applyCss(A.Css.HIDDEN.before),void n();i.scale=A.Scale.HIDDEN,i.isHidden=!0;var s=t.getStylesForTransition(i,A.Css.HIDDEN.before);s.transitionDelay=t._getStaggerAmount(e)+"ms",t._queue.push({item:i,styles:s,callback:n}),e+=1})}},{key:"_handleResize",value:function(){this.isEnabled&&!this.isDestroyed&&this.update()}},{key:"getStylesForTransition",value:function(t,e){var i=Object.assign({},e);return this.options.useTransforms?i.transform="translate("+t.point.x+"px, "+t.point.y+"px) scale("+t.scale+")":(i.left=t.point.x+"px",i.top=t.point.y+"px"),i}},{key:"_whenTransitionDone",value:function(t,e,i){var n=a(t,function(t){e(),i(null,t)});this._transitions.push(n)}},{key:"_getTransitionFunction",value:function(t){var e=this;return function(i){t.item.applyCss(t.styles),e._whenTransitionDone(t.item.element,t.callback,i)}}},{key:"_processQueue",value:function(){this.isTransitioning&&this._cancelMovement();var t=this.options.speed>0,i=this._queue.length>0;i&&t&&this.isInitialized?this._startTransitions(this._queue):i?(this._styleImmediately(this._queue),this._dispatch(e.EventType.LAYOUT)):this._dispatch(e.EventType.LAYOUT),this._queue.length=0}},{key:"_startTransitions",value:function(t){var e=this;this.isTransitioning=!0;var i=t.map(function(t){return e._getTransitionFunction(t)});b(i,this._movementFinished.bind(this))}},{key:"_cancelMovement",value:function(){this._transitions.forEach(l),this._transitions.length=0,this.isTransitioning=!1}},{key:"_styleImmediately",value:function(t){if(t.length){var i=t.map(function(t){return t.item.element});e._skipTransitions(i,function(){t.forEach(function(t){t.item.applyCss(t.styles),t.callback()})})}}},{key:"_movementFinished",value:function(){this._transitions.length=0,this.isTransitioning=!1,this._dispatch(e.EventType.LAYOUT)}},{key:"filter",value:function(t,i){this.isEnabled&&((!t||t&&0===t.length)&&(t=e.ALL_ITEMS),this._filter(t),this._shrink(),this._updateItemCount(),this.sort(i))}},{key:"sort",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.lastSort;if(this.isEnabled){this._resetCols();var e=o(this._getFilteredItems(),t);this._layout(e),this._processQueue(),this._setContainerSize(),this.lastSort=t}}},{key:"update",value:function(){var t=arguments.length>0&&void 0!==arguments[0]&&arguments[0];this.isEnabled&&(t||this._setColumns(),this.sort())}},{key:"layout",value:function(){this.update(!0)}},{key:"add",value:function(t){var e=this,i=y(t).map(function(t){return new A(t)});this._initItems(i),this._resetCols();var n=this._filter(this.lastFilter,i),s=o(this._mergeNewItems(n.visible),this.lastSort),r=this._getNextPositions(s);s.forEach(function(t,i){n.visible.includes(t)&&(t.point=r[i],t.scale=A.Scale.HIDDEN,t.isHidden=!0,t.applyCss(A.Css.HIDDEN.before),t.applyCss(A.Css.HIDDEN.after),t.applyCss(e.getStylesForTransition(t,{})))}),this.element.offsetWidth,this.setItemTransitions(i),this.items=this._mergeNewItems(i),this.filter(this.lastFilter)}},{key:"disable",value:function(){this.isEnabled=!1}},{key:"enable",value:function(){var t=!(arguments.length>0&&void 0!==arguments[0])||arguments[0];this.isEnabled=!0,t&&this.update()}},{key:"remove",value:function(t){var i=this;if(t.length){var n=y(t),s=n.map(function(t){return i.getItemByElement(t)}).filter(function(t){return!!t});this._toggleFilterClasses({visible:[],hidden:s}),this._shrink(s),this.sort(),this.items=this.items.filter(function(t){return!s.includes(t)}),this._updateItemCount(),this.once(e.EventType.LAYOUT,function(){i._disposeItems(s),n.forEach(function(t){t.parentNode.removeChild(t)}),i._dispatch(e.EventType.REMOVED,{collection:n})})}}},{key:"getItemByElement",value:function(t){return this.items.find(function(e){return e.element===t})}},{key:"resetItems",value:function(){var t=this;this._disposeItems(this.items),this.isInitialized=!1,this.items=this._getItems(),this._initItems(this.items),this.once(e.EventType.LAYOUT,function(){t.setItemTransitions(t.items),t.isInitialized=!0}),this.filter(this.lastFilter)}},{key:"destroy",value:function(){this._cancelMovement(),window.removeEventListener("resize",this._onResize),this.element.classList.remove("shuffle"),this.element.removeAttribute("style"),this._disposeItems(this.items),this.items.length=0,this._transitions.length=0,this.options.sizer=null,this.element=null,this.isDestroyed=!0,this.isEnabled=!1}}],[{key:"getSize",value:function(t){var e=arguments.length>1&&void 0!==arguments[1]&&arguments[1],i=window.getComputedStyle(t,null),s=n(t,"width",i),o=n(t,"height",i);return e&&(s+=n(t,"marginLeft",i)+n(t,"marginRight",i),o+=n(t,"marginTop",i)+n(t,"marginBottom",i)),{width:s,height:o}}},{key:"_skipTransitions",value:function(t,e){var i=t.map(function(t){var e=t.style,i=e.transitionDuration,n=e.transitionDelay;return e.transitionDuration="0ms",e.transitionDelay="0ms",{duration:i,delay:n}});e(),t[0].offsetWidth,t.forEach(function(t,e){t.style.transitionDuration=i[e].duration,t.style.transitionDelay=i[e].delay})}}]),e}();return V.ShuffleItem=A,V.ALL_ITEMS="all",V.FILTER_ATTRIBUTE_KEY="groups",V.EventType={LAYOUT:"shuffle:layout",REMOVED:"shuffle:removed"},V.Classes=D,V.FilterMode={ANY:"any",ALL:"all"},V.options={group:V.ALL_ITEMS,speed:250,easing:"cubic-bezier(0.4, 0.0, 0.2, 1)",itemSelector:"*",sizer:null,gutterWidth:0,columnWidth:0,delimeter:null,buffer:0,columnThreshold:.01,initialSort:null,throttle:function(t,e){function i(){r=0,l=+new Date,o=t.apply(n,s),n=null,s=null}var n,s,o,r,l=0;return function(){n=this,s=arguments;var t=new Date-l;return r||(t>=e?i():r=setTimeout(i,e-t)),o}},throttleTime:300,staggerAmount:15,staggerAmountMax:150,useTransforms:!0,filterMode:V.FilterMode.ANY,isCentered:!1},V.Point=C,V.Rect=L,V.__sorter=o,V.__getColumnSpan=f,V.__getAvailablePositions=c,V.__getShortColumn=d,V.__getCenteredPositions=p,V}); //# sourceMappingURL=shuffle.min.js.map diff --git a/dist/shuffle.min.js.map b/dist/shuffle.min.js.map index 00fc620..23f03dd 100644 --- a/dist/shuffle.min.js.map +++ b/dist/shuffle.min.js.map @@ -1 +1 @@ -{"version":3,"file":"shuffle.min.js","sources":["../node_modules/matches-selector/index.js","../node_modules/xtend/immutable.js","../node_modules/throttleit/index.js","../node_modules/array-parallel/index.js","../src/get-number.js","../src/get-number-style.js","../src/sorter.js","../src/on-transition-end.js","../src/array-max.js","../src/array-min.js","../src/layout.js","../src/shuffle.js","../node_modules/custom-event-polyfill/custom-event-polyfill.js","../node_modules/array-uniq/index.js","../src/point.js","../src/classes.js","../src/shuffle-item.js","../src/computed-size.js"],"sourcesContent":["'use strict';\n\nvar proto = Element.prototype;\nvar vendor = proto.matches\n || proto.matchesSelector\n || proto.webkitMatchesSelector\n || proto.mozMatchesSelector\n || proto.msMatchesSelector\n || proto.oMatchesSelector;\n\nmodule.exports = match;\n\n/**\n * Match `el` to `selector`.\n *\n * @param {Element} el\n * @param {String} selector\n * @return {Boolean}\n * @api public\n */\n\nfunction match(el, selector) {\n if (vendor) return vendor.call(el, selector);\n var nodes = el.parentNode.querySelectorAll(selector);\n for (var i = 0; i < nodes.length; i++) {\n if (nodes[i] == el) return true;\n }\n return false;\n}","module.exports = extend\n\nvar hasOwnProperty = Object.prototype.hasOwnProperty;\n\nfunction extend() {\n var target = {}\n\n for (var i = 0; i < arguments.length; i++) {\n var source = arguments[i]\n\n for (var key in source) {\n if (hasOwnProperty.call(source, key)) {\n target[key] = source[key]\n }\n }\n }\n\n return target\n}\n","module.exports = throttle;\n\n/**\n * Returns a new function that, when invoked, invokes `func` at most once per `wait` milliseconds.\n *\n * @param {Function} func Function to wrap.\n * @param {Number} wait Number of milliseconds that must elapse between `func` invocations.\n * @return {Function} A new function that wraps the `func` function passed in.\n */\n\nfunction throttle (func, wait) {\n var ctx, args, rtn, timeoutID; // caching\n var last = 0;\n\n return function throttled () {\n ctx = this;\n args = arguments;\n var delta = new Date() - last;\n if (!timeoutID)\n if (delta >= wait) call();\n else timeoutID = setTimeout(call, wait - delta);\n return rtn;\n };\n\n function call () {\n timeoutID = 0;\n last = +new Date();\n rtn = func.apply(ctx, args);\n ctx = null;\n args = null;\n }\n}\n","module.exports = function parallel(fns, context, callback) {\n if (!callback) {\n if (typeof context === 'function') {\n callback = context\n context = null\n } else {\n callback = noop\n }\n }\n\n var pending = fns && fns.length\n if (!pending) return callback(null, []);\n\n var finished = false\n var results = new Array(pending)\n\n fns.forEach(context ? function (fn, i) {\n fn.call(context, maybeDone(i))\n } : function (fn, i) {\n fn(maybeDone(i))\n })\n\n function maybeDone(i) {\n return function (err, result) {\n if (finished) return;\n\n if (err) {\n callback(err, results)\n finished = true\n return\n }\n\n results[i] = result\n\n if (!--pending) callback(null, results);\n }\n }\n}\n\nfunction noop() {}\n","/**\n * Always returns a numeric value, given a value. Logic from jQuery's `isNumeric`.\n * @param {*} value Possibly numeric value.\n * @return {number} `value` or zero if `value` isn't numeric.\n */\nexport default function getNumber(value) {\n return parseFloat(value) || 0;\n}\n","import getNumber from './get-number';\nimport COMPUTED_SIZE_INCLUDES_PADDING from './computed-size';\n\n/**\n * Retrieve the computed style for an element, parsed as a float.\n * @param {Element} element Element to get style for.\n * @param {string} style Style property.\n * @param {CSSStyleDeclaration} [styles] Optionally include clean styles to\n * use instead of asking for them again.\n * @return {number} The parsed computed value or zero if that fails because IE\n * will return 'auto' when the element doesn't have margins instead of\n * the computed style.\n */\nexport default function getNumberStyle(element, style,\n styles = window.getComputedStyle(element, null)) {\n let value = getNumber(styles[style]);\n\n // Support IE<=11 and W3C spec.\n if (!COMPUTED_SIZE_INCLUDES_PADDING && style === 'width') {\n value += getNumber(styles.paddingLeft) +\n getNumber(styles.paddingRight) +\n getNumber(styles.borderLeftWidth) +\n getNumber(styles.borderRightWidth);\n } else if (!COMPUTED_SIZE_INCLUDES_PADDING && style === 'height') {\n value += getNumber(styles.paddingTop) +\n getNumber(styles.paddingBottom) +\n getNumber(styles.borderTopWidth) +\n getNumber(styles.borderBottomWidth);\n }\n\n return value;\n}\n","import xtend from 'xtend';\n\n/**\n * Fisher-Yates shuffle.\n * http://stackoverflow.com/a/962890/373422\n * https://bost.ocks.org/mike/shuffle/\n * @param {Array} array Array to shuffle.\n * @return {Array} Randomly sorted array.\n */\nfunction randomize(array) {\n let n = array.length;\n\n while (n) {\n n -= 1;\n const i = Math.floor(Math.random() * (n + 1));\n const temp = array[i];\n array[i] = array[n];\n array[n] = temp;\n }\n\n return array;\n}\n\nconst defaults = {\n // Use array.reverse() to reverse the results\n reverse: false,\n\n // Sorting function\n by: null,\n\n // If true, this will skip the sorting and return a randomized order in the array\n randomize: false,\n\n // Determines which property of each item in the array is passed to the\n // sorting method.\n key: 'element',\n};\n\n// You can return `undefined` from the `by` function to revert to DOM order.\nexport default function sorter(arr, options) {\n const opts = xtend(defaults, options);\n const original = [].slice.call(arr);\n let revert = false;\n\n if (!arr.length) {\n return [];\n }\n\n if (opts.randomize) {\n return randomize(arr);\n }\n\n // Sort the elements by the opts.by function.\n // If we don't have opts.by, default to DOM order\n if (typeof opts.by === 'function') {\n arr.sort((a, b) => {\n // Exit early if we already know we want to revert\n if (revert) {\n return 0;\n }\n\n const valA = opts.by(a[opts.key]);\n const valB = opts.by(b[opts.key]);\n\n // If both values are undefined, use the DOM order\n if (valA === undefined && valB === undefined) {\n revert = true;\n return 0;\n }\n\n if (valA < valB || valA === 'sortFirst' || valB === 'sortLast') {\n return -1;\n }\n\n if (valA > valB || valA === 'sortLast' || valB === 'sortFirst') {\n return 1;\n }\n\n return 0;\n });\n }\n\n // Revert to the original array if necessary\n if (revert) {\n return original;\n }\n\n if (opts.reverse) {\n arr.reverse();\n }\n\n return arr;\n}\n","const transitions = {};\nconst eventName = 'transitionend';\nlet count = 0;\n\nfunction uniqueId() {\n count += 1;\n return eventName + count;\n}\n\nexport function cancelTransitionEnd(id) {\n if (transitions[id]) {\n transitions[id].element.removeEventListener(eventName, transitions[id].listener);\n transitions[id] = null;\n return true;\n }\n\n return false;\n}\n\nexport function onTransitionEnd(element, callback) {\n const id = uniqueId();\n const listener = (evt) => {\n if (evt.currentTarget === evt.target) {\n cancelTransitionEnd(id);\n callback(evt);\n }\n };\n\n element.addEventListener(eventName, listener);\n\n transitions[id] = { element, listener };\n\n return id;\n}\n","export default function arrayMax(array) {\n return Math.max.apply(Math, array); // eslint-disable-line prefer-spread\n}\n","export default function arrayMin(array) {\n return Math.min.apply(Math, array); // eslint-disable-line prefer-spread\n}\n","import Point from './point';\nimport arrayMax from './array-max';\nimport arrayMin from './array-min';\n\n/**\n * Determine the number of columns an items spans.\n * @param {number} itemWidth Width of the item.\n * @param {number} columnWidth Width of the column (includes gutter).\n * @param {number} columns Total number of columns\n * @param {number} threshold A buffer value for the size of the column to fit.\n * @return {number}\n */\nexport function getColumnSpan(itemWidth, columnWidth, columns, threshold) {\n let columnSpan = itemWidth / columnWidth;\n\n // If the difference between the rounded column span number and the\n // calculated column span number is really small, round the number to\n // make it fit.\n if (Math.abs(Math.round(columnSpan) - columnSpan) < threshold) {\n // e.g. columnSpan = 4.0089945390298745\n columnSpan = Math.round(columnSpan);\n }\n\n // Ensure the column span is not more than the amount of columns in the whole layout.\n return Math.min(Math.ceil(columnSpan), columns);\n}\n\n/**\n * Retrieves the column set to use for placement.\n * @param {number} columnSpan The number of columns this current item spans.\n * @param {number} columns The total columns in the grid.\n * @return {Array.} An array of numbers represeting the column set.\n */\nexport function getAvailablePositions(positions, columnSpan, columns) {\n // The item spans only one column.\n if (columnSpan === 1) {\n return positions;\n }\n\n // The item spans more than one column, figure out how many different\n // places it could fit horizontally.\n // The group count is the number of places within the positions this block\n // could fit, ignoring the current positions of items.\n // Imagine a 2 column brick as the second item in a 4 column grid with\n // 10px height each. Find the places it would fit:\n // [20, 10, 10, 0]\n // | | |\n // * * *\n //\n // Then take the places which fit and get the bigger of the two:\n // max([20, 10]), max([10, 10]), max([10, 0]) = [20, 10, 0]\n //\n // Next, find the first smallest number (the short column).\n // [20, 10, 0]\n // |\n // *\n //\n // And that's where it should be placed!\n //\n // Another example where the second column's item extends past the first:\n // [10, 20, 10, 0] => [20, 20, 10] => 10\n const available = [];\n\n // For how many possible positions for this item there are.\n for (let i = 0; i <= columns - columnSpan; i++) {\n // Find the bigger value for each place it could fit.\n available.push(arrayMax(positions.slice(i, i + columnSpan)));\n }\n\n return available;\n}\n\n/**\n * Find index of short column, the first from the left where this item will go.\n *\n * @param {Array.} positions The array to search for the smallest number.\n * @param {number} buffer Optional buffer which is very useful when the height\n * is a percentage of the width.\n * @return {number} Index of the short column.\n */\nexport function getShortColumn(positions, buffer) {\n const minPosition = arrayMin(positions);\n for (let i = 0, len = positions.length; i < len; i++) {\n if (positions[i] >= minPosition - buffer && positions[i] <= minPosition + buffer) {\n return i;\n }\n }\n\n return 0;\n}\n\n/**\n * Determine the location of the next item, based on its size.\n * @param {Object} itemSize Object with width and height.\n * @param {Array.} positions Positions of the other current items.\n * @param {number} gridSize The column width or row height.\n * @param {number} total The total number of columns or rows.\n * @param {number} threshold Buffer value for the column to fit.\n * @param {number} buffer Vertical buffer for the height of items.\n * @return {Point}\n */\nexport function getItemPosition({ itemSize, positions, gridSize, total, threshold, buffer }) {\n const span = getColumnSpan(itemSize.width, gridSize, total, threshold);\n const setY = getAvailablePositions(positions, span, total);\n const shortColumnIndex = getShortColumn(setY, buffer);\n\n // Position the item\n const point = new Point(\n Math.round(gridSize * shortColumnIndex),\n Math.round(setY[shortColumnIndex]));\n\n // Update the columns array with the new values for each column.\n // e.g. before the update the columns could be [250, 0, 0, 0] for an item\n // which spans 2 columns. After it would be [250, itemHeight, itemHeight, 0].\n const setHeight = setY[shortColumnIndex] + itemSize.height;\n for (let i = 0; i < span; i++) {\n positions[shortColumnIndex + i] = setHeight;\n }\n\n return point;\n}\n","import 'custom-event-polyfill';\nimport matches from 'matches-selector';\nimport arrayUnique from 'array-uniq';\nimport xtend from 'xtend';\nimport throttle from 'throttleit';\nimport parallel from 'array-parallel';\nimport Point from './point';\nimport ShuffleItem from './shuffle-item';\nimport Classes from './classes';\nimport getNumberStyle from './get-number-style';\nimport sorter from './sorter';\nimport { onTransitionEnd, cancelTransitionEnd } from './on-transition-end';\nimport { getItemPosition, getColumnSpan, getAvailablePositions, getShortColumn } from './layout';\nimport arrayMax from './array-max';\n\nfunction toArray(arrayLike) {\n return Array.prototype.slice.call(arrayLike);\n}\n\nfunction arrayIncludes(array, obj) {\n return array.indexOf(obj) > -1;\n}\n\n// Used for unique instance variables\nlet id = 0;\n\nclass Shuffle {\n\n /**\n * Categorize, sort, and filter a responsive grid of items.\n *\n * @param {Element} element An element which is the parent container for the grid items.\n * @param {Object} [options=Shuffle.options] Options object.\n * @constructor\n */\n constructor(element, options = {}) {\n this.options = xtend(Shuffle.options, options);\n\n this.useSizer = false;\n this.lastSort = {};\n this.group = Shuffle.ALL_ITEMS;\n this.lastFilter = Shuffle.ALL_ITEMS;\n this.isEnabled = true;\n this.isDestroyed = false;\n this.isInitialized = false;\n this._transitions = [];\n this.isTransitioning = false;\n this._queue = [];\n\n const el = this._getElementOption(element);\n\n if (!el) {\n throw new TypeError('Shuffle needs to be initialized with an element.');\n }\n\n this.element = el;\n this.id = 'shuffle_' + id;\n id += 1;\n\n this._init();\n this.isInitialized = true;\n }\n\n _init() {\n this.items = this._getItems();\n\n this.options.sizer = this._getElementOption(this.options.sizer);\n\n if (this.options.sizer) {\n this.useSizer = true;\n }\n\n // Add class and invalidate styles\n this.element.classList.add(Shuffle.Classes.BASE);\n\n // Set initial css for each item\n this._initItems();\n\n // Bind resize events\n this._onResize = this._getResizeFunction();\n window.addEventListener('resize', this._onResize);\n\n // Get container css all in one request. Causes reflow\n const containerCss = window.getComputedStyle(this.element, null);\n const containerWidth = Shuffle.getSize(this.element).width;\n\n // Add styles to the container if it doesn't have them.\n this._validateStyles(containerCss);\n\n // We already got the container's width above, no need to cause another\n // reflow getting it again... Calculate the number of columns there will be\n this._setColumns(containerWidth);\n\n // Kick off!\n this.filter(this.options.group, this.options.initialSort);\n\n // The shuffle items haven't had transitions set on them yet so the user\n // doesn't see the first layout. Set them now that the first layout is done.\n // First, however, a synchronous layout must be caused for the previous\n // styles to be applied without transitions.\n this.element.offsetWidth; // eslint-disable-line no-unused-expressions\n this._setTransitions();\n this.element.style.transition = 'height ' + this.options.speed + 'ms ' + this.options.easing;\n }\n\n /**\n * Returns a throttled and proxied function for the resize handler.\n * @return {Function}\n * @private\n */\n _getResizeFunction() {\n const resizeFunction = this._handleResize.bind(this);\n return this.options.throttle ?\n this.options.throttle(resizeFunction, this.options.throttleTime) :\n resizeFunction;\n }\n\n /**\n * Retrieve an element from an option.\n * @param {string|jQuery|Element} option The option to check.\n * @return {?Element} The plain element or null.\n * @private\n */\n _getElementOption(option) {\n // If column width is a string, treat is as a selector and search for the\n // sizer element within the outermost container\n if (typeof option === 'string') {\n return this.element.querySelector(option);\n\n // Check for an element\n } else if (option && option.nodeType && option.nodeType === 1) {\n return option;\n\n // Check for jQuery object\n } else if (option && option.jquery) {\n return option[0];\n }\n\n return null;\n }\n\n /**\n * Ensures the shuffle container has the css styles it needs applied to it.\n * @param {Object} styles Key value pairs for position and overflow.\n * @private\n */\n _validateStyles(styles) {\n // Position cannot be static.\n if (styles.position === 'static') {\n this.element.style.position = 'relative';\n }\n\n // Overflow has to be hidden.\n if (styles.overflow !== 'hidden') {\n this.element.style.overflow = 'hidden';\n }\n }\n\n /**\n * Filter the elements by a category.\n * @param {string} [category] Category to filter by. If it's given, the last\n * category will be used to filter the items.\n * @param {Array} [collection] Optionally filter a collection. Defaults to\n * all the items.\n * @return {!{visible: Array, hidden: Array}}\n * @private\n */\n _filter(category = this.lastFilter, collection = this.items) {\n const set = this._getFilteredSets(category, collection);\n\n // Individually add/remove hidden/visible classes\n this._toggleFilterClasses(set);\n\n // Save the last filter in case elements are appended.\n this.lastFilter = category;\n\n // This is saved mainly because providing a filter function (like searching)\n // will overwrite the `lastFilter` property every time its called.\n if (typeof category === 'string') {\n this.group = category;\n }\n\n return set;\n }\n\n /**\n * Returns an object containing the visible and hidden elements.\n * @param {string|Function} category Category or function to filter by.\n * @param {Array.} items A collection of items to filter.\n * @return {!{visible: Array, hidden: Array}}\n * @private\n */\n _getFilteredSets(category, items) {\n let visible = [];\n const hidden = [];\n\n // category === 'all', add visible class to everything\n if (category === Shuffle.ALL_ITEMS) {\n visible = items;\n\n // Loop through each item and use provided function to determine\n // whether to hide it or not.\n } else {\n items.forEach((item) => {\n if (this._doesPassFilter(category, item.element)) {\n visible.push(item);\n } else {\n hidden.push(item);\n }\n });\n }\n\n return {\n visible,\n hidden,\n };\n }\n\n /**\n * Test an item to see if it passes a category.\n * @param {string|Function} category Category or function to filter by.\n * @param {Element} element An element to test.\n * @return {boolean} Whether it passes the category/filter.\n * @private\n */\n _doesPassFilter(category, element) {\n if (typeof category === 'function') {\n return category.call(element, element, this);\n }\n\n // Check each element's data-groups attribute against the given category.\n const attr = element.getAttribute('data-' + Shuffle.FILTER_ATTRIBUTE_KEY);\n const keys = this.options.delimeter ?\n attr.split(this.options.delimeter) :\n JSON.parse(attr);\n\n function testCategory(category) {\n return arrayIncludes(keys, category);\n }\n\n if (Array.isArray(category)) {\n if (this.options.filterMode === Shuffle.FilterMode.ANY) {\n return category.some(testCategory);\n }\n return category.every(testCategory);\n }\n\n return arrayIncludes(keys, category);\n }\n\n /**\n * Toggles the visible and hidden class names.\n * @param {{visible, hidden}} Object with visible and hidden arrays.\n * @private\n */\n _toggleFilterClasses({ visible, hidden }) {\n visible.forEach((item) => {\n item.show();\n });\n\n hidden.forEach((item) => {\n item.hide();\n });\n }\n\n /**\n * Set the initial css for each item\n * @param {Array.} [items] Optionally specifiy at set to initialize.\n * @private\n */\n _initItems(items = this.items) {\n items.forEach((item) => {\n item.init();\n });\n }\n\n /**\n * Remove element reference and styles.\n * @private\n */\n _disposeItems(items = this.items) {\n items.forEach((item) => {\n item.dispose();\n });\n }\n\n /**\n * Updates the visible item count.\n * @private\n */\n _updateItemCount() {\n this.visibleItems = this._getFilteredItems().length;\n }\n\n /**\n * Sets css transform transition on a group of elements. This is not executed\n * at the same time as `item.init` so that transitions don't occur upon\n * initialization of Shuffle.\n * @param {Array.} items Shuffle items to set transitions on.\n * @private\n */\n _setTransitions(items = this.items) {\n const speed = this.options.speed;\n const easing = this.options.easing;\n\n const str = this.options.useTransforms ?\n `transform ${speed}ms ${easing}, opacity ${speed}ms ${easing}` :\n `top ${speed}ms ${easing}, left ${speed}ms ${easing}, opacity ${speed}ms ${easing}`;\n\n items.forEach((item) => {\n item.element.style.transition = str;\n });\n }\n\n _getItems() {\n return toArray(this.element.children)\n .filter(el => matches(el, this.options.itemSelector))\n .map(el => new ShuffleItem(el));\n }\n\n /**\n * When new elements are added to the shuffle container, update the array of\n * items because that is the order `_layout` calls them.\n */\n _updateItemsOrder() {\n const children = this.element.children;\n this.items = sorter(this.items, {\n by(element) {\n return Array.prototype.indexOf.call(children, element);\n },\n });\n }\n\n _getFilteredItems() {\n return this.items.filter(item => item.isVisible);\n }\n\n _getConcealedItems() {\n return this.items.filter(item => !item.isVisible);\n }\n\n /**\n * Returns the column size, based on column width and sizer options.\n * @param {number} containerWidth Size of the parent container.\n * @param {number} gutterSize Size of the gutters.\n * @return {number}\n * @private\n */\n _getColumnSize(containerWidth, gutterSize) {\n let size;\n\n // If the columnWidth property is a function, then the grid is fluid\n if (typeof this.options.columnWidth === 'function') {\n size = this.options.columnWidth(containerWidth);\n\n // columnWidth option isn't a function, are they using a sizing element?\n } else if (this.useSizer) {\n size = Shuffle.getSize(this.options.sizer).width;\n\n // if not, how about the explicitly set option?\n } else if (this.options.columnWidth) {\n size = this.options.columnWidth;\n\n // or use the size of the first item\n } else if (this.items.length > 0) {\n size = Shuffle.getSize(this.items[0].element, true).width;\n\n // if there's no items, use size of container\n } else {\n size = containerWidth;\n }\n\n // Don't let them set a column width of zero.\n if (size === 0) {\n size = containerWidth;\n }\n\n return size + gutterSize;\n }\n\n /**\n * Returns the gutter size, based on gutter width and sizer options.\n * @param {number} containerWidth Size of the parent container.\n * @return {number}\n * @private\n */\n _getGutterSize(containerWidth) {\n let size;\n if (typeof this.options.gutterWidth === 'function') {\n size = this.options.gutterWidth(containerWidth);\n } else if (this.useSizer) {\n size = getNumberStyle(this.options.sizer, 'marginLeft');\n } else {\n size = this.options.gutterWidth;\n }\n\n return size;\n }\n\n /**\n * Calculate the number of columns to be used. Gets css if using sizer element.\n * @param {number} [containerWidth] Optionally specify a container width if\n * it's already available.\n */\n _setColumns(containerWidth = Shuffle.getSize(this.element).width) {\n const gutter = this._getGutterSize(containerWidth);\n const columnWidth = this._getColumnSize(containerWidth, gutter);\n let calculatedColumns = (containerWidth + gutter) / columnWidth;\n\n // Widths given from getStyles are not precise enough...\n if (Math.abs(Math.round(calculatedColumns) - calculatedColumns) <\n this.options.columnThreshold) {\n // e.g. calculatedColumns = 11.998876\n calculatedColumns = Math.round(calculatedColumns);\n }\n\n this.cols = Math.max(Math.floor(calculatedColumns), 1);\n this.containerWidth = containerWidth;\n this.colWidth = columnWidth;\n }\n\n /**\n * Adjust the height of the grid\n */\n _setContainerSize() {\n this.element.style.height = this._getContainerSize() + 'px';\n }\n\n /**\n * Based on the column heights, it returns the biggest one.\n * @return {number}\n * @private\n */\n _getContainerSize() {\n return arrayMax(this.positions);\n }\n\n /**\n * Get the clamped stagger amount.\n * @param {number} index Index of the item to be staggered.\n * @return {number}\n */\n _getStaggerAmount(index) {\n return Math.min(index * this.options.staggerAmount, this.options.staggerAmountMax);\n }\n\n /**\n * @return {boolean} Whether the event was prevented or not.\n */\n _dispatch(name, details = {}) {\n if (this.isDestroyed) {\n return false;\n }\n\n details.shuffle = this;\n return !this.element.dispatchEvent(new CustomEvent(name, {\n bubbles: true,\n cancelable: false,\n detail: details,\n }));\n }\n\n /**\n * Zeros out the y columns array, which is used to determine item placement.\n * @private\n */\n _resetCols() {\n let i = this.cols;\n this.positions = [];\n while (i) {\n i -= 1;\n this.positions.push(0);\n }\n }\n\n /**\n * Loops through each item that should be shown and calculates the x, y position.\n * @param {Array.} items Array of items that will be shown/layed\n * out in order in their array.\n */\n _layout(items) {\n let count = 0;\n items.forEach((item) => {\n const currPos = item.point;\n const currScale = item.scale;\n const itemSize = Shuffle.getSize(item.element, true);\n const pos = this._getItemPosition(itemSize);\n\n function callback() {\n item.element.style.transitionDelay = '';\n item.applyCss(ShuffleItem.Css.VISIBLE.after);\n }\n\n // If the item will not change its position, do not add it to the render\n // queue. Transitions don't fire when setting a property to the same value.\n if (Point.equals(currPos, pos) && currScale === ShuffleItem.Scale.VISIBLE) {\n item.applyCss(ShuffleItem.Css.VISIBLE.before);\n callback();\n return;\n }\n\n item.point = pos;\n item.scale = ShuffleItem.Scale.VISIBLE;\n\n // Use xtend here to clone the object so that the `before` object isn't\n // modified when the transition delay is added.\n const styles = xtend(ShuffleItem.Css.VISIBLE.before);\n styles.transitionDelay = this._getStaggerAmount(count) + 'ms';\n\n this._queue.push({\n item,\n styles,\n callback,\n });\n\n count += 1;\n });\n }\n\n /**\n * Determine the location of the next item, based on its size.\n * @param {{width: number, height: number}} itemSize Object with width and height.\n * @return {Point}\n * @private\n */\n _getItemPosition(itemSize) {\n return getItemPosition({\n itemSize,\n positions: this.positions,\n gridSize: this.colWidth,\n total: this.cols,\n threshold: this.options.columnThreshold,\n buffer: this.options.buffer,\n });\n }\n\n /**\n * Hides the elements that don't match our filter.\n * @param {Array.} collection Collection to shrink.\n * @private\n */\n _shrink(collection = this._getConcealedItems()) {\n let count = 0;\n collection.forEach((item) => {\n function callback() {\n item.applyCss(ShuffleItem.Css.HIDDEN.after);\n }\n\n // Continuing would add a transitionend event listener to the element, but\n // that listener would not execute because the transform and opacity would\n // stay the same.\n // The callback is executed here because it is not guaranteed to be called\n // after the transitionend event because the transitionend could be\n // canceled if another animation starts.\n if (item.scale === ShuffleItem.Scale.HIDDEN) {\n item.applyCss(ShuffleItem.Css.HIDDEN.before);\n callback();\n return;\n }\n\n item.scale = ShuffleItem.Scale.HIDDEN;\n\n const styles = xtend(ShuffleItem.Css.HIDDEN.before);\n styles.transitionDelay = this._getStaggerAmount(count) + 'ms';\n\n this._queue.push({\n item,\n styles,\n callback,\n });\n\n count += 1;\n });\n }\n\n /**\n * Resize handler.\n * @private\n */\n _handleResize() {\n // If shuffle is disabled, destroyed, don't do anything\n if (!this.isEnabled || this.isDestroyed) {\n return;\n }\n\n // Will need to check height in the future if it's layed out horizontaly\n const containerWidth = Shuffle.getSize(this.element).width;\n\n // containerWidth hasn't changed, don't do anything\n if (containerWidth === this.containerWidth) {\n return;\n }\n\n this.update();\n }\n\n /**\n * Returns styles which will be applied to the an item for a transition.\n * @param {Object} obj Transition options.\n * @return {!Object} Transforms for transitions, left/top for animate.\n * @private\n */\n _getStylesForTransition({ item, styles }) {\n if (!styles.transitionDelay) {\n styles.transitionDelay = '0ms';\n }\n\n const x = item.point.x;\n const y = item.point.y;\n\n if (this.options.useTransforms) {\n styles.transform = `translate(${x}px, ${y}px) scale(${item.scale})`;\n } else {\n styles.left = x + 'px';\n styles.top = y + 'px';\n }\n\n return styles;\n }\n\n /**\n * Listen for the transition end on an element and execute the itemCallback\n * when it finishes.\n * @param {Element} element Element to listen on.\n * @param {Function} itemCallback Callback for the item.\n * @param {Function} done Callback to notify `parallel` that this one is done.\n */\n _whenTransitionDone(element, itemCallback, done) {\n const id = onTransitionEnd(element, (evt) => {\n itemCallback();\n done(null, evt);\n });\n\n this._transitions.push(id);\n }\n\n /**\n * Return a function which will set CSS styles and call the `done` function\n * when (if) the transition finishes.\n * @param {Object} opts Transition object.\n * @return {Function} A function to be called with a `done` function.\n */\n _getTransitionFunction(opts) {\n return (done) => {\n opts.item.applyCss(this._getStylesForTransition(opts));\n this._whenTransitionDone(opts.item.element, opts.callback, done);\n };\n }\n\n /**\n * Execute the styles gathered in the style queue. This applies styles to elements,\n * triggering transitions.\n * @private\n */\n _processQueue() {\n if (this.isTransitioning) {\n this._cancelMovement();\n }\n\n const hasSpeed = this.options.speed > 0;\n const hasQueue = this._queue.length > 0;\n\n if (hasQueue && hasSpeed && this.isInitialized) {\n this._startTransitions(this._queue);\n } else if (hasQueue) {\n this._styleImmediately(this._queue);\n this._dispatchLayout();\n\n // A call to layout happened, but none of the newly visible items will\n // change position or the transition duration is zero, which will not trigger\n // the transitionend event.\n } else {\n this._dispatchLayout();\n }\n\n // Remove everything in the style queue\n this._queue.length = 0;\n }\n\n /**\n * Wait for each transition to finish, the emit the layout event.\n * @param {Array.} transitions Array of transition objects.\n */\n _startTransitions(transitions) {\n // Set flag that shuffle is currently in motion.\n this.isTransitioning = true;\n\n // Create an array of functions to be called.\n const callbacks = transitions.map(obj => this._getTransitionFunction(obj));\n\n parallel(callbacks, this._movementFinished.bind(this));\n }\n\n _cancelMovement() {\n // Remove the transition end event for each listener.\n this._transitions.forEach(cancelTransitionEnd);\n\n // Reset the array.\n this._transitions.length = 0;\n\n // Show it's no longer active.\n this.isTransitioning = false;\n }\n\n /**\n * Apply styles without a transition.\n * @param {Array.} objects Array of transition objects.\n * @private\n */\n _styleImmediately(objects) {\n if (objects.length) {\n const elements = objects.map(obj => obj.item.element);\n\n Shuffle._skipTransitions(elements, () => {\n objects.forEach((obj) => {\n obj.item.applyCss(this._getStylesForTransition(obj));\n obj.callback();\n });\n });\n }\n }\n\n _movementFinished() {\n this._transitions.length = 0;\n this.isTransitioning = false;\n this._dispatchLayout();\n }\n\n _dispatchLayout() {\n this._dispatch(Shuffle.EventType.LAYOUT);\n }\n\n /**\n * The magic. This is what makes the plugin 'shuffle'\n * @param {string|Function|Array.} [category] Category to filter by.\n * Can be a function, string, or array of strings.\n * @param {Object} [sortObj] A sort object which can sort the visible set\n */\n filter(category, sortObj) {\n if (!this.isEnabled) {\n return;\n }\n\n if (!category || (category && category.length === 0)) {\n category = Shuffle.ALL_ITEMS; // eslint-disable-line no-param-reassign\n }\n\n this._filter(category);\n\n // Shrink each hidden item\n this._shrink();\n\n // How many visible elements?\n this._updateItemCount();\n\n // Update transforms on visible elements so they will animate to their new positions.\n this.sort(sortObj);\n }\n\n /**\n * Gets the visible elements, sorts them, and passes them to layout.\n * @param {Object} opts the options object for the sorted plugin\n */\n sort(opts = this.lastSort) {\n if (!this.isEnabled) {\n return;\n }\n\n this._resetCols();\n\n let items = this._getFilteredItems();\n items = sorter(items, opts);\n\n this._layout(items);\n\n // `_layout` always happens after `_shrink`, so it's safe to process the style\n // queue here with styles from the shrink method.\n this._processQueue();\n\n // Adjust the height of the container.\n this._setContainerSize();\n\n this.lastSort = opts;\n }\n\n /**\n * Reposition everything.\n * @param {boolean} isOnlyLayout If true, column and gutter widths won't be\n * recalculated.\n */\n update(isOnlyLayout) {\n if (this.isEnabled) {\n if (!isOnlyLayout) {\n // Get updated colCount\n this._setColumns();\n }\n\n // Layout items\n this.sort();\n }\n }\n\n /**\n * Use this instead of `update()` if you don't need the columns and gutters updated\n * Maybe an image inside `shuffle` loaded (and now has a height), which means calculations\n * could be off.\n */\n layout() {\n this.update(true);\n }\n\n /**\n * New items have been appended to shuffle. Mix them in with the current\n * filter or sort status.\n * @param {Array.} newItems Collection of new items.\n */\n add(newItems) {\n const items = arrayUnique(newItems).map(el => new ShuffleItem(el));\n\n // Add classes and set initial positions.\n this._initItems(items);\n\n // Add transition to each item.\n this._setTransitions(items);\n\n // Update the list of items.\n this.items = this.items.concat(items);\n this._updateItemsOrder();\n this.filter(this.lastFilter);\n }\n\n /**\n * Disables shuffle from updating dimensions and layout on resize\n */\n disable() {\n this.isEnabled = false;\n }\n\n /**\n * Enables shuffle again\n * @param {boolean} [isUpdateLayout=true] if undefined, shuffle will update columns and gutters\n */\n enable(isUpdateLayout) {\n this.isEnabled = true;\n if (isUpdateLayout !== false) {\n this.update();\n }\n }\n\n /**\n * Remove 1 or more shuffle items\n * @param {Array.} elements An array containing one or more\n * elements in shuffle\n * @return {Shuffle} The shuffle object\n */\n remove(elements) {\n if (!elements.length) {\n return;\n }\n\n const collection = arrayUnique(elements);\n\n const oldItems = collection\n .map(element => this.getItemByElement(element))\n .filter(item => !!item);\n\n const handleLayout = () => {\n this.element.removeEventListener(Shuffle.EventType.LAYOUT, handleLayout);\n this._disposeItems(oldItems);\n\n // Remove the collection in the callback\n collection.forEach((element) => {\n element.parentNode.removeChild(element);\n });\n\n this._dispatch(Shuffle.EventType.REMOVED, { collection });\n };\n\n // Hide collection first.\n this._toggleFilterClasses({\n visible: [],\n hidden: oldItems,\n });\n\n this._shrink(oldItems);\n\n this.sort();\n\n // Update the list of items here because `remove` could be called again\n // with an item that is in the process of being removed.\n this.items = this.items.filter(item => !arrayIncludes(oldItems, item));\n this._updateItemCount();\n\n this.element.addEventListener(Shuffle.EventType.LAYOUT, handleLayout);\n }\n\n /**\n * Retrieve a shuffle item by its element.\n * @param {Element} element Element to look for.\n * @return {?ShuffleItem} A shuffle item or null if it's not found.\n */\n getItemByElement(element) {\n for (let i = this.items.length - 1; i >= 0; i--) {\n if (this.items[i].element === element) {\n return this.items[i];\n }\n }\n\n return null;\n }\n\n /**\n * Destroys shuffle, removes events, styles, and classes\n */\n destroy() {\n this._cancelMovement();\n window.removeEventListener('resize', this._onResize);\n\n // Reset container styles\n this.element.classList.remove('shuffle');\n this.element.removeAttribute('style');\n\n // Reset individual item styles\n this._disposeItems();\n\n // Null DOM references\n this.items = null;\n this.options.sizer = null;\n this.element = null;\n this._transitions = null;\n\n // Set a flag so if a debounced resize has been triggered,\n // it can first check if it is actually isDestroyed and not doing anything\n this.isDestroyed = true;\n }\n\n /**\n * Returns the outer width of an element, optionally including its margins.\n *\n * There are a few different methods for getting the width of an element, none of\n * which work perfectly for all Shuffle's use cases.\n *\n * 1. getBoundingClientRect() `left` and `right` properties.\n * - Accounts for transform scaled elements, making it useless for Shuffle\n * elements which have shrunk.\n * 2. The `offsetWidth` property.\n * - This value stays the same regardless of the elements transform property,\n * however, it does not return subpixel values.\n * 3. getComputedStyle()\n * - This works great Chrome, Firefox, Safari, but IE<=11 does not include\n * padding and border when box-sizing: border-box is set, requiring a feature\n * test and extra work to add the padding back for IE and other browsers which\n * follow the W3C spec here.\n *\n * @param {Element} element The element.\n * @param {boolean} [includeMargins] Whether to include margins. Default is false.\n * @return {{width: number, height: number}} The width and height.\n */\n static getSize(element, includeMargins) {\n // Store the styles so that they can be used by others without asking for it again.\n const styles = window.getComputedStyle(element, null);\n let width = getNumberStyle(element, 'width', styles);\n let height = getNumberStyle(element, 'height', styles);\n\n if (includeMargins) {\n const marginLeft = getNumberStyle(element, 'marginLeft', styles);\n const marginRight = getNumberStyle(element, 'marginRight', styles);\n const marginTop = getNumberStyle(element, 'marginTop', styles);\n const marginBottom = getNumberStyle(element, 'marginBottom', styles);\n width += marginLeft + marginRight;\n height += marginTop + marginBottom;\n }\n\n return {\n width,\n height,\n };\n }\n\n /**\n * Change a property or execute a function which will not have a transition\n * @param {Array.} elements DOM elements that won't be transitioned.\n * @param {Function} callback A function which will be called while transition\n * is set to 0ms.\n * @private\n */\n static _skipTransitions(elements, callback) {\n const zero = '0ms';\n\n // Save current duration and delay.\n const data = elements.map((element) => {\n const style = element.style;\n const duration = style.transitionDuration;\n const delay = style.transitionDelay;\n\n // Set the duration to zero so it happens immediately\n style.transitionDuration = zero;\n style.transitionDelay = zero;\n\n return {\n duration,\n delay,\n };\n });\n\n callback();\n\n // Cause reflow.\n elements[0].offsetWidth; // eslint-disable-line no-unused-expressions\n\n // Put the duration back\n elements.forEach((element, i) => {\n element.style.transitionDuration = data[i].duration;\n element.style.transitionDelay = data[i].delay;\n });\n }\n}\n\nShuffle.ShuffleItem = ShuffleItem;\n\nShuffle.ALL_ITEMS = 'all';\nShuffle.FILTER_ATTRIBUTE_KEY = 'groups';\n\n/**\n * @enum {string}\n */\nShuffle.EventType = {\n LAYOUT: 'shuffle:layout',\n REMOVED: 'shuffle:removed',\n};\n\n/** @enum {string} */\nShuffle.Classes = Classes;\n\n/**\n * @enum {string}\n */\nShuffle.FilterMode = {\n ANY: 'any',\n ALL: 'all',\n};\n\n// Overrideable options\nShuffle.options = {\n // Initial filter group.\n group: Shuffle.ALL_ITEMS,\n\n // Transition/animation speed (milliseconds).\n speed: 250,\n\n // CSS easing function to use.\n easing: 'ease',\n\n // e.g. '.picture-item'.\n itemSelector: '*',\n\n // Element or selector string. Use an element to determine the size of columns\n // and gutters.\n sizer: null,\n\n // A static number or function that tells the plugin how wide the gutters\n // between columns are (in pixels).\n gutterWidth: 0,\n\n // A static number or function that returns a number which tells the plugin\n // how wide the columns are (in pixels).\n columnWidth: 0,\n\n // If your group is not json, and is comma delimeted, you could set delimeter\n // to ','.\n delimeter: null,\n\n // Useful for percentage based heights when they might not always be exactly\n // the same (in pixels).\n buffer: 0,\n\n // Reading the width of elements isn't precise enough and can cause columns to\n // jump between values.\n columnThreshold: 0.01,\n\n // Shuffle can be isInitialized with a sort object. It is the same object\n // given to the sort method.\n initialSort: null,\n\n // By default, shuffle will throttle resize events. This can be changed or\n // removed.\n throttle,\n\n // How often shuffle can be called on resize (in milliseconds).\n throttleTime: 300,\n\n // Transition delay offset for each item in milliseconds.\n staggerAmount: 15,\n\n // Maximum stagger delay in milliseconds.\n staggerAmountMax: 250,\n\n // Whether to use transforms or absolute positioning.\n useTransforms: true,\n\n // Affects using an array with filter. e.g. `filter(['one', 'two'])`. With \"any\",\n // the element passes the test if any of its groups are in the array. With \"all\",\n // the element only passes if all groups are in the array.\n filterMode: Shuffle.FilterMode.ANY,\n};\n\n// Expose for testing. Hack at your own risk.\nShuffle.__Point = Point;\nShuffle.__sorter = sorter;\nShuffle.__getColumnSpan = getColumnSpan;\nShuffle.__getAvailablePositions = getAvailablePositions;\nShuffle.__getShortColumn = getShortColumn;\n\nexport default Shuffle;\n","// Polyfill for creating CustomEvents on IE9/10/11\n\n// code pulled from:\n// https://github.com/d4tocchini/customevent-polyfill\n// https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent#Polyfill\n\ntry {\n var ce = new window.CustomEvent('test');\n ce.preventDefault();\n if (ce.defaultPrevented !== true) {\n // IE has problems with .preventDefault() on custom events\n // http://stackoverflow.com/questions/23349191\n throw new Error('Could not prevent default');\n }\n} catch(e) {\n var CustomEvent = function(event, params) {\n var evt, origPrevent;\n params = params || {\n bubbles: false,\n cancelable: false,\n detail: undefined\n };\n\n evt = document.createEvent(\"CustomEvent\");\n evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail);\n origPrevent = evt.preventDefault;\n evt.preventDefault = function () {\n origPrevent.call(this);\n try {\n Object.defineProperty(this, 'defaultPrevented', {\n get: function () {\n return true;\n }\n });\n } catch(e) {\n this.defaultPrevented = true;\n }\n };\n return evt;\n };\n\n CustomEvent.prototype = window.Event.prototype;\n window.CustomEvent = CustomEvent; // expose definition to window\n}\n","'use strict';\n\n// there's 3 implementations written in increasing order of efficiency\n\n// 1 - no Set type is defined\nfunction uniqNoSet(arr) {\n\tvar ret = [];\n\n\tfor (var i = 0; i < arr.length; i++) {\n\t\tif (ret.indexOf(arr[i]) === -1) {\n\t\t\tret.push(arr[i]);\n\t\t}\n\t}\n\n\treturn ret;\n}\n\n// 2 - a simple Set type is defined\nfunction uniqSet(arr) {\n\tvar seen = new Set();\n\treturn arr.filter(function (el) {\n\t\tif (!seen.has(el)) {\n\t\t\tseen.add(el);\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t});\n}\n\n// 3 - a standard Set type is defined and it has a forEach method\nfunction uniqSetWithForEach(arr) {\n\tvar ret = [];\n\n\t(new Set(arr)).forEach(function (el) {\n\t\tret.push(el);\n\t});\n\n\treturn ret;\n}\n\n// V8 currently has a broken implementation\n// https://github.com/joyent/node/issues/8449\nfunction doesForEachActuallyWork() {\n\tvar ret = false;\n\n\t(new Set([true])).forEach(function (el) {\n\t\tret = el;\n\t});\n\n\treturn ret === true;\n}\n\nif ('Set' in global) {\n\tif (typeof Set.prototype.forEach === 'function' && doesForEachActuallyWork()) {\n\t\tmodule.exports = uniqSetWithForEach;\n\t} else {\n\t\tmodule.exports = uniqSet;\n\t}\n} else {\n\tmodule.exports = uniqNoSet;\n}\n","import getNumber from './get-number';\n\nclass Point {\n\n /**\n * Represents a coordinate pair.\n * @param {number} [x=0] X.\n * @param {number} [y=0] Y.\n */\n constructor(x, y) {\n this.x = getNumber(x);\n this.y = getNumber(y);\n }\n\n /**\n * Whether two points are equal.\n * @param {Point} a Point A.\n * @param {Point} b Point B.\n * @return {boolean}\n */\n static equals(a, b) {\n return a.x === b.x && a.y === b.y;\n }\n}\n\nexport default Point;\n","export default {\n BASE: 'shuffle',\n SHUFFLE_ITEM: 'shuffle-item',\n VISIBLE: 'shuffle-item--visible',\n HIDDEN: 'shuffle-item--hidden',\n};\n","import Point from './point';\nimport Classes from './classes';\n\nlet id = 0;\n\nclass ShuffleItem {\n constructor(element) {\n id += 1;\n this.id = id;\n this.element = element;\n this.isVisible = true;\n }\n\n show() {\n this.isVisible = true;\n this.element.classList.remove(Classes.HIDDEN);\n this.element.classList.add(Classes.VISIBLE);\n }\n\n hide() {\n this.isVisible = false;\n this.element.classList.remove(Classes.VISIBLE);\n this.element.classList.add(Classes.HIDDEN);\n }\n\n init() {\n this.addClasses([Classes.SHUFFLE_ITEM, Classes.VISIBLE]);\n this.applyCss(ShuffleItem.Css.INITIAL);\n this.scale = ShuffleItem.Scale.VISIBLE;\n this.point = new Point();\n }\n\n addClasses(classes) {\n classes.forEach((className) => {\n this.element.classList.add(className);\n });\n }\n\n removeClasses(classes) {\n classes.forEach((className) => {\n this.element.classList.remove(className);\n });\n }\n\n applyCss(obj) {\n Object.keys(obj).forEach((key) => {\n this.element.style[key] = obj[key];\n });\n }\n\n dispose() {\n this.removeClasses([\n Classes.HIDDEN,\n Classes.VISIBLE,\n Classes.SHUFFLE_ITEM,\n ]);\n\n this.element.removeAttribute('style');\n this.element = null;\n }\n}\n\nShuffleItem.Css = {\n INITIAL: {\n position: 'absolute',\n top: 0,\n left: 0,\n visibility: 'visible',\n 'will-change': 'transform',\n },\n VISIBLE: {\n before: {\n opacity: 1,\n visibility: 'visible',\n },\n after: {},\n },\n HIDDEN: {\n before: {\n opacity: 0,\n },\n after: {\n visibility: 'hidden',\n },\n },\n};\n\nShuffleItem.Scale = {\n VISIBLE: 1,\n HIDDEN: 0.001,\n};\n\nexport default ShuffleItem;\n","const element = document.body || document.documentElement;\nconst e = document.createElement('div');\ne.style.cssText = 'width:10px;padding:2px;box-sizing:border-box;';\nelement.appendChild(e);\n\nconst width = window.getComputedStyle(e, null).width;\nconst ret = width === '10px';\n\nelement.removeChild(e);\n\nexport default ret;\n"],"names":["match","el","selector","vendor","call","nodes","parentNode","querySelectorAll","i","length","extend","target","arguments","source","key","hasOwnProperty","throttle","func","wait","timeoutID","last","Date","rtn","apply","ctx","args","this","delta","setTimeout","noop","getNumber","value","parseFloat","getNumberStyle","element","style","styles","window","getComputedStyle","COMPUTED_SIZE_INCLUDES_PADDING","paddingTop","paddingBottom","borderTopWidth","borderBottomWidth","paddingLeft","paddingRight","borderLeftWidth","borderRightWidth","randomize","array","n","Math","floor","random","temp","sorter","arr","options","opts","xtend","defaults","original","slice","revert","by","sort","a","b","valA","valB","undefined","reverse","uniqueId","eventName","count","cancelTransitionEnd","id","transitions","removeEventListener","listener","onTransitionEnd","callback","evt","currentTarget","addEventListener","arrayMax","max","arrayMin","min","getColumnSpan","itemWidth","columnWidth","columns","threshold","columnSpan","abs","round","ceil","getAvailablePositions","positions","available","push","getShortColumn","buffer","minPosition","len","getItemPosition","itemSize","gridSize","total","span","width","setY","shortColumnIndex","point","Point","setHeight","height","toArray","arrayLike","Array","prototype","arrayIncludes","obj","indexOf","ce","CustomEvent","preventDefault","defaultPrevented","Error","e","event","params","origPrevent","bubbles","cancelable","detail","document","createEvent","initCustomEvent","Object","defineProperty","get","Event","proto","Element","matches","matchesSelector","webkitMatchesSelector","mozMatchesSelector","msMatchesSelector","oMatchesSelector","uniqNoSet","ret","uniqSet","seen","Set","filter","has","add","uniqSetWithForEach","forEach","global","module","fns","context","maybeDone","err","result","finished","results","pending","fn","x","y","ShuffleItem","isVisible","classList","remove","Classes","HIDDEN","VISIBLE","addClasses","SHUFFLE_ITEM","applyCss","Css","INITIAL","scale","Scale","classes","className","keys","removeClasses","removeAttribute","body","documentElement","createElement","cssText","appendChild","removeChild","Shuffle","useSizer","lastSort","group","ALL_ITEMS","lastFilter","isEnabled","isDestroyed","isInitialized","_transitions","isTransitioning","_queue","_getElementOption","TypeError","_init","items","_getItems","sizer","BASE","_initItems","_onResize","_getResizeFunction","containerCss","containerWidth","getSize","_validateStyles","_setColumns","initialSort","offsetWidth","_setTransitions","transition","speed","easing","resizeFunction","_handleResize","bind","throttleTime","option","querySelector","nodeType","jquery","position","overflow","category","collection","set","_getFilteredSets","_toggleFilterClasses","visible","hidden","item","_this","_doesPassFilter","testCategory","attr","getAttribute","FILTER_ATTRIBUTE_KEY","delimeter","split","JSON","parse","isArray","filterMode","FilterMode","ANY","some","every","show","hide","init","dispose","visibleItems","_getFilteredItems","str","useTransforms","children","_this2","itemSelector","map","gutterSize","size","gutterWidth","gutter","_getGutterSize","_getColumnSize","calculatedColumns","columnThreshold","cols","colWidth","_getContainerSize","index","staggerAmount","staggerAmountMax","name","details","shuffle","dispatchEvent","transitionDelay","after","currPos","currScale","pos","_this3","_getItemPosition","equals","before","_getStaggerAmount","_getConcealedItems","_this4","update","transform","left","top","itemCallback","done","_this5","_getStylesForTransition","_whenTransitionDone","_cancelMovement","hasSpeed","hasQueue","_startTransitions","_styleImmediately","_dispatchLayout","callbacks","_this6","_getTransitionFunction","_movementFinished","objects","elements","_skipTransitions","_this7","_dispatch","EventType","LAYOUT","sortObj","_filter","_shrink","_updateItemCount","_resetCols","_layout","_processQueue","_setContainerSize","isOnlyLayout","newItems","arrayUnique","concat","_updateItemsOrder","isUpdateLayout","oldItems","_this8","getItemByElement","handleLayout","_disposeItems","REMOVED","includeMargins","data","duration","transitionDuration","delay","__Point","__sorter","__getColumnSpan","__getAvailablePositions","__getShortColumn"],"mappings":"mLAqBA,SAASA,EAAMC,EAAIC,GACjB,GAAIC,EAAQ,OAAOA,EAAOC,KAAKH,EAAIC,GAEnC,IAAK,IADDG,EAAQJ,EAAGK,WAAWC,iBAAiBL,GAClCM,EAAI,EAAGA,EAAIH,EAAMI,OAAQD,IAChC,GAAIH,EAAMG,IAAMP,EAAI,OAAO,EAE7B,OAAO,ECvBT,SAASS,IAGL,IAAK,IAFDC,KAEKH,EAAI,EAAGA,EAAII,UAAUH,OAAQD,IAAK,CACvC,IAAIK,EAASD,UAAUJ,GAEvB,IAAK,IAAIM,KAAOD,EACRE,EAAeX,KAAKS,EAAQC,KAC5BH,EAAOG,GAAOD,EAAOC,IAKjC,OAAOH,ECPX,SAASK,EAAUC,EAAMC,GAcvB,SAASd,IACPe,EAAY,EACZC,GAAQ,IAAIC,KACZC,EAAML,EAAKM,MAAMC,EAAKC,GACtBD,EAAM,KACNC,EAAO,KAlBT,IAAID,EAAKC,EAAMH,EAAKH,EAChBC,EAAO,EAEX,OAAO,WACLI,EAAME,KACND,EAAOb,UACP,IAAIe,EAAQ,IAAIN,KAASD,EAIzB,OAHKD,IACCQ,GAAST,EAAMd,IACde,EAAYS,WAAWxB,EAAMc,EAAOS,IACpCL,GCkBX,SAASO,KClCT,SAAwBC,EAAUC,UACzBC,WAAWD,IAAU,ECO9B,SAAwBE,EAAeC,EAASC,OAC9CC,yDAASC,OAAOC,iBAAiBJ,EAAS,MACtCH,EAAQD,EAAUM,EAAOD,WAGxBI,GAA4C,UAAVJ,EAK3BI,GAA4C,WAAVJ,OACnCL,EAAUM,EAAOI,YACxBV,EAAUM,EAAOK,eACjBX,EAAUM,EAAOM,gBACjBZ,EAAUM,EAAOO,uBARVb,EAAUM,EAAOQ,aACxBd,EAAUM,EAAOS,cACjBf,EAAUM,EAAOU,iBACjBhB,EAAUM,EAAOW,kBAQdhB,ECrBT,SAASiB,EAAUC,WACbC,EAAID,EAAMxC,OAEPyC,GAAG,IACH,MACC1C,EAAI2C,KAAKC,MAAMD,KAAKE,UAAYH,EAAI,IACpCI,EAAOL,EAAMzC,KACbA,GAAKyC,EAAMC,KACXA,GAAKI,SAGNL,EAmBT,SAAwBM,EAAOC,EAAKC,OAC5BC,EAAOC,EAAMC,EAAUH,GACvBI,KAAcC,MAAM1D,KAAKoD,GAC3BO,GAAS,SAERP,EAAI/C,OAILiD,EAAKV,UACAA,EAAUQ,IAKI,mBAAZE,EAAKM,MACVC,KAAK,SAACC,EAAGC,MAEPJ,SACK,MAGHK,EAAOV,EAAKM,GAAGE,EAAER,EAAK5C,MACtBuD,EAAOX,EAAKM,GAAGG,EAAET,EAAK5C,kBAGfwD,IAATF,QAA+BE,IAATD,MACf,EACF,GAGLD,EAAOC,GAAiB,cAATD,GAAiC,aAATC,GACjC,EAGND,EAAOC,GAAiB,aAATD,GAAgC,cAATC,EACjC,EAGF,IAKPN,EACKF,GAGLH,EAAKa,WACHA,UAGCf,OCvFT,SAASgB,cACE,EACFC,EAAYC,EAGrB,SAAgBC,EAAoBC,WAC9BC,EAAYD,OACFA,GAAI1C,QAAQ4C,oBAAoBL,EAAWI,EAAYD,GAAIG,YAC3DH,GAAM,MACX,GAMX,SAAgBI,EAAgB9C,EAAS+C,OACjCL,EAAKJ,IACLO,EAAW,SAACG,GACZA,EAAIC,gBAAkBD,EAAIvE,WACRiE,KACXM,cAILE,iBAAiBX,EAAWM,KAExBH,IAAQ1C,UAAS6C,YAEtBH,EChCM,SAASS,EAASpC,UACxBE,KAAKmC,IAAI/D,MAAM4B,KAAMF,GCDf,SAASsC,EAAStC,UACxBE,KAAKqC,IAAIjE,MAAM4B,KAAMF,GCW9B,SAAgBwC,EAAcC,EAAWC,EAAaC,EAASC,OACzDC,EAAaJ,EAAYC,SAKzBxC,KAAK4C,IAAI5C,KAAK6C,MAAMF,GAAcA,GAAcD,MAErC1C,KAAK6C,MAAMF,IAInB3C,KAAKqC,IAAIrC,KAAK8C,KAAKH,GAAaF,GASzC,SAAgBM,EAAsBC,EAAWL,EAAYF,MAExC,IAAfE,SACKK,MA4BJ,IAHCC,KAGG5F,EAAI,EAAGA,GAAKoF,EAAUE,EAAYtF,MAE/B6F,KAAKhB,EAASc,EAAUrC,MAAMtD,EAAGA,EAAIsF,YAG1CM,EAWT,SAAgBE,EAAeH,EAAWI,OAEnC,IADCC,EAAcjB,EAASY,GACpB3F,EAAI,EAAGiG,EAAMN,EAAU1F,OAAQD,EAAIiG,EAAKjG,OAC3C2F,EAAU3F,IAAMgG,EAAcD,GAAUJ,EAAU3F,IAAMgG,EAAcD,SACjE/F,SAIJ,EAaT,SAAgBkG,SAcT,IAd2BC,IAAAA,SAAUR,IAAAA,UAAWS,IAAAA,SAAUC,IAAAA,MAAOhB,IAAAA,UAAWU,IAAAA,OAC3EO,EAAOrB,EAAckB,EAASI,MAAOH,EAAUC,EAAOhB,GACtDmB,EAAOd,EAAsBC,EAAWW,EAAMD,GAC9CI,EAAmBX,EAAeU,EAAMT,GAGxCW,EAAQ,IAAIC,EAChBhE,KAAK6C,MAAMY,EAAWK,GACtB9D,KAAK6C,MAAMgB,EAAKC,KAKZG,EAAYJ,EAAKC,GAAoBN,EAASU,OAC3C7G,EAAI,EAAGA,EAAIsG,EAAMtG,MACdyG,EAAmBzG,GAAK4G,SAG7BF,ECxGT,SAASI,EAAQC,UACRC,MAAMC,UAAU3D,MAAM1D,KAAKmH,GAGpC,SAASG,EAAczE,EAAO0E,UACrB1E,EAAM2E,QAAQD,IAAQ,ECd/B,IACI,IAAIE,EAAK,IAAIxF,OAAOyF,YAAY,QAEhC,GADAD,EAAGE,kBACyB,IAAxBF,EAAGG,iBAGH,MAAM,IAAIC,MAAM,6BAEtB,MAAMC,GACN,IAAIJ,EAAc,SAASK,EAAOC,GAChC,IAAIlD,EAAKmD,EAsBT,OArBAD,EAASA,IACPE,SAAS,EACTC,YAAY,EACZC,YAAQlE,IAGVY,EAAMuD,SAASC,YAAY,gBACvBC,gBAAgBR,EAAOC,EAAOE,QAASF,EAAOG,WAAYH,EAAOI,QACrEH,EAAcnD,EAAI6C,eAClB7C,EAAI6C,eAAiB,WACnBM,EAAYjI,KAAKsB,MACjB,IACEkH,OAAOC,eAAenH,KAAM,oBAC1BoH,IAAK,WACH,OAAO,KAGX,MAAMZ,GACNxG,KAAKsG,kBAAmB,IAGrB9C,GAGT4C,EAAYL,UAAYpF,OAAO0G,MAAMtB,UACrCpF,OAAOyF,YAAcA,EZxCvB,IAAIkB,EAAQC,QAAQxB,UAChBtH,EAAS6I,EAAME,SACdF,EAAMG,iBACNH,EAAMI,uBACNJ,EAAMK,oBACNL,EAAMM,mBACNN,EAAMO,mBAEMvJ,qLaLjB,SAASwJ,EAAUhG,GAGlB,IAAK,IAFDiG,KAEKjJ,EAAI,EAAGA,EAAIgD,EAAI/C,OAAQD,KACF,IAAzBiJ,EAAI7B,QAAQpE,EAAIhD,KACnBiJ,EAAIpD,KAAK7C,EAAIhD,IAIf,OAAOiJ,EAIR,SAASC,EAAQlG,GAChB,IAAImG,EAAO,IAAIC,IACf,OAAOpG,EAAIqG,OAAO,SAAU5J,GAC3B,OAAK0J,EAAKG,IAAI7J,KACb0J,EAAKI,IAAI9J,IACF,KAQV,SAAS+J,EAAmBxG,GAC3B,IAAIiG,KAMJ,OAJA,IAAKG,IAAIpG,GAAMyG,QAAQ,SAAUhK,GAChCwJ,EAAIpD,KAAKpG,KAGHwJ,EAeJ,QAASS,EACyB,mBAA1BN,IAAInC,UAAUwC,SAX1B,WACC,IAAIR,GAAM,EAMV,OAJA,IAAKG,MAAK,IAAQK,QAAQ,SAAUhK,GACnCwJ,EAAMxJ,KAGQ,IAARwJ,KAKNU,UAAiBH,EAEjBG,UAAiBT,EAGlBS,UAAiBX,MZ5DD9I,EAEbK,EAAiB6H,OAAOnB,UAAU1G,iBCFrBC,ICAA,SAAkBoJ,EAAKC,EAASpF,GAsB/C,SAASqF,EAAU9J,GACjB,OAAO,SAAU+J,EAAKC,GACpB,IAAIC,EAAJ,CAEA,GAAIF,EAGF,OAFAtF,EAASsF,EAAKG,QACdD,GAAW,GAIbC,EAAQlK,GAAKgK,IAENG,GAAS1F,EAAS,KAAMyF,KAjC9BzF,IACoB,mBAAZoF,GACTpF,EAAWoF,EACXA,EAAU,MAEVpF,EAAWpD,GAIf,IAAI8I,EAAUP,GAAOA,EAAI3J,OACzB,IAAKkK,EAAS,OAAO1F,EAAS,SAE9B,IAAIwF,GAAW,EACXC,EAAU,IAAIlD,MAAMmD,GAExBP,EAAIH,QAAQI,EAAU,SAAUO,EAAIpK,GAClCoK,EAAGxK,KAAKiK,EAASC,EAAU9J,KACzB,SAAUoK,EAAIpK,GAChBoK,EAAGN,EAAU9J,2VWjBX2G,wBAOQ0D,EAAGC,kBACRD,EAAI/I,EAAU+I,QACdC,EAAIhJ,EAAUgJ,iDASP5G,EAAGC,UACRD,EAAE2G,IAAM1G,EAAE0G,GAAK3G,EAAE4G,IAAM3G,EAAE2G,mBCpB5B,uBACQ,uBACL,+BACD,wBCDNlG,EAAK,EAEHmG,wBACQ7I,gBACJ,OACD0C,GAAKA,OACL1C,QAAUA,OACV8I,WAAY,gDAIZA,WAAY,OACZ9I,QAAQ+I,UAAUC,OAAOC,EAAQC,aACjClJ,QAAQ+I,UAAUlB,IAAIoB,EAAQE,6CAI9BL,WAAY,OACZ9I,QAAQ+I,UAAUC,OAAOC,EAAQE,cACjCnJ,QAAQ+I,UAAUlB,IAAIoB,EAAQC,4CAI9BE,YAAYH,EAAQI,aAAcJ,EAAQE,eAC1CG,SAAST,EAAYU,IAAIC,cACzBC,MAAQZ,EAAYa,MAAMP,aAC1BnE,MAAQ,IAAIC,qCAGR0E,gBACD5B,QAAQ,SAAC6B,KACV5J,QAAQ+I,UAAUlB,IAAI+B,2CAIjBD,gBACJ5B,QAAQ,SAAC6B,KACV5J,QAAQ+I,UAAUC,OAAOY,sCAIzBnE,qBACAoE,KAAKpE,GAAKsC,QAAQ,SAACnJ,KACnBoB,QAAQC,MAAMrB,GAAO6G,EAAI7G,4CAK3BkL,eACHb,EAAQC,OACRD,EAAQE,QACRF,EAAQI,oBAGLrJ,QAAQ+J,gBAAgB,cACxB/J,QAAU,cAInB6I,EAAYU,uBAEE,eACL,OACC,aACM,wBACG,sCAIJ,aACG,6CAMH,qBAGG,YAKlBV,EAAYa,eACD,SACD,MCzFV,IAAM1J,EAAUuG,SAASyD,MAAQzD,SAAS0D,gBACpCjE,EAAIO,SAAS2D,cAAc,OACjClE,EAAE/F,MAAMkK,QAAU,gDAClBnK,EAAQoK,YAAYpE,GAEpB,IACMuB,EAAgB,SADRpH,OAAOC,iBAAiB4F,EAAG,MAAMnB,MAG/C7E,EAAQqK,YAAYrE,GXepB,IAAMtE,YAEK,KAGL,gBAGO,MAIN,WCnCDiB,KACAJ,EAAY,gBACdC,EAAQ,EIsBRE,EAAK,EAEH4H,wBASQtK,OAASuB,2EACdA,QAAUE,EAAM6I,EAAQ/I,QAASA,QAEjCgJ,UAAW,OACXC,iBACAC,MAAQH,EAAQI,eAChBC,WAAaL,EAAQI,eACrBE,WAAY,OACZC,aAAc,OACdC,eAAgB,OAChBC,qBACAC,iBAAkB,OAClBC,cAEClN,EAAKyB,KAAK0L,kBAAkBlL,OAE7BjC,QACG,IAAIoN,UAAU,yDAGjBnL,QAAUjC,OACV2E,GAAK,WAAaA,KACjB,OAED0I,aACAN,eAAgB,iDAIhBO,MAAQ7L,KAAK8L,iBAEb/J,QAAQgK,MAAQ/L,KAAK0L,kBAAkB1L,KAAK+B,QAAQgK,OAErD/L,KAAK+B,QAAQgK,aACVhB,UAAW,QAIbvK,QAAQ+I,UAAUlB,IAAIyC,EAAQrB,QAAQuC,WAGtCC,kBAGAC,UAAYlM,KAAKmM,4BACfzI,iBAAiB,SAAU1D,KAAKkM,eAGjCE,EAAezL,OAAOC,iBAAiBZ,KAAKQ,QAAS,MACrD6L,EAAiBvB,EAAQwB,QAAQtM,KAAKQ,SAAS6E,WAGhDkH,gBAAgBH,QAIhBI,YAAYH,QAGZlE,OAAOnI,KAAK+B,QAAQkJ,MAAOjL,KAAK+B,QAAQ0K,kBAMxCjM,QAAQkM,iBACRC,uBACAnM,QAAQC,MAAMmM,WAAa,UAAY5M,KAAK+B,QAAQ8K,MAAQ,MAAQ7M,KAAK+B,QAAQ+K,wDAShFC,EAAiB/M,KAAKgN,cAAcC,KAAKjN,aACxCA,KAAK+B,QAAQzC,SAChBU,KAAK+B,QAAQzC,SAASyN,EAAgB/M,KAAK+B,QAAQmL,cACnDH,4CASYI,SAGM,iBAAXA,EACFnN,KAAKQ,QAAQ4M,cAAcD,GAGzBA,GAAUA,EAAOE,UAAgC,IAApBF,EAAOE,SACtCF,EAGEA,GAAUA,EAAOG,OACnBH,EAAO,GAGT,6CAQOzM,GAEU,WAApBA,EAAO6M,gBACJ/M,QAAQC,MAAM8M,SAAW,YAIR,WAApB7M,EAAO8M,gBACJhN,QAAQC,MAAM+M,SAAW,gDAa1BC,yDAAWzN,KAAKmL,WAAYuC,yDAAa1N,KAAK6L,MAC9C8B,EAAM3N,KAAK4N,iBAAiBH,EAAUC,eAGvCG,qBAAqBF,QAGrBxC,WAAasC,EAIM,iBAAbA,SACJxC,MAAQwC,GAGRE,2CAUQF,EAAU5B,cACrBiC,KACEC,YAGFN,IAAa3C,EAAQI,YACbW,IAKJtD,QAAQ,SAACyF,GACTC,EAAKC,gBAAgBT,EAAUO,EAAKxN,WAC9BmE,KAAKqJ,KAENrJ,KAAKqJ,kEAkBJP,EAAUjN,YAWf2N,EAAaV,UACbzH,EAAcqE,EAAMoD,MAXL,mBAAbA,SACFA,EAAS/O,KAAK8B,EAASA,EAASR,UAInCoO,EAAO5N,EAAQ6N,aAAa,QAAUvD,EAAQwD,sBAC9CjE,EAAOrK,KAAK+B,QAAQwM,UACpBH,EAAKI,MAAMxO,KAAK+B,QAAQwM,WACxBE,KAAKC,MAAMN,UAMbtI,MAAM6I,QAAQlB,GACZzN,KAAK+B,QAAQ6M,aAAe9D,EAAQ+D,WAAWC,IAC1CrB,EAASsB,KAAKZ,GAEhBV,EAASuB,MAAMb,GAGjBnI,EAAcqE,EAAMoD,uDAQNK,IAAAA,QAASC,IAAAA,SACtBxF,QAAQ,SAACyF,KACViB,WAGA1G,QAAQ,SAACyF,KACTkB,sGASUlP,KAAK6L,OAChBtD,QAAQ,SAACyF,KACRmB,yGAQanP,KAAK6L,OACnBtD,QAAQ,SAACyF,KACRoB,4DASFC,aAAerP,KAAKsP,oBAAoBvQ,qDAU/B8M,yDAAQ7L,KAAK6L,MACrBgB,EAAQ7M,KAAK+B,QAAQ8K,MACrBC,EAAS9M,KAAK+B,QAAQ+K,OAEtByC,EAAMvP,KAAK+B,QAAQyN,2BACV3C,QAAWC,eAAmBD,QAAWC,SAC/CD,QAAWC,YAAgBD,QAAWC,eAAmBD,QAAWC,IAEvEvE,QAAQ,SAACyF,KACRxN,QAAQC,MAAMmM,WAAa2C,0DAK3B3J,EAAQ5F,KAAKQ,QAAQiP,UACzBtH,OAAO,mBAAMX,EAAQjJ,EAAImR,EAAK3N,QAAQ4N,gBACtCC,IAAI,mBAAM,IAAIvG,EAAY9K,qDAQvBkR,EAAWzP,KAAKQ,QAAQiP,cACzB5D,MAAQhK,EAAO7B,KAAK6L,mBACpBrL,UACMsF,MAAMC,UAAUG,QAAQxH,KAAK+Q,EAAUjP,yDAM3CR,KAAK6L,MAAM1D,OAAO,mBAAQ6F,EAAK1E,gEAI/BtJ,KAAK6L,MAAM1D,OAAO,mBAAS6F,EAAK1E,mDAU1B+C,EAAgBwD,OACzBC,gBAwBS,OArB2B,mBAA7B9P,KAAK+B,QAAQkC,YACfjE,KAAK+B,QAAQkC,YAAYoI,GAGvBrM,KAAK+K,SACPD,EAAQwB,QAAQtM,KAAK+B,QAAQgK,OAAO1G,MAGlCrF,KAAK+B,QAAQkC,YACfjE,KAAK+B,QAAQkC,YAGXjE,KAAK6L,MAAM9M,OAAS,EACtB+L,EAAQwB,QAAQtM,KAAK6L,MAAM,GAAGrL,SAAS,GAAM6E,MAI7CgH,OAKAA,GAGFyD,EAAOD,yCASDxD,SAE2B,mBAA7BrM,KAAK+B,QAAQgO,YACf/P,KAAK+B,QAAQgO,YAAY1D,GACvBrM,KAAK+K,SACPxK,EAAeP,KAAK+B,QAAQgK,MAAO,cAEnC/L,KAAK+B,QAAQgO,sDAWZ1D,yDAAiBvB,EAAQwB,QAAQtM,KAAKQ,SAAS6E,MACnD2K,EAAShQ,KAAKiQ,eAAe5D,GAC7BpI,EAAcjE,KAAKkQ,eAAe7D,EAAgB2D,GACpDG,GAAqB9D,EAAiB2D,GAAU/L,EAGhDxC,KAAK4C,IAAI5C,KAAK6C,MAAM6L,GAAqBA,GACzCnQ,KAAK+B,QAAQqO,oBAEK3O,KAAK6C,MAAM6L,SAG5BE,KAAO5O,KAAKmC,IAAInC,KAAKC,MAAMyO,GAAoB,QAC/C9D,eAAiBA,OACjBiE,SAAWrM,mDAOXzD,QAAQC,MAAMkF,OAAS3F,KAAKuQ,oBAAsB,wDAShD5M,EAAS3D,KAAKyE,qDAQL+L,UACT/O,KAAKqC,IAAI0M,EAAQxQ,KAAK+B,QAAQ0O,cAAezQ,KAAK+B,QAAQ2O,oDAMzDC,OAAMC,mEACV5Q,KAAKqL,gBAIDwF,QAAU7Q,MACVA,KAAKQ,QAAQsQ,cAAc,IAAI1K,YAAYuK,YACxC,cACG,SACJC,+CASN9R,EAAIkB,KAAKqQ,cACR5L,aACE3F,MACA,OACA2F,UAAUE,KAAK,mCAShBkH,cACF7I,EAAQ,IACNuF,QAAQ,SAACyF,YAMJzK,MACF/C,QAAQC,MAAMsQ,gBAAkB,KAChCjH,SAAST,EAAYU,IAAIJ,QAAQqH,WAPlCC,EAAUjD,EAAKxI,MACf0L,EAAYlD,EAAK/D,MACjBhF,EAAW6F,EAAQwB,QAAQ0B,EAAKxN,SAAS,GACzC2Q,EAAMC,EAAKC,iBAAiBpM,MAS9BQ,EAAM6L,OAAOL,EAASE,IAAQD,IAAc7H,EAAYa,MAAMP,iBAC3DG,SAAST,EAAYU,IAAIJ,QAAQ4H,mBAKnC/L,MAAQ2L,IACRlH,MAAQZ,EAAYa,MAAMP,YAIzBjJ,EAASuB,EAAMoH,EAAYU,IAAIJ,QAAQ4H,UACtCR,gBAAkBK,EAAKI,kBAAkBxO,GAAS,OAEpDyI,OAAO9G,sCAMH,6CAUIM,UACRD,wBAEMhF,KAAKyE,mBACNzE,KAAKsQ,eACRtQ,KAAKqQ,eACDrQ,KAAK+B,QAAQqO,uBAChBpQ,KAAK+B,QAAQ8C,sDAUnB7B,EAAQ,0DADOhD,KAAKyR,sBAEblJ,QAAQ,SAACyF,YACTzK,MACFuG,SAAST,EAAYU,IAAIL,OAAOsH,UASnChD,EAAK/D,QAAUZ,EAAYa,MAAMR,gBAC9BI,SAAST,EAAYU,IAAIL,OAAO6H,mBAKlCtH,MAAQZ,EAAYa,MAAMR,WAEzBhJ,EAASuB,EAAMoH,EAAYU,IAAIL,OAAO6H,UACrCR,gBAAkBW,EAAKF,kBAAkBxO,GAAS,OAEpDyI,OAAO9G,sCAMH,4CAUN3E,KAAKoL,YAAapL,KAAKqL,aAKLP,EAAQwB,QAAQtM,KAAKQ,SAAS6E,QAG9BrF,KAAKqM,qBAIvBsF,gEASmB3D,IAAAA,KAAMtN,IAAAA,OACzBA,EAAOqQ,oBACHA,gBAAkB,WAGrB5H,EAAI6E,EAAKxI,MAAM2D,EACfC,EAAI4E,EAAKxI,MAAM4D,SAEjBpJ,KAAK+B,QAAQyN,gBACRoC,uBAAyBzI,SAAQC,eAAc4E,EAAK/D,aAEpD4H,KAAO1I,EAAI,OACX2I,IAAM1I,EAAI,MAGZ1I,8CAUWF,EAASuR,EAAcC,OACnC9O,EAAKI,EAAgB9C,EAAS,SAACgD,SAE9B,KAAMA,UAGR+H,aAAa5G,KAAKzB,kDASFlB,qBACd,SAACgQ,KACDhE,KAAKlE,SAASmI,EAAKC,wBAAwBlQ,MAC3CmQ,oBAAoBnQ,EAAKgM,KAAKxN,QAASwB,EAAKuB,SAAUyO,4CAUzDhS,KAAKwL,sBACF4G,sBAGDC,EAAWrS,KAAK+B,QAAQ8K,MAAQ,EAChCyF,EAAWtS,KAAKyL,OAAO1M,OAAS,EAElCuT,GAAYD,GAAYrS,KAAKsL,mBAC1BiH,kBAAkBvS,KAAKyL,QACnB6G,QACJE,kBAAkBxS,KAAKyL,aACvBgH,wBAMAA,uBAIFhH,OAAO1M,OAAS,4CAOLoE,mBAEXqI,iBAAkB,MAGjBkH,EAAYvP,EAAYyM,IAAI,mBAAO+C,EAAKC,uBAAuB3M,OAE5DyM,EAAW1S,KAAK6S,kBAAkB5F,KAAKjN,sDAK3CuL,aAAahD,QAAQtF,QAGrBsI,aAAaxM,OAAS,OAGtByM,iBAAkB,4CAQPsH,iBACZA,EAAQ/T,OAAQ,KACZgU,EAAWD,EAAQlD,IAAI,mBAAO3J,EAAI+H,KAAKxN,YAErCwS,iBAAiBD,EAAU,aACzBxK,QAAQ,SAACtC,KACX+H,KAAKlE,SAASmJ,EAAKf,wBAAwBjM,MAC3C1C,iEAOLgI,aAAaxM,OAAS,OACtByM,iBAAkB,OAClBiH,iEAIAS,UAAUpI,EAAQqI,UAAUC,uCAS5B3F,EAAU4F,GACVrT,KAAKoL,cAILqC,GAAaA,GAAgC,IAApBA,EAAS1O,YAC1B+L,EAAQI,gBAGhBoI,QAAQ7F,QAGR8F,eAGAC,wBAGAjR,KAAK8Q,uCAOPrR,yDAAOhC,KAAKgL,YACVhL,KAAKoL,gBAILqI,iBAED5H,EAAQ7L,KAAKsP,sBACTzN,EAAOgK,EAAO7J,QAEjB0R,QAAQ7H,QAIR8H,qBAGAC,yBAEA5I,SAAWhJ,kCAQX6R,GACD7T,KAAKoL,YACFyI,QAEErH,mBAIFjK,8CAUFoP,QAAO,+BAQVmC,OACIjI,EAAQkI,EAAYD,GAAUlE,IAAI,mBAAM,IAAIvG,EAAY9K,UAGzD0N,WAAWJ,QAGXc,gBAAgBd,QAGhBA,MAAQ7L,KAAK6L,MAAMmI,OAAOnI,QAC1BoI,yBACA9L,OAAOnI,KAAKmL,mDAOZC,WAAY,iCAOZ8I,QACA9I,WAAY,GACM,IAAnB8I,QACGvC,wCAUFoB,iBACAA,EAAShU,YAIR2O,EAAaqG,EAAYhB,GAEzBoB,EAAWzG,EACdkC,IAAI,mBAAWwE,EAAKC,iBAAiB7T,KACrC2H,OAAO,oBAAU6F,IAEdsG,EAAe,SAAfA,MACC9T,QAAQ4C,oBAAoB0H,EAAQqI,UAAUC,OAAQkB,KACtDC,cAAcJ,KAGR5L,QAAQ,SAAC/H,KACV5B,WAAWiM,YAAYrK,OAG5B0S,UAAUpI,EAAQqI,UAAUqB,SAAW9G,qBAIzCG,wCAEKsG,SAGLZ,QAAQY,QAER5R,YAIAsJ,MAAQ7L,KAAK6L,MAAM1D,OAAO,mBAASnC,EAAcmO,EAAUnG,UAC3DwF,wBAEAhT,QAAQkD,iBAAiBoH,EAAQqI,UAAUC,OAAQkB,6CAQzC9T,OACV,IAAI1B,EAAIkB,KAAK6L,MAAM9M,OAAS,EAAGD,GAAK,EAAGA,OACtCkB,KAAK6L,MAAM/M,GAAG0B,UAAYA,SACrBR,KAAK6L,MAAM/M,UAIf,4CAOFsT,yBACEhP,oBAAoB,SAAUpD,KAAKkM,gBAGrC1L,QAAQ+I,UAAUC,OAAO,gBACzBhJ,QAAQ+J,gBAAgB,cAGxBgK,qBAGA1I,MAAQ,UACR9J,QAAQgK,MAAQ,UAChBvL,QAAU,UACV+K,aAAe,UAIfF,aAAc,oCAyBN7K,EAASiU,OAEhB/T,EAASC,OAAOC,iBAAiBJ,EAAS,MAC5C6E,EAAQ9E,EAAeC,EAAS,QAASE,GACzCiF,EAASpF,EAAeC,EAAS,SAAUE,UAE3C+T,OACiBlU,EAAeC,EAAS,aAAcE,GACrCH,EAAeC,EAAS,cAAeE,MACzCH,EAAeC,EAAS,YAAaE,GAClCH,EAAeC,EAAS,eAAgBE,gEAkBzCqS,EAAUxP,OAI1BmR,EAAO3B,EAASnD,IAAI,SAACpP,OACnBC,EAAQD,EAAQC,MAChBkU,EAAWlU,EAAMmU,mBACjBC,EAAQpU,EAAMsQ,yBAGd6D,mBATK,QAUL7D,gBAVK,mCAqBJ,GAAGrE,cAGHnE,QAAQ,SAAC/H,EAAS1B,KACjB2B,MAAMmU,mBAAqBF,EAAK5V,GAAG6V,WACnClU,MAAMsQ,gBAAkB2D,EAAK5V,GAAG+V,wBAK9C/J,EAAQzB,YAAcA,EAEtByB,EAAQI,UAAY,MACpBJ,EAAQwD,qBAAuB,SAK/BxD,EAAQqI,kBACE,yBACC,mBAIXrI,EAAQrB,QAAUA,EAKlBqB,EAAQ+D,gBACD,UACA,OAIP/D,EAAQ/I,eAEC+I,EAAQI,gBAGR,WAGC,oBAGM,UAIP,iBAIM,cAIA,YAIF,YAIH,kBAIS,gBAIJ,6BAOC,kBAGC,oBAGG,mBAGH,aAKHJ,EAAQ+D,WAAWC,KAIjChE,EAAQgK,QAAUrP,EAClBqF,EAAQiK,SAAWlT,EACnBiJ,EAAQkK,gBAAkBjR,EAC1B+G,EAAQmK,wBAA0BzQ,EAClCsG,EAAQoK,iBAAmBtQ"} \ No newline at end of file +{"version":3,"file":"shuffle.min.js","sources":["../node_modules/tiny-emitter/index.js","../node_modules/array-parallel/index.js","../src/get-number.js","../src/get-number-style.js","../src/sorter.js","../src/on-transition-end.js","../src/array-max.js","../src/array-min.js","../src/layout.js","../src/hyphenate.js","../src/shuffle.js","../node_modules/matches-selector/index.js","../src/point.js","../src/rect.js","../src/classes.js","../src/shuffle-item.js","../src/computed-size.js","../node_modules/throttleit/index.js"],"sourcesContent":["function E () {\n // Keep this empty so it's easier to inherit from\n // (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3)\n}\n\nE.prototype = {\n on: function (name, callback, ctx) {\n var e = this.e || (this.e = {});\n\n (e[name] || (e[name] = [])).push({\n fn: callback,\n ctx: ctx\n });\n\n return this;\n },\n\n once: function (name, callback, ctx) {\n var self = this;\n function listener () {\n self.off(name, listener);\n callback.apply(ctx, arguments);\n };\n\n listener._ = callback\n return this.on(name, listener, ctx);\n },\n\n emit: function (name) {\n var data = [].slice.call(arguments, 1);\n var evtArr = ((this.e || (this.e = {}))[name] || []).slice();\n var i = 0;\n var len = evtArr.length;\n\n for (i; i < len; i++) {\n evtArr[i].fn.apply(evtArr[i].ctx, data);\n }\n\n return this;\n },\n\n off: function (name, callback) {\n var e = this.e || (this.e = {});\n var evts = e[name];\n var liveEvents = [];\n\n if (evts && callback) {\n for (var i = 0, len = evts.length; i < len; i++) {\n if (evts[i].fn !== callback && evts[i].fn._ !== callback)\n liveEvents.push(evts[i]);\n }\n }\n\n // Remove event from queue to prevent memory leak\n // Suggested by https://github.com/lazd\n // Ref: https://github.com/scottcorgan/tiny-emitter/commit/c6ebfaa9bc973b33d110a84a307742b7cf94c953#commitcomment-5024910\n\n (liveEvents.length)\n ? e[name] = liveEvents\n : delete e[name];\n\n return this;\n }\n};\n\nmodule.exports = E;\n","module.exports = function parallel(fns, context, callback) {\n if (!callback) {\n if (typeof context === 'function') {\n callback = context\n context = null\n } else {\n callback = noop\n }\n }\n\n var pending = fns && fns.length\n if (!pending) return callback(null, []);\n\n var finished = false\n var results = new Array(pending)\n\n fns.forEach(context ? function (fn, i) {\n fn.call(context, maybeDone(i))\n } : function (fn, i) {\n fn(maybeDone(i))\n })\n\n function maybeDone(i) {\n return function (err, result) {\n if (finished) return;\n\n if (err) {\n callback(err, results)\n finished = true\n return\n }\n\n results[i] = result\n\n if (!--pending) callback(null, results);\n }\n }\n}\n\nfunction noop() {}\n","/**\n * Always returns a numeric value, given a value. Logic from jQuery's `isNumeric`.\n * @param {*} value Possibly numeric value.\n * @return {number} `value` or zero if `value` isn't numeric.\n */\nexport default function getNumber(value) {\n return parseFloat(value) || 0;\n}\n","import getNumber from './get-number';\nimport COMPUTED_SIZE_INCLUDES_PADDING from './computed-size';\n\n/**\n * Retrieve the computed style for an element, parsed as a float.\n * @param {Element} element Element to get style for.\n * @param {string} style Style property.\n * @param {CSSStyleDeclaration} [styles] Optionally include clean styles to\n * use instead of asking for them again.\n * @return {number} The parsed computed value or zero if that fails because IE\n * will return 'auto' when the element doesn't have margins instead of\n * the computed style.\n */\nexport default function getNumberStyle(element, style,\n styles = window.getComputedStyle(element, null)) {\n let value = getNumber(styles[style]);\n\n // Support IE<=11 and W3C spec.\n if (!COMPUTED_SIZE_INCLUDES_PADDING && style === 'width') {\n value += getNumber(styles.paddingLeft) +\n getNumber(styles.paddingRight) +\n getNumber(styles.borderLeftWidth) +\n getNumber(styles.borderRightWidth);\n } else if (!COMPUTED_SIZE_INCLUDES_PADDING && style === 'height') {\n value += getNumber(styles.paddingTop) +\n getNumber(styles.paddingBottom) +\n getNumber(styles.borderTopWidth) +\n getNumber(styles.borderBottomWidth);\n }\n\n return value;\n}\n","/**\n * Fisher-Yates shuffle.\n * http://stackoverflow.com/a/962890/373422\n * https://bost.ocks.org/mike/shuffle/\n * @param {Array} array Array to shuffle.\n * @return {Array} Randomly sorted array.\n */\nfunction randomize(array) {\n let n = array.length;\n\n while (n) {\n n -= 1;\n const i = Math.floor(Math.random() * (n + 1));\n const temp = array[i];\n array[i] = array[n];\n array[n] = temp;\n }\n\n return array;\n}\n\nconst defaults = {\n // Use array.reverse() to reverse the results\n reverse: false,\n\n // Sorting function\n by: null,\n\n // If true, this will skip the sorting and return a randomized order in the array\n randomize: false,\n\n // Determines which property of each item in the array is passed to the\n // sorting method.\n key: 'element',\n};\n\n// You can return `undefined` from the `by` function to revert to DOM order.\nexport default function sorter(arr, options) {\n const opts = Object.assign({}, defaults, options);\n const original = Array.from(arr);\n let revert = false;\n\n if (!arr.length) {\n return [];\n }\n\n if (opts.randomize) {\n return randomize(arr);\n }\n\n // Sort the elements by the opts.by function.\n // If we don't have opts.by, default to DOM order\n if (typeof opts.by === 'function') {\n arr.sort((a, b) => {\n // Exit early if we already know we want to revert\n if (revert) {\n return 0;\n }\n\n const valA = opts.by(a[opts.key]);\n const valB = opts.by(b[opts.key]);\n\n // If both values are undefined, use the DOM order\n if (valA === undefined && valB === undefined) {\n revert = true;\n return 0;\n }\n\n if (valA < valB || valA === 'sortFirst' || valB === 'sortLast') {\n return -1;\n }\n\n if (valA > valB || valA === 'sortLast' || valB === 'sortFirst') {\n return 1;\n }\n\n return 0;\n });\n }\n\n // Revert to the original array if necessary\n if (revert) {\n return original;\n }\n\n if (opts.reverse) {\n arr.reverse();\n }\n\n return arr;\n}\n","const transitions = {};\nconst eventName = 'transitionend';\nlet count = 0;\n\nfunction uniqueId() {\n count += 1;\n return eventName + count;\n}\n\nexport function cancelTransitionEnd(id) {\n if (transitions[id]) {\n transitions[id].element.removeEventListener(eventName, transitions[id].listener);\n transitions[id] = null;\n return true;\n }\n\n return false;\n}\n\nexport function onTransitionEnd(element, callback) {\n const id = uniqueId();\n const listener = (evt) => {\n if (evt.currentTarget === evt.target) {\n cancelTransitionEnd(id);\n callback(evt);\n }\n };\n\n element.addEventListener(eventName, listener);\n\n transitions[id] = { element, listener };\n\n return id;\n}\n","export default function arrayMax(array) {\n return Math.max.apply(Math, array); // eslint-disable-line prefer-spread\n}\n","export default function arrayMin(array) {\n return Math.min.apply(Math, array); // eslint-disable-line prefer-spread\n}\n","import Point from './point';\nimport Rect from './rect';\nimport arrayMax from './array-max';\nimport arrayMin from './array-min';\n\n/**\n * Determine the number of columns an items spans.\n * @param {number} itemWidth Width of the item.\n * @param {number} columnWidth Width of the column (includes gutter).\n * @param {number} columns Total number of columns\n * @param {number} threshold A buffer value for the size of the column to fit.\n * @return {number}\n */\nexport function getColumnSpan(itemWidth, columnWidth, columns, threshold) {\n let columnSpan = itemWidth / columnWidth;\n\n // If the difference between the rounded column span number and the\n // calculated column span number is really small, round the number to\n // make it fit.\n if (Math.abs(Math.round(columnSpan) - columnSpan) < threshold) {\n // e.g. columnSpan = 4.0089945390298745\n columnSpan = Math.round(columnSpan);\n }\n\n // Ensure the column span is not more than the amount of columns in the whole layout.\n return Math.min(Math.ceil(columnSpan), columns);\n}\n\n/**\n * Retrieves the column set to use for placement.\n * @param {number} columnSpan The number of columns this current item spans.\n * @param {number} columns The total columns in the grid.\n * @return {Array.} An array of numbers represeting the column set.\n */\nexport function getAvailablePositions(positions, columnSpan, columns) {\n // The item spans only one column.\n if (columnSpan === 1) {\n return positions;\n }\n\n // The item spans more than one column, figure out how many different\n // places it could fit horizontally.\n // The group count is the number of places within the positions this block\n // could fit, ignoring the current positions of items.\n // Imagine a 2 column brick as the second item in a 4 column grid with\n // 10px height each. Find the places it would fit:\n // [20, 10, 10, 0]\n // | | |\n // * * *\n //\n // Then take the places which fit and get the bigger of the two:\n // max([20, 10]), max([10, 10]), max([10, 0]) = [20, 10, 0]\n //\n // Next, find the first smallest number (the short column).\n // [20, 10, 0]\n // |\n // *\n //\n // And that's where it should be placed!\n //\n // Another example where the second column's item extends past the first:\n // [10, 20, 10, 0] => [20, 20, 10] => 10\n const available = [];\n\n // For how many possible positions for this item there are.\n for (let i = 0; i <= columns - columnSpan; i++) {\n // Find the bigger value for each place it could fit.\n available.push(arrayMax(positions.slice(i, i + columnSpan)));\n }\n\n return available;\n}\n\n/**\n * Find index of short column, the first from the left where this item will go.\n *\n * @param {Array.} positions The array to search for the smallest number.\n * @param {number} buffer Optional buffer which is very useful when the height\n * is a percentage of the width.\n * @return {number} Index of the short column.\n */\nexport function getShortColumn(positions, buffer) {\n const minPosition = arrayMin(positions);\n for (let i = 0, len = positions.length; i < len; i++) {\n if (positions[i] >= minPosition - buffer && positions[i] <= minPosition + buffer) {\n return i;\n }\n }\n\n return 0;\n}\n\n/**\n * Determine the location of the next item, based on its size.\n * @param {Object} itemSize Object with width and height.\n * @param {Array.} positions Positions of the other current items.\n * @param {number} gridSize The column width or row height.\n * @param {number} total The total number of columns or rows.\n * @param {number} threshold Buffer value for the column to fit.\n * @param {number} buffer Vertical buffer for the height of items.\n * @return {Point}\n */\nexport function getItemPosition({ itemSize, positions, gridSize, total, threshold, buffer }) {\n const span = getColumnSpan(itemSize.width, gridSize, total, threshold);\n const setY = getAvailablePositions(positions, span, total);\n const shortColumnIndex = getShortColumn(setY, buffer);\n\n // Position the item\n const point = new Point(gridSize * shortColumnIndex, setY[shortColumnIndex]);\n\n // Update the columns array with the new values for each column.\n // e.g. before the update the columns could be [250, 0, 0, 0] for an item\n // which spans 2 columns. After it would be [250, itemHeight, itemHeight, 0].\n const setHeight = setY[shortColumnIndex] + itemSize.height;\n for (let i = 0; i < span; i++) {\n positions[shortColumnIndex + i] = setHeight;\n }\n\n return point;\n}\n\n/**\n * This method attempts to center items. This method could potentially be slow\n * with a large number of items because it must place items, then check every\n * previous item to ensure there is no overlap.\n * @param {Array.} itemRects Item data objects.\n * @param {number} containerWidth Width of the containing element.\n * @return {Array.}\n */\nexport function getCenteredPositions(itemRects, containerWidth) {\n const rowMap = {};\n\n // Populate rows by their offset because items could jump between rows like:\n // a c\n // bbb\n itemRects.forEach((itemRect) => {\n if (rowMap[itemRect.top]) {\n // Push the point to the last row array.\n rowMap[itemRect.top].push(itemRect);\n } else {\n // Start of a new row.\n rowMap[itemRect.top] = [itemRect];\n }\n });\n\n // For each row, find the end of the last item, then calculate\n // the remaining space by dividing it by 2. Then add that\n // offset to the x position of each point.\n let rects = [];\n const rows = [];\n const centeredRows = [];\n Object.keys(rowMap).forEach((key) => {\n const itemRects = rowMap[key];\n rows.push(itemRects);\n const lastItem = itemRects[itemRects.length - 1];\n const end = lastItem.left + lastItem.width;\n const offset = Math.round((containerWidth - end) / 2);\n\n let finalRects = itemRects;\n let canMove = false;\n if (offset > 0) {\n const newRects = [];\n canMove = itemRects.every((r) => {\n const newRect = new Rect(r.left + offset, r.top, r.width, r.height, r.id);\n\n // Check all current rects to make sure none overlap.\n const noOverlap = !rects.some(r => Rect.intersects(newRect, r));\n\n newRects.push(newRect);\n return noOverlap;\n });\n\n // If none of the rectangles overlapped, the whole group can be centered.\n if (canMove) {\n finalRects = newRects;\n }\n }\n\n // If the items are not going to be offset, ensure that the original\n // placement for this row will not overlap previous rows (row-spanning\n // elements could be in the way).\n if (!canMove) {\n let intersectingRect;\n const hasOverlap = itemRects.some(itemRect => rects.some((r) => {\n const intersects = Rect.intersects(itemRect, r);\n if (intersects) {\n intersectingRect = r;\n }\n return intersects;\n }));\n\n // If there is any overlap, replace the overlapping row with the original.\n if (hasOverlap) {\n const rowIndex = centeredRows.findIndex(items => items.includes(intersectingRect));\n centeredRows.splice(rowIndex, 1, rows[rowIndex]);\n }\n }\n\n rects = rects.concat(finalRects);\n centeredRows.push(finalRects);\n });\n\n // Reduce array of arrays to a single array of points.\n // https://stackoverflow.com/a/10865042/373422\n // Then reset sort back to how the items were passed to this method.\n // Remove the wrapper object with index, map to a Point.\n return [].concat.apply([], centeredRows) // eslint-disable-line prefer-spread\n .sort((a, b) => (a.id - b.id))\n .map(itemRect => new Point(itemRect.left, itemRect.top));\n}\n","/**\n * Hyphenates a javascript style string to a css one. For example:\n * MozBoxSizing -> -moz-box-sizing.\n * @param {string} str The string to hyphenate.\n * @return {string} The hyphenated string.\n */\nexport default function hyphenate(str) {\n return str.replace(/([A-Z])/g, (str, m1) => `-${m1.toLowerCase()}`);\n}\n","import TinyEmitter from 'tiny-emitter';\nimport matches from 'matches-selector';\nimport throttle from 'throttleit';\nimport parallel from 'array-parallel';\n\nimport Point from './point';\nimport Rect from './rect';\nimport ShuffleItem from './shuffle-item';\nimport Classes from './classes';\nimport getNumberStyle from './get-number-style';\nimport sorter from './sorter';\nimport { onTransitionEnd, cancelTransitionEnd } from './on-transition-end';\nimport {\n getItemPosition,\n getColumnSpan,\n getAvailablePositions,\n getShortColumn,\n getCenteredPositions,\n} from './layout';\nimport arrayMax from './array-max';\nimport hyphenate from './hyphenate';\n\nfunction arrayUnique(x) {\n return Array.from(new Set(x));\n}\n\n// Used for unique instance variables\nlet id = 0;\n\nclass Shuffle extends TinyEmitter {\n\n /**\n * Categorize, sort, and filter a responsive grid of items.\n *\n * @param {Element} element An element which is the parent container for the grid items.\n * @param {Object} [options=Shuffle.options] Options object.\n * @constructor\n */\n constructor(element, options = {}) {\n super();\n this.options = Object.assign({}, Shuffle.options, options);\n\n this.lastSort = {};\n this.group = Shuffle.ALL_ITEMS;\n this.lastFilter = Shuffle.ALL_ITEMS;\n this.isEnabled = true;\n this.isDestroyed = false;\n this.isInitialized = false;\n this._transitions = [];\n this.isTransitioning = false;\n this._queue = [];\n\n const el = this._getElementOption(element);\n\n if (!el) {\n throw new TypeError('Shuffle needs to be initialized with an element.');\n }\n\n this.element = el;\n this.id = 'shuffle_' + id;\n id += 1;\n\n this._init();\n this.isInitialized = true;\n }\n\n _init() {\n this.items = this._getItems();\n\n this.options.sizer = this._getElementOption(this.options.sizer);\n\n // Add class and invalidate styles\n this.element.classList.add(Shuffle.Classes.BASE);\n\n // Set initial css for each item\n this._initItems(this.items);\n\n // Bind resize events\n this._onResize = this._getResizeFunction();\n window.addEventListener('resize', this._onResize);\n\n // If the page has not already emitted the `load` event, call layout on load.\n // This avoids layout issues caused by images and fonts loading after the\n // instance has been initialized.\n if (document.readyState !== 'complete') {\n const layout = this.layout.bind(this);\n window.addEventListener('load', function onLoad() {\n window.removeEventListener('load', onLoad);\n layout();\n });\n }\n\n // Get container css all in one request. Causes reflow\n const containerCss = window.getComputedStyle(this.element, null);\n const containerWidth = Shuffle.getSize(this.element).width;\n\n // Add styles to the container if it doesn't have them.\n this._validateStyles(containerCss);\n\n // We already got the container's width above, no need to cause another\n // reflow getting it again... Calculate the number of columns there will be\n this._setColumns(containerWidth);\n\n // Kick off!\n this.filter(this.options.group, this.options.initialSort);\n\n // The shuffle items haven't had transitions set on them yet so the user\n // doesn't see the first layout. Set them now that the first layout is done.\n // First, however, a synchronous layout must be caused for the previous\n // styles to be applied without transitions.\n this.element.offsetWidth; // eslint-disable-line no-unused-expressions\n this.setItemTransitions(this.items);\n this.element.style.transition = `height ${this.options.speed}ms ${this.options.easing}`;\n }\n\n /**\n * Returns a throttled and proxied function for the resize handler.\n * @return {function}\n * @private\n */\n _getResizeFunction() {\n const resizeFunction = this._handleResize.bind(this);\n return this.options.throttle ?\n this.options.throttle(resizeFunction, this.options.throttleTime) :\n resizeFunction;\n }\n\n /**\n * Retrieve an element from an option.\n * @param {string|jQuery|Element} option The option to check.\n * @return {?Element} The plain element or null.\n * @private\n */\n _getElementOption(option) {\n // If column width is a string, treat is as a selector and search for the\n // sizer element within the outermost container\n if (typeof option === 'string') {\n return this.element.querySelector(option);\n\n // Check for an element\n } else if (option && option.nodeType && option.nodeType === 1) {\n return option;\n\n // Check for jQuery object\n } else if (option && option.jquery) {\n return option[0];\n }\n\n return null;\n }\n\n /**\n * Ensures the shuffle container has the css styles it needs applied to it.\n * @param {Object} styles Key value pairs for position and overflow.\n * @private\n */\n _validateStyles(styles) {\n // Position cannot be static.\n if (styles.position === 'static') {\n this.element.style.position = 'relative';\n }\n\n // Overflow has to be hidden.\n if (styles.overflow !== 'hidden') {\n this.element.style.overflow = 'hidden';\n }\n }\n\n /**\n * Filter the elements by a category.\n * @param {string|string[]|function(Element):boolean} [category] Category to\n * filter by. If it's given, the last category will be used to filter the items.\n * @param {Array} [collection] Optionally filter a collection. Defaults to\n * all the items.\n * @return {{visible: ShuffleItem[], hidden: ShuffleItem[]}}\n * @private\n */\n _filter(category = this.lastFilter, collection = this.items) {\n const set = this._getFilteredSets(category, collection);\n\n // Individually add/remove hidden/visible classes\n this._toggleFilterClasses(set);\n\n // Save the last filter in case elements are appended.\n this.lastFilter = category;\n\n // This is saved mainly because providing a filter function (like searching)\n // will overwrite the `lastFilter` property every time its called.\n if (typeof category === 'string') {\n this.group = category;\n }\n\n return set;\n }\n\n /**\n * Returns an object containing the visible and hidden elements.\n * @param {string|string[]|function(Element):boolean} category Category or function to filter by.\n * @param {ShuffleItem[]} items A collection of items to filter.\n * @return {{visible: ShuffleItem[], hidden: ShuffleItem[]}}\n * @private\n */\n _getFilteredSets(category, items) {\n let visible = [];\n const hidden = [];\n\n // category === 'all', add visible class to everything\n if (category === Shuffle.ALL_ITEMS) {\n visible = items;\n\n // Loop through each item and use provided function to determine\n // whether to hide it or not.\n } else {\n items.forEach((item) => {\n if (this._doesPassFilter(category, item.element)) {\n visible.push(item);\n } else {\n hidden.push(item);\n }\n });\n }\n\n return {\n visible,\n hidden,\n };\n }\n\n /**\n * Test an item to see if it passes a category.\n * @param {string|string[]|function():boolean} category Category or function to filter by.\n * @param {Element} element An element to test.\n * @return {boolean} Whether it passes the category/filter.\n * @private\n */\n _doesPassFilter(category, element) {\n if (typeof category === 'function') {\n return category.call(element, element, this);\n }\n\n // Check each element's data-groups attribute against the given category.\n const attr = element.getAttribute('data-' + Shuffle.FILTER_ATTRIBUTE_KEY);\n const keys = this.options.delimeter ?\n attr.split(this.options.delimeter) :\n JSON.parse(attr);\n\n function testCategory(category) {\n return keys.includes(category);\n }\n\n if (Array.isArray(category)) {\n if (this.options.filterMode === Shuffle.FilterMode.ANY) {\n return category.some(testCategory);\n }\n return category.every(testCategory);\n }\n\n return keys.includes(category);\n }\n\n /**\n * Toggles the visible and hidden class names.\n * @param {{visible, hidden}} Object with visible and hidden arrays.\n * @private\n */\n _toggleFilterClasses({ visible, hidden }) {\n visible.forEach((item) => {\n item.show();\n });\n\n hidden.forEach((item) => {\n item.hide();\n });\n }\n\n /**\n * Set the initial css for each item\n * @param {ShuffleItem[]} items Set to initialize.\n * @private\n */\n _initItems(items) {\n items.forEach((item) => {\n item.init();\n });\n }\n\n /**\n * Remove element reference and styles.\n * @param {ShuffleItem[]} items Set to dispose.\n * @private\n */\n _disposeItems(items) {\n items.forEach((item) => {\n item.dispose();\n });\n }\n\n /**\n * Updates the visible item count.\n * @private\n */\n _updateItemCount() {\n this.visibleItems = this._getFilteredItems().length;\n }\n\n /**\n * Sets css transform transition on a group of elements. This is not executed\n * at the same time as `item.init` so that transitions don't occur upon\n * initialization of a new Shuffle instance.\n * @param {ShuffleItem[]} items Shuffle items to set transitions on.\n * @protected\n */\n setItemTransitions(items) {\n const speed = this.options.speed;\n const easing = this.options.easing;\n const positionProps = this.options.useTransforms ? ['transform'] : ['top', 'left'];\n\n // Allow users to transtion other properties if they exist in the `before`\n // css mapping of the shuffle item.\n const properties = positionProps.concat(\n Object.keys(ShuffleItem.Css.HIDDEN.before).map(k => hyphenate(k)),\n ).join();\n\n items.forEach((item) => {\n item.element.style.transitionDuration = speed + 'ms';\n item.element.style.transitionTimingFunction = easing;\n item.element.style.transitionProperty = properties;\n });\n }\n\n _getItems() {\n return Array.from(this.element.children)\n .filter(el => matches(el, this.options.itemSelector))\n .map(el => new ShuffleItem(el));\n }\n\n /**\n * When new elements are added to the shuffle container, update the array of\n * items because that is the order `_layout` calls them.\n * @param {ShuffleItem[]} items Items to track.\n * @return {Shuffle[]}\n */\n _mergeNewItems(items) {\n const children = Array.from(this.element.children);\n return sorter(this.items.concat(items), {\n by(element) {\n return children.indexOf(element);\n },\n });\n }\n\n _getFilteredItems() {\n return this.items.filter(item => item.isVisible);\n }\n\n _getConcealedItems() {\n return this.items.filter(item => !item.isVisible);\n }\n\n /**\n * Returns the column size, based on column width and sizer options.\n * @param {number} containerWidth Size of the parent container.\n * @param {number} gutterSize Size of the gutters.\n * @return {number}\n * @private\n */\n _getColumnSize(containerWidth, gutterSize) {\n let size;\n\n // If the columnWidth property is a function, then the grid is fluid\n if (typeof this.options.columnWidth === 'function') {\n size = this.options.columnWidth(containerWidth);\n\n // columnWidth option isn't a function, are they using a sizing element?\n } else if (this.options.sizer) {\n size = Shuffle.getSize(this.options.sizer).width;\n\n // if not, how about the explicitly set option?\n } else if (this.options.columnWidth) {\n size = this.options.columnWidth;\n\n // or use the size of the first item\n } else if (this.items.length > 0) {\n size = Shuffle.getSize(this.items[0].element, true).width;\n\n // if there's no items, use size of container\n } else {\n size = containerWidth;\n }\n\n // Don't let them set a column width of zero.\n if (size === 0) {\n size = containerWidth;\n }\n\n return size + gutterSize;\n }\n\n /**\n * Returns the gutter size, based on gutter width and sizer options.\n * @param {number} containerWidth Size of the parent container.\n * @return {number}\n * @private\n */\n _getGutterSize(containerWidth) {\n let size;\n if (typeof this.options.gutterWidth === 'function') {\n size = this.options.gutterWidth(containerWidth);\n } else if (this.options.sizer) {\n size = getNumberStyle(this.options.sizer, 'marginLeft');\n } else {\n size = this.options.gutterWidth;\n }\n\n return size;\n }\n\n /**\n * Calculate the number of columns to be used. Gets css if using sizer element.\n * @param {number} [containerWidth] Optionally specify a container width if\n * it's already available.\n */\n _setColumns(containerWidth = Shuffle.getSize(this.element).width) {\n const gutter = this._getGutterSize(containerWidth);\n const columnWidth = this._getColumnSize(containerWidth, gutter);\n let calculatedColumns = (containerWidth + gutter) / columnWidth;\n\n // Widths given from getStyles are not precise enough...\n if (Math.abs(Math.round(calculatedColumns) - calculatedColumns) <\n this.options.columnThreshold) {\n // e.g. calculatedColumns = 11.998876\n calculatedColumns = Math.round(calculatedColumns);\n }\n\n this.cols = Math.max(Math.floor(calculatedColumns), 1);\n this.containerWidth = containerWidth;\n this.colWidth = columnWidth;\n }\n\n /**\n * Adjust the height of the grid\n */\n _setContainerSize() {\n this.element.style.height = this._getContainerSize() + 'px';\n }\n\n /**\n * Based on the column heights, it returns the biggest one.\n * @return {number}\n * @private\n */\n _getContainerSize() {\n return arrayMax(this.positions);\n }\n\n /**\n * Get the clamped stagger amount.\n * @param {number} index Index of the item to be staggered.\n * @return {number}\n */\n _getStaggerAmount(index) {\n return Math.min(index * this.options.staggerAmount, this.options.staggerAmountMax);\n }\n\n /**\n * Emit an event from this instance.\n * @param {string} name Event name.\n * @param {Object} [data={}] Optional object data.\n */\n _dispatch(name, data = {}) {\n if (this.isDestroyed) {\n return;\n }\n\n data.shuffle = this;\n this.emit(name, data);\n }\n\n /**\n * Zeros out the y columns array, which is used to determine item placement.\n * @private\n */\n _resetCols() {\n let i = this.cols;\n this.positions = [];\n while (i) {\n i -= 1;\n this.positions.push(0);\n }\n }\n\n /**\n * Loops through each item that should be shown and calculates the x, y position.\n * @param {ShuffleItem[]} items Array of items that will be shown/layed\n * out in order in their array.\n */\n _layout(items) {\n const itemPositions = this._getNextPositions(items);\n\n let count = 0;\n items.forEach((item, i) => {\n function callback() {\n item.applyCss(ShuffleItem.Css.VISIBLE.after);\n }\n\n // If the item will not change its position, do not add it to the render\n // queue. Transitions don't fire when setting a property to the same value.\n if (Point.equals(item.point, itemPositions[i]) && !item.isHidden) {\n item.applyCss(ShuffleItem.Css.VISIBLE.before);\n callback();\n return;\n }\n\n item.point = itemPositions[i];\n item.scale = ShuffleItem.Scale.VISIBLE;\n item.isHidden = false;\n\n // Clone the object so that the `before` object isn't modified when the\n // transition delay is added.\n const styles = this.getStylesForTransition(item, ShuffleItem.Css.VISIBLE.before);\n styles.transitionDelay = this._getStaggerAmount(count) + 'ms';\n\n this._queue.push({\n item,\n styles,\n callback,\n });\n\n count += 1;\n });\n }\n\n /**\n * Return an array of Point instances representing the future positions of\n * each item.\n * @param {ShuffleItem[]} items Array of sorted shuffle items.\n * @return {Point[]}\n * @private\n */\n _getNextPositions(items) {\n // If position data is going to be changed, add the item's size to the\n // transformer to allow for calculations.\n if (this.options.isCentered) {\n const itemsData = items.map((item, i) => {\n const itemSize = Shuffle.getSize(item.element, true);\n const point = this._getItemPosition(itemSize);\n return new Rect(point.x, point.y, itemSize.width, itemSize.height, i);\n });\n\n return this.getTransformedPositions(itemsData, this.containerWidth);\n }\n\n // If no transforms are going to happen, simply return an array of the\n // future points of each item.\n return items.map(item => this._getItemPosition(Shuffle.getSize(item.element, true)));\n }\n\n /**\n * Determine the location of the next item, based on its size.\n * @param {{width: number, height: number}} itemSize Object with width and height.\n * @return {Point}\n * @private\n */\n _getItemPosition(itemSize) {\n return getItemPosition({\n itemSize,\n positions: this.positions,\n gridSize: this.colWidth,\n total: this.cols,\n threshold: this.options.columnThreshold,\n buffer: this.options.buffer,\n });\n }\n\n /**\n * Mutate positions before they're applied.\n * @param {Rect[]} itemRects Item data objects.\n * @param {number} containerWidth Width of the containing element.\n * @return {Point[]}\n * @protected\n */\n getTransformedPositions(itemRects, containerWidth) {\n return getCenteredPositions(itemRects, containerWidth);\n }\n\n /**\n * Hides the elements that don't match our filter.\n * @param {ShuffleItem[]} collection Collection to shrink.\n * @private\n */\n _shrink(collection = this._getConcealedItems()) {\n let count = 0;\n collection.forEach((item) => {\n function callback() {\n item.applyCss(ShuffleItem.Css.HIDDEN.after);\n }\n\n // Continuing would add a transitionend event listener to the element, but\n // that listener would not execute because the transform and opacity would\n // stay the same.\n // The callback is executed here because it is not guaranteed to be called\n // after the transitionend event because the transitionend could be\n // canceled if another animation starts.\n if (item.isHidden) {\n item.applyCss(ShuffleItem.Css.HIDDEN.before);\n callback();\n return;\n }\n\n item.scale = ShuffleItem.Scale.HIDDEN;\n item.isHidden = true;\n\n const styles = this.getStylesForTransition(item, ShuffleItem.Css.HIDDEN.before);\n styles.transitionDelay = this._getStaggerAmount(count) + 'ms';\n\n this._queue.push({\n item,\n styles,\n callback,\n });\n\n count += 1;\n });\n }\n\n /**\n * Resize handler.\n * @private\n */\n _handleResize() {\n // If shuffle is disabled, destroyed, don't do anything\n if (!this.isEnabled || this.isDestroyed) {\n return;\n }\n\n this.update();\n }\n\n /**\n * Returns styles which will be applied to the an item for a transition.\n * @param {ShuffleItem} item Item to get styles for. Should have updated\n * scale and point properties.\n * @param {Object} styleObject Extra styles that will be used in the transition.\n * @return {!Object} Transforms for transitions, left/top for animate.\n * @protected\n */\n getStylesForTransition(item, styleObject) {\n // Clone the object to avoid mutating the original.\n const styles = Object.assign({}, styleObject);\n\n if (this.options.useTransforms) {\n styles.transform = `translate(${item.point.x}px, ${item.point.y}px) scale(${item.scale})`;\n } else {\n styles.left = item.point.x + 'px';\n styles.top = item.point.y + 'px';\n }\n\n return styles;\n }\n\n /**\n * Listen for the transition end on an element and execute the itemCallback\n * when it finishes.\n * @param {Element} element Element to listen on.\n * @param {function} itemCallback Callback for the item.\n * @param {function} done Callback to notify `parallel` that this one is done.\n */\n _whenTransitionDone(element, itemCallback, done) {\n const id = onTransitionEnd(element, (evt) => {\n itemCallback();\n done(null, evt);\n });\n\n this._transitions.push(id);\n }\n\n /**\n * Return a function which will set CSS styles and call the `done` function\n * when (if) the transition finishes.\n * @param {Object} opts Transition object.\n * @return {function} A function to be called with a `done` function.\n */\n _getTransitionFunction(opts) {\n return (done) => {\n opts.item.applyCss(opts.styles);\n this._whenTransitionDone(opts.item.element, opts.callback, done);\n };\n }\n\n /**\n * Execute the styles gathered in the style queue. This applies styles to elements,\n * triggering transitions.\n * @private\n */\n _processQueue() {\n if (this.isTransitioning) {\n this._cancelMovement();\n }\n\n const hasSpeed = this.options.speed > 0;\n const hasQueue = this._queue.length > 0;\n\n if (hasQueue && hasSpeed && this.isInitialized) {\n this._startTransitions(this._queue);\n } else if (hasQueue) {\n this._styleImmediately(this._queue);\n this._dispatch(Shuffle.EventType.LAYOUT);\n\n // A call to layout happened, but none of the newly visible items will\n // change position or the transition duration is zero, which will not trigger\n // the transitionend event.\n } else {\n this._dispatch(Shuffle.EventType.LAYOUT);\n }\n\n // Remove everything in the style queue\n this._queue.length = 0;\n }\n\n /**\n * Wait for each transition to finish, the emit the layout event.\n * @param {Object[]} transitions Array of transition objects.\n */\n _startTransitions(transitions) {\n // Set flag that shuffle is currently in motion.\n this.isTransitioning = true;\n\n // Create an array of functions to be called.\n const callbacks = transitions.map(obj => this._getTransitionFunction(obj));\n\n parallel(callbacks, this._movementFinished.bind(this));\n }\n\n _cancelMovement() {\n // Remove the transition end event for each listener.\n this._transitions.forEach(cancelTransitionEnd);\n\n // Reset the array.\n this._transitions.length = 0;\n\n // Show it's no longer active.\n this.isTransitioning = false;\n }\n\n /**\n * Apply styles without a transition.\n * @param {Object[]} objects Array of transition objects.\n * @private\n */\n _styleImmediately(objects) {\n if (objects.length) {\n const elements = objects.map(obj => obj.item.element);\n\n Shuffle._skipTransitions(elements, () => {\n objects.forEach((obj) => {\n obj.item.applyCss(obj.styles);\n obj.callback();\n });\n });\n }\n }\n\n _movementFinished() {\n this._transitions.length = 0;\n this.isTransitioning = false;\n this._dispatch(Shuffle.EventType.LAYOUT);\n }\n\n /**\n * The magic. This is what makes the plugin 'shuffle'\n * @param {string|string[]|function(Element):boolean} [category] Category to filter by.\n * Can be a function, string, or array of strings.\n * @param {Object} [sortObj] A sort object which can sort the visible set\n */\n filter(category, sortObj) {\n if (!this.isEnabled) {\n return;\n }\n\n if (!category || (category && category.length === 0)) {\n category = Shuffle.ALL_ITEMS; // eslint-disable-line no-param-reassign\n }\n\n this._filter(category);\n\n // Shrink each hidden item\n this._shrink();\n\n // How many visible elements?\n this._updateItemCount();\n\n // Update transforms on visible elements so they will animate to their new positions.\n this.sort(sortObj);\n }\n\n /**\n * Gets the visible elements, sorts them, and passes them to layout.\n * @param {Object} [sortOptions] The options object to pass to `sorter`.\n */\n sort(sortOptions = this.lastSort) {\n if (!this.isEnabled) {\n return;\n }\n\n this._resetCols();\n\n const items = sorter(this._getFilteredItems(), sortOptions);\n\n this._layout(items);\n\n // `_layout` always happens after `_shrink`, so it's safe to process the style\n // queue here with styles from the shrink method.\n this._processQueue();\n\n // Adjust the height of the container.\n this._setContainerSize();\n\n this.lastSort = sortOptions;\n }\n\n /**\n * Reposition everything.\n * @param {boolean} [isOnlyLayout=false] If true, column and gutter widths won't be recalculated.\n */\n update(isOnlyLayout = false) {\n if (this.isEnabled) {\n if (!isOnlyLayout) {\n // Get updated colCount\n this._setColumns();\n }\n\n // Layout items\n this.sort();\n }\n }\n\n /**\n * Use this instead of `update()` if you don't need the columns and gutters updated\n * Maybe an image inside `shuffle` loaded (and now has a height), which means calculations\n * could be off.\n */\n layout() {\n this.update(true);\n }\n\n /**\n * New items have been appended to shuffle. Mix them in with the current\n * filter or sort status.\n * @param {Element[]} newItems Collection of new items.\n */\n add(newItems) {\n const items = arrayUnique(newItems).map(el => new ShuffleItem(el));\n\n // Add classes and set initial positions.\n this._initItems(items);\n\n // Determine which items will go with the current filter.\n this._resetCols();\n const newItemSet = this._filter(this.lastFilter, items);\n const willBeVisible = this._mergeNewItems(newItemSet.visible);\n const sortedVisibleItems = sorter(willBeVisible, this.lastSort);\n\n // Layout all items again so that new items get positions.\n // Synchonously apply positions.\n const itemPositions = this._getNextPositions(sortedVisibleItems);\n sortedVisibleItems.forEach((item, i) => {\n if (newItemSet.visible.includes(item)) {\n item.point = itemPositions[i];\n item.scale = ShuffleItem.Scale.HIDDEN;\n item.isHidden = true;\n item.applyCss(ShuffleItem.Css.HIDDEN.before);\n item.applyCss(ShuffleItem.Css.HIDDEN.after);\n item.applyCss(this.getStylesForTransition(item, {}));\n }\n });\n\n // Cause layout so that the styles above are applied.\n this.element.offsetWidth; // eslint-disable-line no-unused-expressions\n\n // Add transition to each item.\n this.setItemTransitions(items);\n\n // Update the list of items.\n this.items = this._mergeNewItems(items);\n\n // Update layout/visibility of new and old items.\n this.filter(this.lastFilter);\n }\n\n /**\n * Disables shuffle from updating dimensions and layout on resize\n */\n disable() {\n this.isEnabled = false;\n }\n\n /**\n * Enables shuffle again\n * @param {boolean} [isUpdateLayout=true] if undefined, shuffle will update columns and gutters\n */\n enable(isUpdateLayout = true) {\n this.isEnabled = true;\n if (isUpdateLayout) {\n this.update();\n }\n }\n\n /**\n * Remove 1 or more shuffle items.\n * @param {Element[]} elements An array containing one or more\n * elements in shuffle\n * @return {Shuffle} The shuffle instance.\n */\n remove(elements) {\n if (!elements.length) {\n return;\n }\n\n const collection = arrayUnique(elements);\n\n const oldItems = collection\n .map(element => this.getItemByElement(element))\n .filter(item => !!item);\n\n const handleLayout = () => {\n this._disposeItems(oldItems);\n\n // Remove the collection in the callback\n collection.forEach((element) => {\n element.parentNode.removeChild(element);\n });\n\n this._dispatch(Shuffle.EventType.REMOVED, { collection });\n };\n\n // Hide collection first.\n this._toggleFilterClasses({\n visible: [],\n hidden: oldItems,\n });\n\n this._shrink(oldItems);\n\n this.sort();\n\n // Update the list of items here because `remove` could be called again\n // with an item that is in the process of being removed.\n this.items = this.items.filter(item => !oldItems.includes(item));\n this._updateItemCount();\n\n this.once(Shuffle.EventType.LAYOUT, handleLayout);\n }\n\n /**\n * Retrieve a shuffle item by its element.\n * @param {Element} element Element to look for.\n * @return {?ShuffleItem} A shuffle item or undefined if it's not found.\n */\n getItemByElement(element) {\n return this.items.find(item => item.element === element);\n }\n\n /**\n * Dump the elements currently stored and reinitialize all child elements which\n * match the `itemSelector`.\n */\n resetItems() {\n // Remove refs to current items.\n this._disposeItems(this.items);\n this.isInitialized = false;\n\n // Find new items in the DOM.\n this.items = this._getItems();\n\n // Set initial styles on the new items.\n this._initItems(this.items);\n\n this.once(Shuffle.EventType.LAYOUT, () => {\n // Add transition to each item.\n this.setItemTransitions(this.items);\n this.isInitialized = true;\n });\n\n // Lay out all items.\n this.filter(this.lastFilter);\n }\n\n /**\n * Destroys shuffle, removes events, styles, and classes\n */\n destroy() {\n this._cancelMovement();\n window.removeEventListener('resize', this._onResize);\n\n // Reset container styles\n this.element.classList.remove('shuffle');\n this.element.removeAttribute('style');\n\n // Reset individual item styles\n this._disposeItems(this.items);\n\n this.items.length = 0;\n this._transitions.length = 0;\n\n // Null DOM references\n this.options.sizer = null;\n this.element = null;\n\n // Set a flag so if a debounced resize has been triggered,\n // it can first check if it is actually isDestroyed and not doing anything\n this.isDestroyed = true;\n this.isEnabled = false;\n }\n\n /**\n * Returns the outer width of an element, optionally including its margins.\n *\n * There are a few different methods for getting the width of an element, none of\n * which work perfectly for all Shuffle's use cases.\n *\n * 1. getBoundingClientRect() `left` and `right` properties.\n * - Accounts for transform scaled elements, making it useless for Shuffle\n * elements which have shrunk.\n * 2. The `offsetWidth` property.\n * - This value stays the same regardless of the elements transform property,\n * however, it does not return subpixel values.\n * 3. getComputedStyle()\n * - This works great Chrome, Firefox, Safari, but IE<=11 does not include\n * padding and border when box-sizing: border-box is set, requiring a feature\n * test and extra work to add the padding back for IE and other browsers which\n * follow the W3C spec here.\n *\n * @param {Element} element The element.\n * @param {boolean} [includeMargins=false] Whether to include margins.\n * @return {{width: number, height: number}} The width and height.\n */\n static getSize(element, includeMargins = false) {\n // Store the styles so that they can be used by others without asking for it again.\n const styles = window.getComputedStyle(element, null);\n let width = getNumberStyle(element, 'width', styles);\n let height = getNumberStyle(element, 'height', styles);\n\n if (includeMargins) {\n const marginLeft = getNumberStyle(element, 'marginLeft', styles);\n const marginRight = getNumberStyle(element, 'marginRight', styles);\n const marginTop = getNumberStyle(element, 'marginTop', styles);\n const marginBottom = getNumberStyle(element, 'marginBottom', styles);\n width += marginLeft + marginRight;\n height += marginTop + marginBottom;\n }\n\n return {\n width,\n height,\n };\n }\n\n /**\n * Change a property or execute a function which will not have a transition\n * @param {Element[]} elements DOM elements that won't be transitioned.\n * @param {function} callback A function which will be called while transition\n * is set to 0ms.\n * @private\n */\n static _skipTransitions(elements, callback) {\n const zero = '0ms';\n\n // Save current duration and delay.\n const data = elements.map((element) => {\n const style = element.style;\n const duration = style.transitionDuration;\n const delay = style.transitionDelay;\n\n // Set the duration to zero so it happens immediately\n style.transitionDuration = zero;\n style.transitionDelay = zero;\n\n return {\n duration,\n delay,\n };\n });\n\n callback();\n\n // Cause forced synchronous layout.\n elements[0].offsetWidth; // eslint-disable-line no-unused-expressions\n\n // Put the duration back\n elements.forEach((element, i) => {\n element.style.transitionDuration = data[i].duration;\n element.style.transitionDelay = data[i].delay;\n });\n }\n}\n\nShuffle.ShuffleItem = ShuffleItem;\n\nShuffle.ALL_ITEMS = 'all';\nShuffle.FILTER_ATTRIBUTE_KEY = 'groups';\n\n/** @enum {string} */\nShuffle.EventType = {\n LAYOUT: 'shuffle:layout',\n REMOVED: 'shuffle:removed',\n};\n\n/** @enum {string} */\nShuffle.Classes = Classes;\n\n/** @enum {string} */\nShuffle.FilterMode = {\n ANY: 'any',\n ALL: 'all',\n};\n\n// Overrideable options\nShuffle.options = {\n // Initial filter group.\n group: Shuffle.ALL_ITEMS,\n\n // Transition/animation speed (milliseconds).\n speed: 250,\n\n // CSS easing function to use.\n easing: 'cubic-bezier(0.4, 0.0, 0.2, 1)',\n\n // e.g. '.picture-item'.\n itemSelector: '*',\n\n // Element or selector string. Use an element to determine the size of columns\n // and gutters.\n sizer: null,\n\n // A static number or function that tells the plugin how wide the gutters\n // between columns are (in pixels).\n gutterWidth: 0,\n\n // A static number or function that returns a number which tells the plugin\n // how wide the columns are (in pixels).\n columnWidth: 0,\n\n // If your group is not json, and is comma delimeted, you could set delimeter\n // to ','.\n delimeter: null,\n\n // Useful for percentage based heights when they might not always be exactly\n // the same (in pixels).\n buffer: 0,\n\n // Reading the width of elements isn't precise enough and can cause columns to\n // jump between values.\n columnThreshold: 0.01,\n\n // Shuffle can be isInitialized with a sort object. It is the same object\n // given to the sort method.\n initialSort: null,\n\n // By default, shuffle will throttle resize events. This can be changed or\n // removed.\n throttle,\n\n // How often shuffle can be called on resize (in milliseconds).\n throttleTime: 300,\n\n // Transition delay offset for each item in milliseconds.\n staggerAmount: 15,\n\n // Maximum stagger delay in milliseconds.\n staggerAmountMax: 150,\n\n // Whether to use transforms or absolute positioning.\n useTransforms: true,\n\n // Affects using an array with filter. e.g. `filter(['one', 'two'])`. With \"any\",\n // the element passes the test if any of its groups are in the array. With \"all\",\n // the element only passes if all groups are in the array.\n filterMode: Shuffle.FilterMode.ANY,\n\n // Attempt to center grid items in each row.\n isCentered: false,\n};\n\nShuffle.Point = Point;\nShuffle.Rect = Rect;\n\n// Expose for testing. Hack at your own risk.\nShuffle.__sorter = sorter;\nShuffle.__getColumnSpan = getColumnSpan;\nShuffle.__getAvailablePositions = getAvailablePositions;\nShuffle.__getShortColumn = getShortColumn;\nShuffle.__getCenteredPositions = getCenteredPositions;\n\nexport default Shuffle;\n","'use strict';\n\nvar proto = typeof Element !== 'undefined' ? Element.prototype : {};\nvar vendor = proto.matches\n || proto.matchesSelector\n || proto.webkitMatchesSelector\n || proto.mozMatchesSelector\n || proto.msMatchesSelector\n || proto.oMatchesSelector;\n\nmodule.exports = match;\n\n/**\n * Match `el` to `selector`.\n *\n * @param {Element} el\n * @param {String} selector\n * @return {Boolean}\n * @api public\n */\n\nfunction match(el, selector) {\n if (!el || el.nodeType !== 1) return false;\n if (vendor) return vendor.call(el, selector);\n var nodes = el.parentNode.querySelectorAll(selector);\n for (var i = 0; i < nodes.length; i++) {\n if (nodes[i] == el) return true;\n }\n return false;\n}\n","import getNumber from './get-number';\n\nclass Point {\n\n /**\n * Represents a coordinate pair.\n * @param {number} [x=0] X.\n * @param {number} [y=0] Y.\n */\n constructor(x, y) {\n this.x = getNumber(x);\n this.y = getNumber(y);\n }\n\n /**\n * Whether two points are equal.\n * @param {Point} a Point A.\n * @param {Point} b Point B.\n * @return {boolean}\n */\n static equals(a, b) {\n return a.x === b.x && a.y === b.y;\n }\n}\n\nexport default Point;\n","export default class Rect {\n /**\n * Class for representing rectangular regions.\n * https://github.com/google/closure-library/blob/master/closure/goog/math/rect.js\n * @param {number} x Left.\n * @param {number} y Top.\n * @param {number} w Width.\n * @param {number} h Height.\n * @param {number} id Identifier\n * @constructor\n */\n constructor(x, y, w, h, id) {\n this.id = id;\n\n /** @type {number} */\n this.left = x;\n\n /** @type {number} */\n this.top = y;\n\n /** @type {number} */\n this.width = w;\n\n /** @type {number} */\n this.height = h;\n }\n\n /**\n * Returns whether two rectangles intersect.\n * @param {Rect} a A Rectangle.\n * @param {Rect} b A Rectangle.\n * @return {boolean} Whether a and b intersect.\n */\n static intersects(a, b) {\n return (\n a.left < b.left + b.width && b.left < a.left + a.width &&\n a.top < b.top + b.height && b.top < a.top + a.height);\n }\n}\n","export default {\n BASE: 'shuffle',\n SHUFFLE_ITEM: 'shuffle-item',\n VISIBLE: 'shuffle-item--visible',\n HIDDEN: 'shuffle-item--hidden',\n};\n","import Point from './point';\nimport Classes from './classes';\n\nlet id = 0;\n\nclass ShuffleItem {\n constructor(element) {\n id += 1;\n this.id = id;\n this.element = element;\n\n /**\n * Used to separate items for layout and shrink.\n */\n this.isVisible = true;\n\n /**\n * Used to determine if a transition will happen. By the time the _layout\n * and _shrink methods get the ShuffleItem instances, the `isVisible` value\n * has already been changed by the separation methods, so this property is\n * needed to know if the item was visible/hidden before the shrink/layout.\n */\n this.isHidden = false;\n }\n\n show() {\n this.isVisible = true;\n this.element.classList.remove(Classes.HIDDEN);\n this.element.classList.add(Classes.VISIBLE);\n this.element.removeAttribute('aria-hidden');\n }\n\n hide() {\n this.isVisible = false;\n this.element.classList.remove(Classes.VISIBLE);\n this.element.classList.add(Classes.HIDDEN);\n this.element.setAttribute('aria-hidden', true);\n }\n\n init() {\n this.addClasses([Classes.SHUFFLE_ITEM, Classes.VISIBLE]);\n this.applyCss(ShuffleItem.Css.INITIAL);\n this.scale = ShuffleItem.Scale.VISIBLE;\n this.point = new Point();\n }\n\n addClasses(classes) {\n classes.forEach((className) => {\n this.element.classList.add(className);\n });\n }\n\n removeClasses(classes) {\n classes.forEach((className) => {\n this.element.classList.remove(className);\n });\n }\n\n applyCss(obj) {\n Object.keys(obj).forEach((key) => {\n this.element.style[key] = obj[key];\n });\n }\n\n dispose() {\n this.removeClasses([\n Classes.HIDDEN,\n Classes.VISIBLE,\n Classes.SHUFFLE_ITEM,\n ]);\n\n this.element.removeAttribute('style');\n this.element = null;\n }\n}\n\nShuffleItem.Css = {\n INITIAL: {\n position: 'absolute',\n top: 0,\n left: 0,\n visibility: 'visible',\n 'will-change': 'transform',\n },\n VISIBLE: {\n before: {\n opacity: 1,\n visibility: 'visible',\n },\n after: {\n transitionDelay: '',\n },\n },\n HIDDEN: {\n before: {\n opacity: 0,\n },\n after: {\n visibility: 'hidden',\n transitionDelay: '',\n },\n },\n};\n\nShuffleItem.Scale = {\n VISIBLE: 1,\n HIDDEN: 0.001,\n};\n\nexport default ShuffleItem;\n","const element = document.body || document.documentElement;\nconst e = document.createElement('div');\ne.style.cssText = 'width:10px;padding:2px;box-sizing:border-box;';\nelement.appendChild(e);\n\nconst width = window.getComputedStyle(e, null).width;\nconst ret = width === '10px';\n\nelement.removeChild(e);\n\nexport default ret;\n","module.exports = throttle;\n\n/**\n * Returns a new function that, when invoked, invokes `func` at most once per `wait` milliseconds.\n *\n * @param {Function} func Function to wrap.\n * @param {Number} wait Number of milliseconds that must elapse between `func` invocations.\n * @return {Function} A new function that wraps the `func` function passed in.\n */\n\nfunction throttle (func, wait) {\n var ctx, args, rtn, timeoutID; // caching\n var last = 0;\n\n return function throttled () {\n ctx = this;\n args = arguments;\n var delta = new Date() - last;\n if (!timeoutID)\n if (delta >= wait) call();\n else timeoutID = setTimeout(call, wait - delta);\n return rtn;\n };\n\n function call () {\n timeoutID = 0;\n last = +new Date();\n rtn = func.apply(ctx, args);\n ctx = null;\n args = null;\n }\n}\n"],"names":["E","noop","getNumber","value","parseFloat","getNumberStyle","element","style","styles","window","getComputedStyle","COMPUTED_SIZE_INCLUDES_PADDING","paddingTop","paddingBottom","borderTopWidth","borderBottomWidth","paddingLeft","paddingRight","borderLeftWidth","borderRightWidth","randomize","array","n","length","i","Math","floor","random","temp","sorter","arr","options","opts","Object","assign","defaults","original","Array","from","revert","by","sort","a","b","valA","key","valB","undefined","reverse","uniqueId","eventName","count","cancelTransitionEnd","id","transitions","removeEventListener","listener","onTransitionEnd","callback","evt","currentTarget","target","addEventListener","arrayMax","max","apply","arrayMin","min","getColumnSpan","itemWidth","columnWidth","columns","threshold","columnSpan","abs","round","ceil","getAvailablePositions","positions","available","push","slice","getShortColumn","buffer","minPosition","len","getItemPosition","itemSize","gridSize","total","span","width","setY","shortColumnIndex","point","Point","setHeight","height","getCenteredPositions","itemRects","containerWidth","rowMap","forEach","itemRect","top","rects","rows","centeredRows","keys","lastItem","end","left","offset","finalRects","canMove","newRects","every","r","newRect","Rect","noOverlap","some","intersects","intersectingRect","rowIndex","findIndex","items","includes","splice","concat","map","hyphenate","str","replace","m1","toLowerCase","arrayUnique","x","Set","prototype","on","name","ctx","e","this","fn","once","self","off","arguments","_","emit","data","call","evtArr","evts","liveEvents","proto","Element","vendor","matches","matchesSelector","webkitMatchesSelector","mozMatchesSelector","msMatchesSelector","oMatchesSelector","el","selector","nodeType","nodes","parentNode","querySelectorAll","fns","context","maybeDone","err","result","finished","results","pending","y","w","h","ShuffleItem","isVisible","isHidden","classList","remove","Classes","HIDDEN","add","VISIBLE","removeAttribute","setAttribute","addClasses","SHUFFLE_ITEM","applyCss","Css","INITIAL","scale","Scale","classes","className","obj","removeClasses","document","body","documentElement","createElement","cssText","appendChild","ret","removeChild","Shuffle","lastSort","group","ALL_ITEMS","lastFilter","isEnabled","isDestroyed","isInitialized","_transitions","isTransitioning","_queue","_this","_getElementOption","TypeError","_init","TinyEmitter","_getItems","sizer","BASE","_initItems","_onResize","_getResizeFunction","readyState","layout","bind","onLoad","containerCss","getSize","_validateStyles","_setColumns","filter","initialSort","offsetWidth","setItemTransitions","transition","speed","easing","resizeFunction","_handleResize","throttle","throttleTime","option","querySelector","jquery","position","overflow","category","collection","set","_getFilteredSets","_toggleFilterClasses","visible","hidden","item","_this2","_doesPassFilter","testCategory","attr","getAttribute","FILTER_ATTRIBUTE_KEY","delimeter","split","JSON","parse","isArray","filterMode","FilterMode","ANY","show","hide","init","dispose","visibleItems","_getFilteredItems","properties","useTransforms","before","k","join","transitionDuration","transitionTimingFunction","transitionProperty","children","_this3","itemSelector","indexOf","gutterSize","size","gutterWidth","gutter","_getGutterSize","_getColumnSize","calculatedColumns","columnThreshold","cols","colWidth","_getContainerSize","index","staggerAmount","staggerAmountMax","shuffle","itemPositions","_getNextPositions","after","equals","_this4","getStylesForTransition","transitionDelay","_getStaggerAmount","isCentered","itemsData","_this5","_getItemPosition","getTransformedPositions","_getConcealedItems","_this6","update","styleObject","transform","itemCallback","done","_whenTransitionDone","_cancelMovement","hasSpeed","hasQueue","_startTransitions","_styleImmediately","_dispatch","EventType","LAYOUT","callbacks","_this8","_getTransitionFunction","_movementFinished","objects","elements","_skipTransitions","sortObj","_filter","_shrink","_updateItemCount","sortOptions","_resetCols","_layout","_processQueue","_setContainerSize","isOnlyLayout","newItems","newItemSet","sortedVisibleItems","_mergeNewItems","_this9","isUpdateLayout","oldItems","_this10","getItemByElement","_disposeItems","REMOVED","find","_this11","includeMargins","duration","delay","func","wait","timeoutID","last","Date","rtn","args","delta","setTimeout","__sorter","__getColumnSpan","__getAvailablePositions","__getShortColumn","__getCenteredPositions"],"mappings":"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"} \ No newline at end of file diff --git a/_config.yml b/docs/_config.yml similarity index 73% rename from _config.yml rename to docs/_config.yml index 123625a..e4e9c29 100644 --- a/_config.yml +++ b/docs/_config.yml @@ -3,21 +3,8 @@ destination: _site plugins_dir: _plugins layouts_dir: _layouts data_dir: _data -include: ['.htaccess'] -exclude: [ - '.github', - '_scss', - 'coverage', - 'node_modules', - 'src', - 'test', - 'bower.json', - 'CONTRIBUTING.md', - 'gulpfile.js', - 'README.md', - 'webpack.config.js', - 'webpack.config.min.js' -] +include: ["dist"] +exclude: ["./_scss"] permalink: /:title diff --git a/_config_dev.yml b/docs/_config_dev.yml similarity index 100% rename from _config_dev.yml rename to docs/_config_dev.yml diff --git a/_data/demos.json b/docs/_data/demos.json similarity index 71% rename from _data/demos.json rename to docs/_data/demos.json index 98f4f3c..2cc1643 100644 --- a/_data/demos.json +++ b/docs/_data/demos.json @@ -27,17 +27,27 @@ { "url": "demos/2014-03-08-bootstrap3-grid", "slug": "bootstrap3-grid", - "label": "Bootstrap 3 Grid Demo" + "label": "Bootstrap 3 grid" + }, + { + "url": "demos/2017-06-12-flexbox-grid", + "slug": "flexbox-grid", + "label": "Flexbox grid" }, { "url": "demos/2014-04-09-requirejs", "slug": "requirejs", - "label": "RequireJS with Shuffle" + "label": "Shuffle with RequireJS" + }, + { + "url": "demos/2017-06-29-shuffle-with-react", + "slug": "shuffle-with-react", + "label": "Shuffle with React" }, { "external": true, "url": "http://codepen.io/pen?template=qrjOpX", "slug": "codepen-template", - "label": "CodePen Template" + "label": "CodePen template" } ] diff --git a/docs/_data/items.json b/docs/_data/items.json new file mode 100644 index 0000000..1ccd587 --- /dev/null +++ b/docs/_data/items.json @@ -0,0 +1,188 @@ +[ + { + "groups": ["nature"], + "source": "https://unsplash.com/photos/zshyCr6HGw0", + "date": "2017-04-30", + "title": "Lake Walchen", + "images": { + "small": "https://images.unsplash.com/photo-1493585552824-131927c85da2?ixlib=rb-0.3.5&auto=format&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=284&h=160&fit=crop&s=6ef0f8984525fc4500d43ffa53fe8190", + "small-2x": "https://images.unsplash.com/photo-1493585552824-131927c85da2?ixlib=rb-0.3.5&auto=format&q=55&fm=jpg&dpr=2&crop=entropy&cs=tinysrgb&w=284&h=160&fit=crop&s=6ef0f8984525fc4500d43ffa53fe8190", + "large": "https://images.unsplash.com/photo-1493585552824-131927c85da2?ixlib=rb-0.3.5&auto=format&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=584&h=329&fit=crop&s=3bd6c16cb04e08ff57de2001770f8311", + "large-2x": "https://images.unsplash.com/photo-1493585552824-131927c85da2?ixlib=rb-0.3.5&auto=format&q=55&fm=jpg&dpr=2&crop=entropy&cs=tinysrgb&w=584&h=329&fit=crop&s=3bd6c16cb04e08ff57de2001770f8311" + }, + "description": "A deep blue lake sits in the middle of vast hills covered with evergreen trees", + "type": "small", + "cols": [3, 4, 3] + }, + { + "groups": ["city"], + "source": "https://unsplash.com/photos/RRNbMiPmTZY", + "date": "2016-07-01", + "title": "Golden Gate Bridge", + "images": { + "small": "https://images.unsplash.com/photo-1467348733814-f93fc480bec6?ixlib=rb-0.3.5&auto=format&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=284&h=160&fit=crop&s=c7e6f790e22b5e61c2a757ead9c34759", + "small-2x": "https://images.unsplash.com/photo-1467348733814-f93fc480bec6?ixlib=rb-0.3.5&auto=format&q=55&fm=jpg&dpr=2&crop=entropy&cs=tinysrgb&w=284&h=160&fit=crop&s=c7e6f790e22b5e61c2a757ead9c34759", + "large": "https://images.unsplash.com/photo-1467348733814-f93fc480bec6?ixlib=rb-0.3.5&auto=format&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=584&h=329&fit=crop&s=2590c736835ec6555e952e19bb37f06e", + "large-2x": "https://images.unsplash.com/photo-1467348733814-f93fc480bec6?ixlib=rb-0.3.5&auto=format&q=55&fm=jpg&dpr=2&crop=entropy&cs=tinysrgb&w=584&h=329&fit=crop&s=2590c736835ec6555e952e19bb37f06e" + }, + "description": "Looking down over one of the pillars of the Golden Gate Bridge to the roadside and water below", + "extras": ["overlay"], + "type": "wide", + "cols": [3, 8, 6] + }, + { + "groups": ["animal"], + "source": "https://unsplash.com/photos/YOX8ZMTo7hk", + "date": "2016-08-12", + "title": "Crocodile", + "images": { + "small": "https://images.unsplash.com/photo-1471005197911-88e9d4a7834d?ixlib=rb-0.3.5&auto=format&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=284&h=160&fit=crop&s=bd8b952c4c983d4bde5e2018c90c9124", + "small-2x": "https://images.unsplash.com/photo-1471005197911-88e9d4a7834d?ixlib=rb-0.3.5&auto=format&q=55&fm=jpg&dpr=2&crop=entropy&cs=tinysrgb&w=284&h=160&fit=crop&s=bd8b952c4c983d4bde5e2018c90c9124", + "large": "https://images.unsplash.com/photo-1471005197911-88e9d4a7834d?ixlib=rb-0.3.5&auto=format&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=584&h=329&fit=crop&s=e26be7f5704cffb3bddce22148a8118a", + "large-2x": "https://images.unsplash.com/photo-1471005197911-88e9d4a7834d?ixlib=rb-0.3.5&auto=format&q=55&fm=jpg&dpr=2&crop=entropy&cs=tinysrgb&w=584&h=329&fit=crop&s=e26be7f5704cffb3bddce22148a8118a" + }, + "description": "A close, profile view of a crocodile looking directly into the camera", + "type": "small", + "cols": [3, 4, 3] + }, + { + "groups": ["space"], + "source": "https://unsplash.com/photos/GDdRP7U5ct0", + "date": "2016-03-07", + "title": "SpaceX", + "images": { + "small": "https://images.unsplash.com/photo-1457364559154-aa2644600ebb?ixlib=rb-0.3.5&auto=format&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=284&h=160&fit=crop&s=3d0e3e8d72fc5667fd9fbe354e80957b", + "small-2x": "https://images.unsplash.com/photo-1457364559154-aa2644600ebb?ixlib=rb-0.3.5&auto=format&q=55&fm=jpg&dpr=2&crop=entropy&cs=tinysrgb&w=284&h=160&fit=crop&s=3d0e3e8d72fc5667fd9fbe354e80957b", + "large": "https://images.unsplash.com/photo-1457364559154-aa2644600ebb?ixlib=rb-0.3.5&auto=format&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=584&h=329&fit=crop&s=62c4791948e0b871c95d0485efca3e74", + "large-2x": "https://images.unsplash.com/photo-1457364559154-aa2644600ebb?ixlib=rb-0.3.5&auto=format&q=55&fm=jpg&dpr=2&crop=entropy&cs=tinysrgb&w=584&h=329&fit=crop&s=62c4791948e0b871c95d0485efca3e74" + }, + "description": "SpaceX launches a Falcon 9 rocket from Cape Canaveral Air Force Station", + "extras": ["h2"], + "type": "tall", + "cols": [3, 4, 3] + }, + { + "groups": ["city"], + "source": "https://unsplash.com/photos/7nrsVjvALnA", + "date": "2016-06-09", + "title": "Crossroads", + "images": { + "small": "https://images.unsplash.com/photo-1465447142348-e9952c393450?ixlib=rb-0.3.5&auto=format&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=284&h=160&fit=crop&s=7d97e22d36a9a73beb639a936e6774e9", + "small-2x": "https://images.unsplash.com/photo-1465447142348-e9952c393450?ixlib=rb-0.3.5&auto=format&q=55&fm=jpg&dpr=2&crop=entropy&cs=tinysrgb&w=284&h=160&fit=crop&s=7d97e22d36a9a73beb639a936e6774e9", + "large": "https://images.unsplash.com/photo-1465447142348-e9952c393450?ixlib=rb-0.3.5&auto=format&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=584&h=329&fit=crop&s=c5d7cdb3aa81a476198da2648dd9b826", + "large-2x": "https://images.unsplash.com/photo-1465447142348-e9952c393450?ixlib=rb-0.3.5&auto=format&q=55&fm=jpg&dpr=2&crop=entropy&cs=tinysrgb&w=584&h=329&fit=crop&s=c5d7cdb3aa81a476198da2648dd9b826" + }, + "description": "A multi-level highway stack interchange in Puxi, Shanghai", + "type": "small", + "cols": [3, 4, 3] + }, + { + "groups": ["space", "nature"], + "source": "https://unsplash.com/photos/_4Ib-a8g9aA", + "date": "2016-06-29", + "title": "Milky Way", + "images": { + "small": "https://images.unsplash.com/photo-1467173572719-f14b9fb86e5f?ixlib=rb-0.3.5&auto=format&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=284&h=160&fit=crop&s=cdc2d3d21c872193c66d31f05aaa421d", + "small-2x": "https://images.unsplash.com/photo-1467173572719-f14b9fb86e5f?ixlib=rb-0.3.5&auto=format&q=55&fm=jpg&dpr=2&crop=entropy&cs=tinysrgb&w=284&h=160&fit=crop&s=cdc2d3d21c872193c66d31f05aaa421d", + "large": "https://images.unsplash.com/photo-1467173572719-f14b9fb86e5f?ixlib=rb-0.3.5&auto=format&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=584&h=329&fit=crop&s=e641d6b3c4c2c967e80e998d02a4d03b", + "large-2x": "https://images.unsplash.com/photo-1467173572719-f14b9fb86e5f?ixlib=rb-0.3.5&auto=format&q=55&fm=jpg&dpr=2&crop=entropy&cs=tinysrgb&w=584&h=329&fit=crop&s=e641d6b3c4c2c967e80e998d02a4d03b" + }, + "description": "Dimly lit mountains give way to a starry night showing the Milky Way", + "extras": ["overlay"], + "type": "wide", + "cols": [6, 8, 6] + }, + { + "groups": ["space"], + "source": "https://unsplash.com/photos/yZygONrUBe8", + "date": "2015-11-06", + "title": "Earth", + "images": { + "small": "https://images.unsplash.com/photo-1446776811953-b23d57bd21aa?ixlib=rb-0.3.5&auto=format&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=284&h=160&fit=crop&s=d479589955bd9f45f2ee914532ba414e", + "small-2x": "https://images.unsplash.com/photo-1446776811953-b23d57bd21aa?ixlib=rb-0.3.5&auto=format&q=55&fm=jpg&dpr=2&crop=entropy&cs=tinysrgb&w=284&h=160&fit=crop&s=d479589955bd9f45f2ee914532ba414e", + "large": "https://images.unsplash.com/photo-1446776811953-b23d57bd21aa?ixlib=rb-0.3.5&auto=format&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=584&h=329&fit=crop&s=f4856588634def31d5885dc396fe9a2e", + "large-2x": "https://images.unsplash.com/photo-1446776811953-b23d57bd21aa?ixlib=rb-0.3.5&auto=format&q=55&fm=jpg&dpr=2&crop=entropy&cs=tinysrgb&w=584&h=329&fit=crop&s=f4856588634def31d5885dc396fe9a2e" + }, + "description": "NASA Satellite view of Earth", + "extras": ["h2"], + "type": "large", + "cols": [6, 8, 6] + }, + { + "groups": ["animal"], + "source": "https://unsplash.com/photos/L-2p8fapOA8", + "date": "2015-07-23", + "title": "Turtle", + "images": { + "small": "https://images.unsplash.com/photo-1437622368342-7a3d73a34c8f?ixlib=rb-0.3.5&auto=format&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=284&h=160&fit=crop&s=bc4e1180b6b8789d38c614edc8d0dd01", + "small-2x": "https://images.unsplash.com/photo-1437622368342-7a3d73a34c8f?ixlib=rb-0.3.5&auto=format&q=55&fm=jpg&dpr=2&crop=entropy&cs=tinysrgb&w=284&h=160&fit=crop&s=bc4e1180b6b8789d38c614edc8d0dd01", + "large": "https://images.unsplash.com/photo-1437622368342-7a3d73a34c8f?ixlib=rb-0.3.5&auto=format&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=584&h=329&fit=crop&s=992981aed536106dd1865fb2a97b331d", + "large-2x": "https://images.unsplash.com/photo-1437622368342-7a3d73a34c8f?ixlib=rb-0.3.5&auto=format&q=55&fm=jpg&dpr=2&crop=entropy&cs=tinysrgb&w=584&h=329&fit=crop&s=992981aed536106dd1865fb2a97b331d" + }, + "description": "A close up of a turtle underwater", + "extras": ["h2"], + "type": "tall", + "cols": [3, 4, 3] + }, + { + "groups": ["nature"], + "source": "https://unsplash.com/photos/b-yEdfrvQ50", + "date": "2014-10-12", + "title": "Stanley Park", + "images": { + "small": "https://images.unsplash.com/uploads/1413142095961484763cf/d141726c?ixlib=rb-0.3.5&auto=format&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=284&h=160&fit=crop&s=6141097da144d759176d77b4024c064b", + "small-2x": "https://images.unsplash.com/uploads/1413142095961484763cf/d141726c?ixlib=rb-0.3.5&auto=format&q=55&fm=jpg&dpr=2&crop=entropy&cs=tinysrgb&w=284&h=160&fit=crop&s=6141097da144d759176d77b4024c064b", + "large": "https://images.unsplash.com/uploads/1413142095961484763cf/d141726c?ixlib=rb-0.3.5&auto=format&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=584&h=329&fit=crop&s=d54eaf9ae3abedc7709a8f2003add79a", + "large-2x": "https://images.unsplash.com/uploads/1413142095961484763cf/d141726c?ixlib=rb-0.3.5&auto=format&q=55&fm=jpg&dpr=2&crop=entropy&cs=tinysrgb&w=584&h=329&fit=crop&s=d54eaf9ae3abedc7709a8f2003add79a" + }, + "description": "Many trees stand alonside a hill which overlooks a pedestrian path, next to the ocean at Stanley Park in Vancouver, Canada", + "type": "small", + "cols": [3, 4, 3] + }, + { + "groups": ["animal"], + "source": "https://unsplash.com/photos/FqkBXo2Nkq0", + "date": "2017-01-12", + "title": "Astronaut Cat", + "images": { + "small": "https://images.unsplash.com/photo-1484244233201-29892afe6a2c?ixlib=rb-0.3.5&auto=format&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=284&h=160&fit=crop&s=98423596f72d9f0913a4d44f0580a34c", + "small-2x": "https://images.unsplash.com/photo-1484244233201-29892afe6a2c?ixlib=rb-0.3.5&auto=format&q=55&fm=jpg&dpr=2&crop=entropy&cs=tinysrgb&w=284&h=160&fit=crop&s=98423596f72d9f0913a4d44f0580a34c", + "large": "https://images.unsplash.com/photo-1484244233201-29892afe6a2c?ixlib=rb-0.3.5&auto=format&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=584&h=329&fit=crop&s=af0c7497e581b7efd906db9f20937b8b", + "large-2x": "https://images.unsplash.com/photo-1484244233201-29892afe6a2c?ixlib=rb-0.3.5&auto=format&q=55&fm=jpg&dpr=2&crop=entropy&cs=tinysrgb&w=584&h=329&fit=crop&s=af0c7497e581b7efd906db9f20937b8b" + }, + "description": "An intrigued cat sits in grass next to a flag planted in front of it with an astronaut space kitty sticker on beige fabric.", + "type": "small", + "cols": [3, 4, 3] + }, + { + "groups": ["city"], + "source": "https://unsplash.com/photos/h3jarbNzlOg", + "date": "2017-01-19", + "title": "San Francisco", + "images": { + "small": "https://images.unsplash.com/photo-1484851050019-ca9daf7736fb?ixlib=rb-0.3.5&auto=format&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=284&h=160&fit=crop&s=e81b5cec7eec8fef5d4faed3ecc37a1b", + "small-2x": "https://images.unsplash.com/photo-1484851050019-ca9daf7736fb?ixlib=rb-0.3.5&auto=format&q=55&fm=jpg&dpr=2&crop=entropy&cs=tinysrgb&w=284&h=160&fit=crop&s=e81b5cec7eec8fef5d4faed3ecc37a1b", + "large": "https://images.unsplash.com/photo-1484851050019-ca9daf7736fb?ixlib=rb-0.3.5&auto=format&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=584&h=329&fit=crop&s=05325a7cc678f7f765cbbdcf7159ab89", + "large-2x": "https://images.unsplash.com/photo-1484851050019-ca9daf7736fb?ixlib=rb-0.3.5&auto=format&q=55&fm=jpg&dpr=2&crop=entropy&cs=tinysrgb&w=584&h=329&fit=crop&s=05325a7cc678f7f765cbbdcf7159ab89" + }, + "description": "Pier 14 at night, looking towards downtown San Francisco's brightly lit buildings", + "extras": ["overlay"], + "type": "wide", + "cols": [3, 8, 6] + }, + { + "groups": ["nature", "city"], + "source": "https://unsplash.com/photos/utwYoEu9SU8", + "date": "2015-10-20", + "title": "Central Park", + "images": { + "small": "https://images.unsplash.com/photo-1445346366695-5bf62de05412?ixlib=rb-0.3.5&auto=format&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=284&h=160&fit=crop&s=1822bfd69c4021973a3d926e9294b70f", + "small-2x": "https://images.unsplash.com/photo-1445346366695-5bf62de05412?ixlib=rb-0.3.5&auto=format&q=55&fm=jpg&dpr=2&crop=entropy&cs=tinysrgb&w=284&h=160&fit=crop&s=1822bfd69c4021973a3d926e9294b70f", + "large": "https://images.unsplash.com/photo-1445346366695-5bf62de05412?ixlib=rb-0.3.5&auto=format&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=584&h=329&fit=crop&s=43f26c1f7fce5aa6f763ff71cb422e1b", + "large-2x": "https://images.unsplash.com/photo-1445346366695-5bf62de05412?ixlib=rb-0.3.5&auto=format&q=55&fm=jpg&dpr=2&crop=entropy&cs=tinysrgb&w=584&h=329&fit=crop&s=43f26c1f7fce5aa6f763ff71cb422e1b" + }, + "description": "Looking down on central park and the surrounding builds from the Rockefellar Center", + "type": "small", + "cols": [3, 4, 3] + } +] diff --git a/_data/shapes.json b/docs/_data/shapes.json similarity index 100% rename from _data/shapes.json rename to docs/_data/shapes.json diff --git a/_includes/adding-removing.html b/docs/_includes/adding-removing.html similarity index 76% rename from _includes/adding-removing.html rename to docs/_includes/adding-removing.html index a764c8e..8c0ebb6 100644 --- a/_includes/adding-removing.html +++ b/docs/_includes/adding-removing.html @@ -1,4 +1,4 @@ -

Adding and removing items

+

Adding and Removing Items

You can add and remove elements from shuffle after it has been created. This also works for infinite scrolling.

Adding elements

@@ -9,20 +9,20 @@ * shuffle about the new items. You could also insert the HTML as a string. */ Demo.prototype.onAppendBoxes = function () { - var items = this._getArrayOfElementsToAdd(); + var elements = this._getArrayOfElementsToAdd(); - items.forEach(function (item) { - this.shuffle.element.appendChild(item); + elements.forEach(function (element) { + this.shuffle.element.appendChild(element); }, this); - // Tell shuffle items have been appended. + // Tell shuffle elements have been appended. // It expects an array of elements as the parameter. - this.shuffle.add(items); + this.shuffle.add(elements); };

Removing elements

-

Shuffle will animate the element away and then remove it from the DOM once it's finished. It will then emit the Shuffle.EventType.REMOVED custom event with the array of elements in event.detail.collection.

+

Shuffle will animate the element away and then remove it from the DOM once it's finished. It will then emit the Shuffle.EventType.REMOVED event with the array of elements in event.collection.

this.shuffle.remove([element1, element2]);
diff --git a/_includes/advanced-filters.html b/docs/_includes/advanced-filters.html similarity index 93% rename from _includes/advanced-filters.html rename to docs/_includes/advanced-filters.html index c4bf1e2..f3b6807 100644 --- a/_includes/advanced-filters.html +++ b/docs/_includes/advanced-filters.html @@ -1,11 +1,11 @@ -

Advanced Filtering

+

Advanced Filters

By passing a function to filter, you can fully customize filtering items. Shuffle will iterate over each item and give your function the element and the shuffle instance. Return true to keep the element or false to hide it.

Example

// Filters elements with a data-title attribute with less than 10 characters
-instance.filter(function (element) {
+shuffleInstance.filter(function (element) {
   return element.getAttribute('data-title').length < 10;
 });
diff --git a/_includes/changelog.html b/docs/_includes/changelog.html similarity index 87% rename from _includes/changelog.html rename to docs/_includes/changelog.html index 315adc1..4585bae 100644 --- a/_includes/changelog.html +++ b/docs/_includes/changelog.html @@ -1,5 +1,7 @@ -

Changes

+

Changelog

+

For a more detailed changelog, visit the latest releases on GitHub.

    +
  • v5.0.0 x/x/17 - Change global export from shuffle to Shuffle. Remove bower support. Expect ES6 environment. Make Shuffle instances Event Emitters instead of dispatching CustomEvent.
  • v4.2.0 5/10/17 - Replace webpack build with rollup. Replace jshint and jscs with eslint. Add filterMode option.
  • v4.1.1 3/21/17 - the before styles for a ShuffleItem were not applied if the item didn’t move.
  • v4.1.0 1/30/17 - Use webpack-2 to bundle Shuffle.
  • diff --git a/_includes/custom-styles.html b/docs/_includes/custom-styles.html similarity index 90% rename from _includes/custom-styles.html rename to docs/_includes/custom-styles.html index 64319d2..916f903 100644 --- a/_includes/custom-styles.html +++ b/docs/_includes/custom-styles.html @@ -15,7 +15,9 @@ opacity: 1, visibility: 'visible', }, - after: {}, + after: { + transitionDelay: '', + }, }, HIDDEN: { before: { @@ -23,6 +25,7 @@ }, after: { visibility: 'hidden', + transitionDelay: '', }, }, }; @@ -43,7 +46,7 @@ ShuffleItem.Scale = {
    Shuffle.ShuffleItem.Css.VISIBLE.after.color = 'teal';
    -

    You can also customize the scaling effect with visible or hidden items, however, the VISIBLE and HIDDEN values cannot be the exact same.

    +

    You can also customize the scaling effect with visible or hidden items.

    Shuffle.ShuffleItem.Scale.HIDDEN = 0.5;
    diff --git a/_includes/demo-list.html b/docs/_includes/demo-list.html similarity index 100% rename from _includes/demo-list.html rename to docs/_includes/demo-list.html diff --git a/docs/_includes/events.html b/docs/_includes/events.html new file mode 100644 index 0000000..94c09e5 --- /dev/null +++ b/docs/_includes/events.html @@ -0,0 +1,19 @@ +

    Events

    +

    Shuffle is a subclass of TinyEmitter. It emits an event when a layout happens and when elements are removed. The event names are Shuffle.EventType.LAYOUT and Shuffle.EventType.REMOVED.

    + +

    Get notified when a layout happens

    +
    +
    shuffleInstance.on(Shuffle.EventType.LAYOUT, function () {
    +  console.log('Things finished moving!');
    +});
    +
    + + +

    Do something when an item is removed

    +
    +
    shuffleInstance.on(Shuffle.EventType.REMOVED, function (data) {
    +  console.log(this, data, data.collection, data.shuffle);
    +});
    +
    + + diff --git a/_includes/features.html b/docs/_includes/features.html similarity index 100% rename from _includes/features.html rename to docs/_includes/features.html diff --git a/docs/_includes/filters.html b/docs/_includes/filters.html new file mode 100644 index 0000000..b7be2bf --- /dev/null +++ b/docs/_includes/filters.html @@ -0,0 +1,45 @@ +

    Filters

    + +

    Filter by a group

    +

    Use the filter() method. If, for example, you wanted to show only items that match "space", you would do this:

    + +
    +
    shuffleInstance.filter('space');
    +
    + +

    Filter by multiple groups

    +

    Show multiple groups at once by using an array.

    + +
    +
    shuffleInstance.filter(['space', 'nature']);
    +
    + +

    By default, this will show items that match space or nature. To show only groups that match space and nature, set the filterMode option to Shuffle.FilterMode.ALL.

    + +

    Show all items

    +

    To go back to having no items filtered, you can call filter() without a parameter, or use Shuffle.ALL_ITEMS (which by default is the string "all").

    + +
    +
    shuffleInstance.filter(Shuffle.ALL_ITEMS); // or .filter()
    +
    + +

    Filter and sort

    +

    You can filter and sort at the same time by passing a sort object as the second parameter.

    + +
    +
    shuffleInstance.filter('space', {
    +  by: function (element) {
    +    return element.getAttribute('data-title').toLowerCase();
    +  },
    +});
    +
    + +

    Overrides

    +

    You can override both Shuffle.ALL_ITEMS and Shuffle.FILTER_ATTRIBUTE_KEY if you want.

    + +
    +
    Shuffle.ALL_ITEMS = 'any';
    +Shuffle.FILTER_ATTRIBUTE_KEY = 'categories';
    +
    + +

    Then you would have to use data-categories attribute on your items instead of data-groups.

    diff --git a/_includes/foot.html b/docs/_includes/foot.html similarity index 100% rename from _includes/foot.html rename to docs/_includes/foot.html diff --git a/docs/_includes/footer.html b/docs/_includes/footer.html new file mode 100644 index 0000000..5717b33 --- /dev/null +++ b/docs/_includes/footer.html @@ -0,0 +1,17 @@ + diff --git a/_includes/head.html b/docs/_includes/head.html similarity index 85% rename from _includes/head.html rename to docs/_includes/head.html index 4452121..7cbdcd4 100644 --- a/_includes/head.html +++ b/docs/_includes/head.html @@ -13,7 +13,8 @@ - + + @@ -28,15 +29,15 @@ - - + - + {% if page.prism %}{% endif %} + - + {% if page.extraCSS %} {% for href in page.extraCSS %} @@ -47,5 +48,6 @@ {% endfor %} {% endif %} + diff --git a/docs/_includes/install.html b/docs/_includes/install.html new file mode 100644 index 0000000..cf7a136 --- /dev/null +++ b/docs/_includes/install.html @@ -0,0 +1,14 @@ +
    +

    Install

    +
    +
    +
    +
    npm install shufflejs
    +
    +
    + diff --git a/docs/_includes/nav.html b/docs/_includes/nav.html new file mode 100644 index 0000000..41397c1 --- /dev/null +++ b/docs/_includes/nav.html @@ -0,0 +1,72 @@ + diff --git a/_includes/options.html b/docs/_includes/options.html similarity index 90% rename from _includes/options.html rename to docs/_includes/options.html index 82e1e09..cc77eb0 100644 --- a/_includes/options.html +++ b/docs/_includes/options.html @@ -4,23 +4,24 @@
    // Overrideable options
     Shuffle.options = {
    -  group: Shuffle.ALL_ITEMS, // Initial filter group.
    -  speed: 250, // Transition/animation speed (milliseconds).
    -  easing: 'ease', // CSS easing function to use.
    -  itemSelector: '*', // e.g. '.picture-item'.
    -  sizer: null, // Element or selector string. Use an element to determine the size of columns and gutters.
    -  gutterWidth: 0, // A static number or function that tells the plugin how wide the gutters between columns are (in pixels).
    -  columnWidth: 0, // A static number or function that returns a number which tells the plugin how wide the columns are (in pixels).
    -  delimeter: null, // If your group is not json, and is comma delimeted, you could set delimeter to ','.
       buffer: 0, // Useful for percentage based heights when they might not always be exactly the same (in pixels).
       columnThreshold: 0.01, // Reading the width of elements isn't precise enough and can cause columns to jump between values.
    +  columnWidth: 0, // A static number or function that returns a number which tells the plugin how wide the columns are (in pixels).
    +  delimeter: null, // If your group is not json, and is comma delimeted, you could set delimeter to ','.
    +  easing: 'cubic-bezier(0.4, 0.0, 0.2, 1)', // CSS easing function to use.
    +  filterMode: Shuffle.FilterMode.ANY, // When using an array with filter(), the element passes the test if any of its groups are in the array. With "all", the element only passes if all groups are in the array.
    +  group: Shuffle.ALL_ITEMS, // Initial filter group.
    +  gutterWidth: 0, // A static number or function that tells the plugin how wide the gutters between columns are (in pixels).
       initialSort: null, // Shuffle can be initialized with a sort object. It is the same object given to the sort method.
    +  isCentered: false, // Attempt to center grid items in each row.
    +  itemSelector: '*', // e.g. '.picture-item'.
       throttle: throttle, // By default, shuffle will throttle resize events. This can be changed or removed.
       throttleTime: 300, // How often shuffle can be called on resize (in milliseconds).
    +  sizer: null, // Element or selector string. Use an element to determine the size of columns and gutters.
    +  speed: 250, // Transition/animation speed (milliseconds).
       staggerAmount: 15, // Transition delay offset for each item in milliseconds.
    -  staggerAmountMax: 250, // Maximum stagger delay in milliseconds.
    +  staggerAmountMax: 150, // Maximum stagger delay in milliseconds.
       useTransforms: true, // Whether to use transforms or absolute positioning.
    -  filterMode: Shuffle.FilterMode.ANY, // When using an array with filter(), the element passes the test if any of its groups are in the array. With "all", the element only passes if all groups are in the array.
     };
    diff --git a/docs/_includes/picture-item.html b/docs/_includes/picture-item.html new file mode 100644 index 0000000..a5950cf --- /dev/null +++ b/docs/_includes/picture-item.html @@ -0,0 +1,34 @@ +{%- if item.extras | size: > 0 -%} + {%- capture extras %} picture-item--{{ item.extras | join: " picture-item--" }}{%- endcapture -%} +{%- else -%} + {%- assign extras = "" -%} +{%- endif -%} +{%- assign description = item.description -%} +
    +
    + {%- if item.type != 'wide' -%} +
    +
    + {%- endif -%} + {%- if item.type == 'small' or item.type == 'tall' -%} + {%- assign src1x = item.images.small -%} + {%- assign src2x = item.images.small-2x -%} + {%- else -%} + {%- assign src1x = item.images.large -%} + {%- assign src2x = item.images.large-2x -%} + {%- endif -%} + {{ item.description }} + + {%- if item.type != 'wide' -%} +
    +
    + {%- endif -%} +
    +
    {{ item.title }}
    +

    {{ item.groups | join: ', ' }}

    +
    + {%- if item.type == 'large' or item.type == 'tall' -%} +

    {{ item.description }}

    + {%- endif -%} +
    +
    diff --git a/_includes/public-methods.html b/docs/_includes/public-methods.html similarity index 100% rename from _includes/public-methods.html rename to docs/_includes/public-methods.html diff --git a/_includes/scripts.html b/docs/_includes/scripts.html similarity index 57% rename from _includes/scripts.html rename to docs/_includes/scripts.html index 277e6a1..f8c0ec0 100644 --- a/_includes/scripts.html +++ b/docs/_includes/scripts.html @@ -1,26 +1,23 @@ -{% if page.jquery %} - -{% endif %} - -{% if page.shuffle != false %} - - -{% endif %} - -{% if page.prism %} +{% if page.requirejs %} + +{% else %} + + + {% endif %} + - -{% if page.pagejs != false %} - - +{% if page.externalJS %} +{% for src in page.externalJS %} + +{% endfor %} {% endif %} {% if page.extraJS && page.extraJS.length %} {% for src in page.extraJS %} - + {% endfor %} {% endif %} diff --git a/_includes/sorting.html b/docs/_includes/sorting.html similarity index 59% rename from _includes/sorting.html rename to docs/_includes/sorting.html index 6de94ee..c20bb54 100644 --- a/_includes/sorting.html +++ b/docs/_includes/sorting.html @@ -1,9 +1,9 @@

    Sorting

    -

    You can order the elements with a function you supply. In the demo above, each item has a data-date-created and data-title attribute. When the select option menu changes, a sort object is passed to shuffle.

    +

    You can order the elements with a function you supply. In the demo above, each item has a data-date-created and data-title attribute which are used for sorting.

    -
    <figure class="picture-item" data-groups='["photography"]' data-date-created="2010-09-14" data-title="Baseball">…</figure>
    +
    <figure class="col-4@sm picture-item" data-groups='["city"]' data-date-created="2016-06-09" data-title="Crossroads">…</figure>
    @@ -21,7 +21,6 @@ Demo.prototype._handleSortChange = function (evt) { var value = evt.target.value; - var options = {}; function sortByDate(element) { return element.getAttribute('data-created'); @@ -31,6 +30,7 @@ Demo.prototype._handleSortChange = function (evt) { return element.getAttribute('data-title').toLowerCase(); } + var options; if (value === 'date-created') { options = { reverse: true, @@ -40,18 +40,20 @@ Demo.prototype._handleSortChange = function (evt) { options = { by: sortByTitle, }; + } else { + options = {}; } this.shuffle.sort(options); };
    -

    The options object can contain three properties:

    +

    The options object can contain three properties:

      -
    • reverse: a boolean which will reverse the resulting order.
    • -
    • by: a function with an element as the parameter. Above, we’re returning the value of the data-date-created or data-title attribute.
    • -
    • randomize: Make the order random.
    • +
    • reverse: a boolean which will reverse the resulting order.
    • +
    • by: a function with an element as the parameter. Above, we’re returning the value of the data-date-created or data-title attribute.
    • +
    • randomize: Make the order random.
    -

    Returning undefined from the by function will reset the order to DOM order.

    +

    Returning undefined from the by function will reset the order to DOM order.

    Calling sort with an empty object will reset the elements to DOM order.

    diff --git a/_includes/usage.html b/docs/_includes/usage.html similarity index 61% rename from _includes/usage.html rename to docs/_includes/usage.html index 416723c..c609d79 100644 --- a/_includes/usage.html +++ b/docs/_includes/usage.html @@ -1,38 +1,38 @@

    Usage

    The HTML Structure

    -

    The only real important thing here is the data-groups attribute. It has to be a valid JSON array of strings. Optionally, it can be a string delimeted by a value you provide. See delimeter in the options.

    +

    The only real important thing here is the data-groups attribute. It has to be a valid JSON array of strings. It can also be a string delimeted by a value you provide with the delimeter option.

    This example is using this site's grid. Each item would be 4 columns at the "sm" breakpoint (768px).

    Images

    -

    To see why the images are wrapped in .aspect elements, check out the images demo.

    +

    Images are wrapped in .aspect elements to take up the same amount of space the image will when it loads. For details, check out the images demo.

    -
    <div id="grid" class="row my-shuffle-container">
    -  <figure class="col-4@sm picture-item" data-groups='["photography"]' data-date-created="2010-09-14" data-title="Baseball">
    +  
    <div class="row my-shuffle-container">
    +  <figure class="col-4@sm picture-item" data-groups='["animal"]' data-date-created="2016-08-12" data-title="Crocodile">
         <div class="aspect aspect--16x9">
           <div class="aspect__inner">
    -        <img src="/img/baseball.png" alt="" height="145" width="230">
    +        <img src="crocodile.jpg" alt="A close, profile view of a crocodile looking directly into the camera" />
           </div>
         </div>
    -    <figcaption>Baseball</figcaption>
    +    <figcaption>Crocodile</figcaption>
       </figure>
    -  <figure class="col-4@sm picture-item" data-groups='["wallpaper","3d"]' data-date-created="2011-08-14" data-title="Tennis">
    +  <figure class="col-4@sm picture-item" data-groups='["city"]' data-date-created="2016-06-09" data-title="Crossroads">
         <div class="aspect aspect--16x9">
           <div class="aspect__inner">
    -        <img src="/img/tennis-ball.png" alt="" height="145" width="230">
    +        <img src="crossroads.jpg" alt="A multi-level highway stack interchange in Puxi, Shanghai" />
           </div>
         </div>
    -    <figcaption>Tennis</figcaption>
    +    <figcaption>Crossroads</figcaption>
       </figure>
    -  <figure class="col-4@sm picture-item" data-groups='["wallpaper","3d"]' data-date-created="2009-05-27" data-title="iMac">
    +  <figure class="col-4@sm picture-item" data-groups='["nature","city"]' data-date-created="2015-10-20" data-title="Central Park">
         <div class="aspect aspect--16x9">
           <div class="aspect__inner">
    -        <img src="/img/imac.png" alt="" height="145" width="230">
    +        <img src="central-park.jpg" alt="Looking down on central park and the surrounding builds from the Rockefellar Center" />
           </div>
         </div>
    -    <figcaption>iMac</figcaption>
    +    <figcaption>Central Park</figcaption>
       </figure>
       <div class="col-1@sm my-sizer-element"></div>
     </div>
    @@ -51,11 +51,11 @@

    If you want functional buttons, check out the js file.

    Shuffle uses a UMD definition so that you can use it with globals, AMD, or CommonJS.

    -
    var Shuffle = window.shuffle;
    -var element = document.getElementById('grid');
    +  
    var Shuffle = window.Shuffle;
    +var element = document.querySelector('.my-shuffle-container');
     var sizer = element.querySelector('.my-sizer-element');
     
    -var shuffle = new Shuffle(element, {
    +var shuffleInstance = new Shuffle(element, {
       itemSelector: '.picture-item',
       sizer: sizer // could also be a selector: '.my-sizer-element'
     });
    diff --git a/_layouts/default.html b/docs/_layouts/default.html similarity index 55% rename from _layouts/default.html rename to docs/_layouts/default.html index 856f4f7..99dce2a 100644 --- a/_layouts/default.html +++ b/docs/_layouts/default.html @@ -3,16 +3,16 @@ {% if page.includeHeader %}
    -
    +

    Shuffle

    -

    {{ site.defaultDescription }}

    -

    By @Vestride

    +

    {{ site.defaultDescription }}

    {% endif %} -
    +
    {{ content }}
    +{% include footer.html %} {% include scripts.html %} {% include foot.html %} diff --git a/_posts/2013-05-01-basic.html b/docs/_posts/2013-05-01-basic.html similarity index 61% rename from _posts/2013-05-01-basic.html rename to docs/_posts/2013-05-01-basic.html index 170c707..e435e57 100644 --- a/_posts/2013-05-01-basic.html +++ b/docs/_posts/2013-05-01-basic.html @@ -26,9 +26,19 @@ extraJS: [ "demos/homepage.js" ]
    -

    Shuffle.js

    -

    {{ site.longDescription }}

    +
    +

    Source code for this demo

    +

    This demo uses the same code as the home page (with the filters).

    +

    Link to demo source

    +
    -{% include credit-jake.html %} +
    +
    +
    +

    Shuffle.js

    +

    {{ site.longDescription }}

    +
    +
    +
    diff --git a/_posts/2013-05-02-compound-filters.html b/docs/_posts/2013-05-02-compound-filters.html similarity index 94% rename from _posts/2013-05-02-compound-filters.html rename to docs/_posts/2013-05-02-compound-filters.html index 32c5243..93af3bc 100644 --- a/_posts/2013-05-02-compound-filters.html +++ b/docs/_posts/2013-05-02-compound-filters.html @@ -5,6 +5,7 @@ description: A demo with compound filtering image: /demos/adaptive.jpg extraJS: [ "demos/compound-filters.js" ] prism: true +photoCredit: false ---
    @@ -19,7 +20,7 @@ prism: true
    -
    Colors
    +

    Colors

    @@ -29,7 +30,7 @@ prism: true
    -
    Shapes
    +

    Shapes

    diff --git a/_posts/2013-05-03-images.html b/docs/_posts/2013-05-03-images.html similarity index 85% rename from _posts/2013-05-03-images.html rename to docs/_posts/2013-05-03-images.html index aec0802..0e6fb3e 100644 --- a/_posts/2013-05-03-images.html +++ b/docs/_posts/2013-05-03-images.html @@ -14,8 +14,9 @@ prism: true

    You can encounter problems when shuffle item dimensions depend on images. Like this demo. There are three good solutions to this.

    1. Set an explicit height on .shuffle-items like the basic demo.
    2. -
    3. Similar to number 1, make the height of the image container a percentage of the width. If you know the aspect ratio of the images you're using, this is the technique you should use. This demo uses this technique.
    4. -
    5. Get notified when images load and call myShuffleInstance.layout(). I recommend using Desandro's images loaded plugin to know when your images have finished loading.
    6. +
    7. Similar to number 1, make the height of the image container a percentage of the width. If you know the aspect ratio of the images you're using, this is the technique you should use. This demo uses that technique.
    8. +
    9. Get notified when images load and call shuffleInstance.layout(). I recommend using Desandro's images loaded plugin to know when your images have finished loading.
    10. +
    11. Do nothing and let your shuffle instance call layout() on the window's load event. This will the item layout to change on page load.
    @@ -46,10 +47,10 @@ prism: true
    - {{item.title}} + {{ item.description }}
    -
    {{ item.groups | join: ', ' }}
    +
    {{ item.title }}
    {% endfor %}
    @@ -121,6 +122,3 @@ prism: true
    - - -{% include credit-jake.html %} diff --git a/_posts/2013-06-19-adding-removing.html b/docs/_posts/2013-06-19-adding-removing.html similarity index 66% rename from _posts/2013-06-19-adding-removing.html rename to docs/_posts/2013-06-19-adding-removing.html index eb79dfb..be2e79a 100644 --- a/_posts/2013-06-19-adding-removing.html +++ b/docs/_posts/2013-06-19-adding-removing.html @@ -5,6 +5,7 @@ description: This demo of shuffle shows how to add and removing items. image: /demos/adding-removing.jpg extraJS: [ "demos/adding-removing.js" ] prism: true +photoCredit: false --- + +
    +
    +
    +

    Shuffle with Flexbox (Bootstrap 4)

    +

    On this page, I have added the minified bootstrap css file from the Bootstrap CDN (which is also why some of the site-styles are being overriden).

    +

    The Bootstrap 4 grid system uses flexbox with padding for gutters.

    +

    The best way to handle this is to have the shuffle container element (#grid in this case), to be a .row so that all the shuffle items remain flex-items.

    +

    If you cannot make the shuffle container element a .row, you will need to set a width for each column (like width: 25%;).

    +
    +
    +
    + + +
    +
    + {% for i in (1..20) %} +
    +
    +
    + {% cycle + 'Return on investment product management equity crowdfunding stock pivot innovator sales ownership.', + 'Founders ecosystem hackathon product management lean startup MVP.', + 'Traction bandwidth MVP direct mailing partner network gen-z growth hacking crowdsource channels responsive web design pivot.', + 'Conversion technology long tail influencer analytics rockstar market seed money.', + 'Investor bandwidth equity ecosystem vesting period client social media.', + 'Angel investor niche market client churn rate crowdsource infrastructure paradigm shift marketing prototype.' + %} +
    +
    +
    + {% endfor %} +
    +
    +
    + +
    +
    +
    +

    The one change I've made to the grid is to allow grid columns to fit on mobile.

    +

    By default, bootstrap 4 grid gutters are 30px, even on mobile, and they use as 12 column grid. At 320px, each column would need to be 26.667px for 12 columsn to fit, but since there is 30px of inner gutter, the columns are always >= 30px, so they don't fit for us.

    +

    If you're using Bootstrap's sass files, you can customize the gutter width via the $grid-gutter-widths map. In this example, I'm overriding it instead.

    +
    +
    @media (max-width: 575px) {
    +  .row > [class*="col-"] {
    +    padding-left: 8px;
    +    padding-right: 8px;
    +  }
    +}
    +
    +
    + +
    + +
    + +
    +
    +
    +

    Source code for this demo

    +

    Link to demo source

    +
    +
    +
    + +
    +
    +
    +

    Shuffle.js

    +

    {{ site.longDescription }}

    +
    +
    +
    diff --git a/docs/_posts/2017-06-29-shuffle-with-react.html b/docs/_posts/2017-06-29-shuffle-with-react.html new file mode 100644 index 0000000..05f2a2c --- /dev/null +++ b/docs/_posts/2017-06-29-shuffle-with-react.html @@ -0,0 +1,82 @@ +--- +layout: default +title: Shuffle with React +description: TODO +image: /demos/flexbox-grid.jpg +extraJS: [ "demos/react.js" ] +externalJS: ["https://unpkg.com/react@latest/dist/react.js", "https://unpkg.com/react-dom@latest/dist/react-dom.js", "https://unpkg.com/babel-standalone@6.15.0/babel.min.js"] +jsType: "text/babel" +prism: true +--- + + + +
    +
    +
    +

    Shuffle with React

    +

    And other view-based libraries like Vue and Preact.

    +

    The simplest way is to use shuffleInstance.resetItems(); inside the componentDidUpdate() lifecycle method.

    +
    +
    +
    + +
    +
    +
    +
    + Loading React... +
    +
    +
    +
    + +
    +
    +
    +

    Source code for this demo

    +

    Link to demo source

    +
    +
    
    +      
    +
    +
    +
    diff --git a/docs/_scss/components/_buttons.scss b/docs/_scss/components/_buttons.scss new file mode 100644 index 0000000..bfc397d --- /dev/null +++ b/docs/_scss/components/_buttons.scss @@ -0,0 +1,143 @@ +.btn-group { + @include clearfix(); + + .btn { + float: left; + border-radius: 0; + } + + .btn:first-child { + border-radius: 3px 0 0 3px; + } + + .btn:not(:first-child) { + margin-left: -1px; + } + + .btn:last-child { + border-radius: 0 3px 3px 0; + } + + label.btn input[type=radio] { + position: absolute; + clip: rect(0, 0, 0, 0); + pointer-events: none; + } +} + +.btn { + display: inline-block; + padding: .75em .8em; + text-align: center; + border-radius: 3px; + border: 1px solid $gray20; + color: $gray20; + font-size: 1rem; + background-color: rgba($gray20, 0); + transition: .2s ease-out; + cursor: pointer; + -webkit-appearance: none; + + @include with-fine-pointer() { + &:hover { + color: white; + text-decoration: none; + background-color: $gray20; + } + } + + &:focus { + outline-width: 0; + box-shadow: 0 0 0 2px rgba($gray20, 0.4); + } + + &.active, + &:active { + box-shadow: inset 0 1px 2px rgba(0,0,0,.3); + color: white; + background-color: $gray20; + } + + &:focus.active { + box-shadow: inset 0 1px 2px rgba(0,0,0,.3), 0 0 0 2px rgba($gray20, 0.4); + } +} + +$btn-variants: ( + 'warning': $carrot, + 'primary': $river, + 'danger': $alizarin, + 'go': $emerald, +); + +@each $name, $color in $btn-variants { + .btn--#{$name} { + color: $color; + border-color: $color; + background-color: rgba($color, 0); + + @include with-fine-pointer() { + &:hover { + background-color: $color; + } + } + + &:focus { + box-shadow: 0 0 0 2px rgba($color, 0.4); + } + + &.active, + &:active { + background-color: $color; + } + + &:focus.active { + box-shadow: inset 0 1px 2px rgba(0,0,0,.3), 0 0 0 2px rgba($color, 0.4); + } + } +} + +@include breakpoint(sm, true) { + .btn { + font-size: 0.875rem; + } +} + +.filter-group .btn { + position: relative; + + $size: 20px; + // Circle and check + &.active:before, + &.active:after { + content: ''; + position: absolute; + top: 50%; + left: 50%; + width: $size; + height: $size; + margin-left: -$size / 2; + margin-top: -$size / 2; + opacity: 0; + transition: .2s; + } + + // Circle + &:before { + background-color: $gray10; + border-radius: 50%; + } + + // Check + &:after { + background-size: 60%; + background-position: center center; + background-repeat: no-repeat; + background-image: url(../img/check.svg); + } + + &.active:before, + &.active:after { + opacity: 1; + } +} diff --git a/_scss/_demo-list.scss b/docs/_scss/components/_demo-list.scss similarity index 98% rename from _scss/_demo-list.scss rename to docs/_scss/components/_demo-list.scss index 71ad4ff..e5d1ea8 100644 --- a/_scss/_demo-list.scss +++ b/docs/_scss/components/_demo-list.scss @@ -37,6 +37,7 @@ } .demo-list .figure-wrap figcaption { + height: 2em; margin-top: .5em; margin-bottom: 1em; } diff --git a/docs/_scss/components/_site-nav.scss b/docs/_scss/components/_site-nav.scss new file mode 100644 index 0000000..5c65ec8 --- /dev/null +++ b/docs/_scss/components/_site-nav.scss @@ -0,0 +1,349 @@ +.site-nav { + padding: 10px 0; + border-bottom: 1px solid $gray90; + margin-bottom: 28px; + background: $gray95; +} + +.site-nav__content { + display: flex; + justify-content: space-between; +} + +.site-nav__logo { + font-size: 20px; +} + +.site-nav__logo, +.site-nav__logo:visited { + color: $gray20; + + &:hover { + text-decoration: none; + } +} + +.site-nav__logo, +.site-nav__links { + display: flex; + align-items: center; +} + +.site-nav__logo svg { + display: block; + width: 24px; + height: 24px; + margin-right: 4px; +} + +.site-nav__logo rect { + transition: 180ms cubic-bezier(0.4, 0.0, 0.2, 1); +} + +.site-nav__link { + position: relative; + z-index: 3; +} + +.site-nav__link:not(:last-of-type) { + margin-right: 8px; +} + +.site-nav__dropdown { + position: absolute; + z-index: 2; + top: 40px; + right: 0; + opacity: 0; + visibility: hidden; + max-height: 100vh; + transition: 300ms cubic-bezier(0.165, 0.84, 0.44, 1); + background-color: white; + transform: translateY(10px); + box-shadow: 0 7px 10px -1px rgba(0, 0, 0, 0.12); + + // Triangle. + &::before { + content: ''; + position: absolute; + top: -8px; + right: 32px; + display: block; + border-bottom: 8px solid white; + border-left: 9px solid transparent; + border-right: 9px solid transparent; + } + + li + li { + margin-top: 8px; + } + + a { + display: block; + color: $gray30; + } + + a:hover { + background-color: $gray95; + text-decoration: none; + color: $gray30; + } + + figure { + display: flex; + align-items: center; + } + + picture { + flex-shrink: 0; + width: 100px; + height: 100px * 0.75; + } + + figcaption { + padding-left: 8px; + padding-right: 8px; + } +} + +.site-nav__dropdown--simple-links { + a { + padding: 8px 16px; + } + + li + li { + margin-top: 0; + } +} + +.site-nav__link-toggle { + padding: 6px 8px; +} + +// Dropdown link triangle. +.site-nav__link-toggle::after { + content: ''; + display: inline-block; + vertical-align: middle; + margin-top: -1px; + margin-left: 4px; + border-top: 6px solid currentColor; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + transition: transform 180ms cubic-bezier(0.4, 0.0, 0.2, 1); +} + +.site-nav__link--dropdown-active { + // Dropdown link triangle. + .site-nav__link-toggle::after { + transform: rotate(-180deg); + } + + .site-nav__dropdown { + visibility: visible; + opacity: 1; + transform: translateY(0); + } +} + +// Rules for non-touch screens +@include with-fine-pointer() { + $interval: 10ms; + .site-nav__logo:hover { + rect:nth-of-type(1) { + transform: translate(20px, 10px); + transition-delay: (1 - 1) * $interval; + } + + rect:nth-of-type(2) { + transform: translate(0px, 20px); + transition-delay: (2 - 1) * $interval; + } + + rect:nth-of-type(3) { + transform: translate(-20px, 6px); + transition-delay: (3 - 1) * $interval; + } + + rect:nth-of-type(4) { + transform: translate(10px, -10px); + transition-delay: (4 - 1) * $interval; + } + + rect:nth-of-type(5) { + transform: translate(-10px, 10px); + transition-delay: (5 - 1) * $interval; + } + + rect:nth-of-type(6) { + transform: translate(-20px, -14px); + transition-delay: (6 - 1) * $interval; + } + + rect:nth-of-type(7) { + transform: translate(0px, -20px); + transition-delay: (7 - 1) * $interval; + } + } + + .site-nav__link-toggle:hover { + border-color: $gray20; + } +} + +@include breakpoint(sm, true) { + // Affix the nav when a dropdown is open so that scrolling the page + // behind the dropdown doesn't scroll away the nav. + body.site-nav--open { + padding-top: 51px; + } + + body.site-nav--open .site-nav { + position: fixed; + z-index: 4; + top: 0; + left: 0; + width: 100%; + } + + .site-nav__dropdown { + position: fixed; + left: 0; + right: 0; + top: 51px; + width: 100vw; + padding: 8px calc(3.5vw + 8px); + overflow: auto; + -webkit-overflow-scrolling: touch; + } +} + +@include breakpoint(sm) { + .site-nav { + padding: 16px 0; + } + + .site-nav__logo { + font-size: 24px; + } + + .site-nav__logo svg { + width: 32px; + height: 32px; + } + + .site-nav__link:not(:last-child) { + margin-right: 16px; + } + + .site-nav__link--dropdown:not(:last-child) { + margin-right: 12px; + } + + .site-nav__dropdown { + max-height: none !important; // override inline style. + right: -100px; + padding: 16px; + box-shadow: 0 0 10px rgba(0, 0, 0, 0.12); + + &::before { + right: 132px; + } + + ul { + column-count: 2; + column-gap: 16px; + } + + li { + -webkit-column-break-inside: avoid; + page-break-inside: avoid; + break-inside: avoid; + } + + figcaption { + white-space: nowrap; + } + } + + @supports (filter: drop-shadow(0 0 5px rgba(0, 0, 0, 0.12))) { + .site-nav__dropdown { + box-shadow: none; + filter: drop-shadow(0 0 5px rgba(0, 0, 0, 0.12)); + } + } + + .site-nav__link-img { + width: 24px; + height: 24px; + } + + .site-nav__dropdown--simple-links { + right: 0; + padding: 0; + + &::before { + right: 24px; + } + + a { + width: 200px; + } + } +} + +@include breakpoint(md) { + .site-nav__dropdown { + right: 0; + + &::before { + right: 32px; + } + } + + .site-nav__dropdown--simple-links { + + &::before { + right: 24px; + } + } +} + +// Footer +// ------------- +.site-footer { + margin-top: 2em; + padding: 1em 0; + background-color: $gray20; + + p { + color: $gray95; + } + + a { + color: white; + text-decoration: underline; + + &:hover { + color: $river; + } + } +} + +.has-code-block .code-block pre { + margin-bottom: 0; +} + +.has-code-block + .site-footer { + margin-top: 0; +} + +.site-footer__credit { + // margin: 0; +} + +@include breakpoint(sm) { + .site-footer__credit { + text-align: right; + } +} diff --git a/_scss/_grid-framework.scss b/docs/_scss/extensions/_grid-framework.scss similarity index 100% rename from _scss/_grid-framework.scss rename to docs/_scss/extensions/_grid-framework.scss diff --git a/_scss/_mixins.scss b/docs/_scss/extensions/_mixins.scss similarity index 88% rename from _scss/_mixins.scss rename to docs/_scss/extensions/_mixins.scss index af00815..1bd62ce 100644 --- a/_scss/_mixins.scss +++ b/docs/_scss/extensions/_mixins.scss @@ -18,6 +18,14 @@ } } +// https://caniuse.com/#feat=css-media-interaction +// https://bugzilla.mozilla.org/show_bug.cgi?id=1035774#c9 +@mixin with-fine-pointer() { + @media (-moz-touch-enabled: 0), (pointer: fine) { + @content; + } +} + @mixin clearfix() { &::before, &::after { diff --git a/_scss/_variables.scss b/docs/_scss/extensions/_variables.scss similarity index 82% rename from _scss/_variables.scss rename to docs/_scss/extensions/_variables.scss index 6968d06..5f3c173 100644 --- a/_scss/_variables.scss +++ b/docs/_scss/extensions/_variables.scss @@ -7,44 +7,34 @@ $breakpoints: ( ); // Colors from Flat UI - $turqoise: #1ABC9C; $greenSea: #16A085; - $emerald: #2ECC71; $nephritis: #27AE60; - $river: #3498DB; $belizeHole: #2980B9; - $amethyst: #9B59B6; $wisteria: #8E44AD; - -$wetAsphalt: #34495E; +$wet-asphalt: #34495E; $midnightBlue: #2C3E50; - $sunflower: #F1C40F; $orange: #F39C12; - $carrot: #E67E22; $pumpkin: #D35400; - $alizarin: #E74C3C; $pomegranate: #C0392B; - $clouds: #ECF0F1; $silver: #BDC3C7; - $concrete: #95A5A6; $asbestos: #7F8C8D; - -// - $black: #000; $gray10: $midnightBlue; -$gray20: $wetAsphalt; +$gray20: $wet-asphalt; $gray30: #5D6D77; -$gray40: $concrete; $gray50: $asbestos; +$gray60: $concrete; +$gray80: $silver; +$gray90: #E1E5E6; +$gray95: $clouds; $white: #FFF; diff --git a/docs/_scss/global-rules/_forms.scss b/docs/_scss/global-rules/_forms.scss new file mode 100644 index 0000000..d400cfc --- /dev/null +++ b/docs/_scss/global-rules/_forms.scss @@ -0,0 +1,40 @@ +.textfield { + -webkit-appearance: none; + box-sizing: border-box; + width: 100%; + border: 2px solid $gray60; + border-radius: 4px; + padding: 0.5em; + font-size: 1rem; + color: $gray20; + transition: .15s; + + &::placeholder { + color: $gray60; + transition: .15s; + } + + &:hover { + outline-width: 0; + color: $gray30; + border-color: $gray30; + + &::placeholder { + color: $gray30; + } + } + + &:focus { + outline-width: 0; + // color: $gray20; + border-color: $gray20; + + &::placeholder { + color: $gray20; + } + } +} + +.textfield--large { + font-size: 1.125em; +} diff --git a/_scss/_global.scss b/docs/_scss/global-rules/_global.scss similarity index 64% rename from _scss/_global.scss rename to docs/_scss/global-rules/_global.scss index e1ba129..a37e9dd 100644 --- a/_scss/_global.scss +++ b/docs/_scss/global-rules/_global.scss @@ -36,31 +36,15 @@ li { line-height: 1.4; } -nav > a { - display: block; - margin: 5px 0; -} - -.breathable-list li { - line-height: 1.7; -} - -// Filters -.filter__label { - margin: 0 0 3px; +li + li { + margin-top: 4px; } -.filter__search { +nav > a { + display: block; margin: 5px 0; } - -.sort-options { - margin-top: 10px; -} - -#be-social { - h2 { - margin-bottom: 32px; - } +#demos { + margin-top: 1em; } diff --git a/_scss/_grid.scss b/docs/_scss/global-rules/_grid.scss similarity index 96% rename from _scss/_grid.scss rename to docs/_scss/global-rules/_grid.scss index 29df1e9..00dc7c7 100644 --- a/_scss/_grid.scss +++ b/docs/_scss/global-rules/_grid.scss @@ -1,4 +1,4 @@ -@import "grid-framework"; +@import "../extensions/grid-framework"; // .container .#{$grid-container} { @@ -81,8 +81,10 @@ .code-block { position: relative; overflow: visible; - margin-left: calc(-3.5vw - #{($grid-gutter-width / 2)}); + margin-top: 0.5em; margin-right: calc(-3.5vw - #{($grid-gutter-width / 2)}); + margin-bottom: 0.5em; + margin-left: calc(-3.5vw - #{($grid-gutter-width / 2)}); pre { position: relative; @@ -92,7 +94,7 @@ padding-bottom: 1em; padding-left: calc(3.5vw + #{($grid-gutter-width / 2)}); padding-right: calc(3.5vw + #{($grid-gutter-width / 2)}); - margin: .5em 0; + margin: 0; } } diff --git a/_scss/_helpers.scss b/docs/_scss/global-rules/_helpers.scss similarity index 93% rename from _scss/_helpers.scss rename to docs/_scss/global-rules/_helpers.scss index 1eb7ef1..5120cf0 100644 --- a/_scss/_helpers.scss +++ b/docs/_scss/global-rules/_helpers.scss @@ -8,6 +8,10 @@ .hidden\@xs { display: none; } } +@include breakpoint(sm) { + .visible\@xs { display: none; } +} + // Hide from both screenreaders and browsers. .hidden { display: none !important; diff --git a/docs/_scss/global-rules/_type.scss b/docs/_scss/global-rules/_type.scss new file mode 100644 index 0000000..54eb782 --- /dev/null +++ b/docs/_scss/global-rules/_type.scss @@ -0,0 +1,132 @@ +body { + font-family: 'Open Sans', 'Helvetica Neue', Helvetica, sans-serif; + color: $gray30; +} + +// Links +a { + text-decoration: none; + + &, + &:visited { + color: $river; + } + + &:hover { + text-decoration: underline; + } + + &:active { + color: $emerald; + } +} + +h1, +h2, +h3, +h4, +h5, +h6 { + color: $gray20; + font-weight: 700; +} + +h1 { + margin: 3vw 0; + font-size: 10vw; + font-weight: 400; + line-height: 1; +} + +h2 { + position: relative; + font-size: 7vw; + margin: 3vw 0; +} + +h3 { + font-size: 6vw; + margin: 2vw 0; +} + +h4 { + font-size: 1.25em; +} + +p { + margin: 1em 0; + line-height: 1.4; +} + +.intro-text { + margin: 0.7em 0; + font-size: 1.125em; +} + +@include breakpoint(sm) { + h1 { + margin: 0.5em 0 0.25em; + font-size: 3.5em; + } + + h2 { + margin: 0.45em 0; + font-size: 2.5em; + } + + h3 { + margin: 0.8em 0 0.5em; + font-size: 1.5em; + } + + h1 > a, + h2 > a, + h3 > a { + display: none; + } + + h1:hover > a, + h2:hover > a, + h3:hover > a { + position: absolute; + display: inline-block; + top: 0; + height: 50px; + width: 50px; + background: url('../img/link.svg') no-repeat; + overflow: hidden; + text-indent: -999em; + } + + .intro-text { + font-size: 1.25em; + } +} + +.unstyled { + list-style-type: none; + padding: 0; + margin: 0; +} + +.type--underline { + text-decoration: underline; +} + +code:not([class*="language"]) { + padding: 0; + padding-top: 0.2em; + padding-bottom: 0.2em; + margin: 0; + font-size: 85%; + color: $gray10; + background-color: rgba(27,31,35,0.05); + border-radius: 3px; + font-family: Menlo, Consolas, "Liberation Mono", Courier, monospace; +} + +code:not([class*="language"])::before, +code:not([class*="language"])::after { + content: "\00a0"; + letter-spacing: -.2em; +} diff --git a/_scss/_compound-filters.scss b/docs/_scss/pages/_compound-filters.scss similarity index 96% rename from _scss/_compound-filters.scss rename to docs/_scss/pages/_compound-filters.scss index f9ffa04..adf03e3 100644 --- a/_scss/_compound-filters.scss +++ b/docs/_scss/pages/_compound-filters.scss @@ -1,4 +1,4 @@ -@import "variables"; +@import "../extensions/variables"; .compound-filter-options { @@ -12,6 +12,7 @@ width: 40px; height: 40px; padding: 0; + background-color: currentColor; } label { @@ -23,10 +24,6 @@ } } -.filter-group__label--compound { - margin: 0 0 5px; -} - .shape-shuffle-container { position: relative; overflow: hidden; diff --git a/docs/_scss/pages/_faq.scss b/docs/_scss/pages/_faq.scss new file mode 100644 index 0000000..9947d4d --- /dev/null +++ b/docs/_scss/pages/_faq.scss @@ -0,0 +1,37 @@ +// FAQ + +.search-section { + margin-top: 1em; + margin-bottom: 1em; +} + +.question { + float: none; + margin: 2em 0; + overflow: hidden; + transition: .2s ease-out; +} + +.question--collapsed { + height: 0 !important; // Needs to override inline style + margin: 0; + border-width: 0; +} + +.question--collapsed + .question { + margin-top: 0; +} + +.question--unanswered { + padding-top: 1.25em; + border-top: 2px solid $emerald; +} + +.question__title { + margin-top: 0; +} + +.question__answer { + padding-bottom: 1px; + margin-bottom: 0; +} diff --git a/docs/_scss/pages/_homepage-filters.scss b/docs/_scss/pages/_homepage-filters.scss new file mode 100644 index 0000000..4e59181 --- /dev/null +++ b/docs/_scss/pages/_homepage-filters.scss @@ -0,0 +1,19 @@ + +// Filters +.filter-label { + display: block; + margin-top: 0; + margin-bottom: 4px; + color: $gray60; +} + +.filters-group { + margin-bottom: 4px; +} + +@include breakpoint(sm) { + .filters-group-wrap { + display: flex; + justify-content: space-between; + } +} diff --git a/_scss/shuffle-styles.scss b/docs/_scss/shuffle-styles.scss similarity index 72% rename from _scss/shuffle-styles.scss rename to docs/_scss/shuffle-styles.scss index a07a0c2..aaabd31 100644 --- a/_scss/shuffle-styles.scss +++ b/docs/_scss/shuffle-styles.scss @@ -1,58 +1,68 @@ -@import "variables"; -@import "mixins"; +@import "./extensions/variables"; +@import "./extensions/mixins"; /*=============================================*\ Some styles to show off masonry layout \*=============================================*/ -$pictureGutter: 24px; -$itemHeight: 220px; +$picture-gutter: 24px; +$item-height: 220px; .picture-item { height: 220px; - margin-top: $pictureGutter; + margin-top: $picture-gutter; margin-left: 0; /* shuffle items shouldn't have a left margin*/ img { display: block; width: 100%; + } +} + +@supports (object-fit: cover) { + .picture-item img { max-width: none; height: 100%; object-fit: cover; } - - .no-objectfit & img { - height: auto; - max-width: 100%; - } } .picture-item--h2 { - height: ($itemHeight * 2) + $pictureGutter; /* 2x the height + 1 gutter */ + height: ($item-height * 2) + $picture-gutter; /* 2x the height + 1 gutter */ } .picture-item__inner { position: relative; height: 100%; overflow: hidden; - background: $clouds; + background: $gray95; } -.picture-item__blur { +img.picture-item__blur { display: none; } -.picture-item__details, -.picture-item__description { - padding: 1em; +.picture-item__details { + display: flex; + align-items: baseline; + justify-content: space-between; width: 100%; + padding: 1em; } + .picture-item__description { + width: 100%; + padding: 0 2em 1em 1em; margin: 0; - padding-top: 0; - padding-right: 2em; +} + +.picture-item__title { + flex-shrink: 0; + margin-right: 4px; } .picture-item__tags { + flex-shrink: 1; + text-align: right; margin: 0; } @@ -86,7 +96,7 @@ $itemHeight: 220px; left: 0; display: block; filter: blur(7px); - clip-path: inset(#{$itemHeight - 50px} 0 0 0); + clip-path: inset(#{$item-height - 50px} 0 0 0); } .picture-item__details { @@ -146,29 +156,20 @@ $itemHeight: 220px; .picture-item { height: auto; margin-top: 20px; + } - &.picture-item--h2 { - height: auto; - } - - .picture-item__details, - .picture-item__description { - font-size: .875em; - padding: .625em; - } - - .picture-item__description { - padding-right: .875em; - padding-bottom: 1.25em; - } + .picture-item__details, + .picture-item__description { + font-size: .875em; + padding: .625em; } - .filter > .row, - .filter > .row > div { - margin: 10px 0; + .picture-item__description { + padding-right: .875em; + padding-bottom: 1.25em; } - .m-nofloat { - float: none; + .picture-item--h2 { + height: auto; } } diff --git a/docs/_scss/style.scss b/docs/_scss/style.scss new file mode 100644 index 0000000..5303374 --- /dev/null +++ b/docs/_scss/style.scss @@ -0,0 +1,16 @@ +@import "./extensions/variables"; +@import "./extensions/mixins"; + +@import "./global-rules/global"; +@import "./global-rules/type"; +@import "./global-rules/grid"; +@import "./global-rules/forms"; +@import "./global-rules/helpers"; + +@import "./components/buttons"; +@import "./components/demo-list"; +@import "./components/site-nav"; + +@import "./pages/homepage-filters"; +@import "./pages/compound-filters"; +@import "./pages/faq"; diff --git a/docs/css/normalize.css b/docs/css/normalize.css new file mode 100644 index 0000000..e04d10a --- /dev/null +++ b/docs/css/normalize.css @@ -0,0 +1,3 @@ +/*! normalize.css v7.0.0 | MIT License | github.com/necolas/normalize.css */ +/* search cancel styles removed */ +html{line-height:1.15;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,main,menu,nav,section{display:block}h1{font-size:2em;margin:.67em 0}figure{margin:1em 40px}hr{box-sizing:content-box;height:0;overflow:visible}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}a{background-color:transparent;-webkit-text-decoration-skip:objects}abbr[title]{border-bottom:none;text-decoration:underline dotted}b,strong{font-weight:bolder}dfn{font-style:italic}mark{background-color:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}audio,canvas,video{display:inline-block}audio:not([controls]){display:none;height:0}img{border-style:none}svg:not(:root){overflow:hidden}button,input,optgroup,select,textarea{font-family:sans-serif;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:.35em .75em .625em}legend{color:inherit;display:table;max-width:100%;white-space:normal}progress{display:inline-block;vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio],legend{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}[hidden],template{display:none} diff --git a/css/prism.css b/docs/css/prism.css similarity index 90% rename from css/prism.css rename to docs/css/prism.css index 57ba41d..cf4a934 100644 --- a/css/prism.css +++ b/docs/css/prism.css @@ -1,4 +1,4 @@ -/* http://prismjs.com/download.html?themes=prism&languages=markup+css+clike+javascript+scss&plugins=line-highlight+file-highlight */ +/* http://prismjs.com/download.html?themes=prism&languages=markup+css+clike+javascript+jsx+scss&plugins=line-highlight+file-highlight */ /** * prism.js default theme for JavaScript, CSS and HTML * Based on dabblet (http://dabblet.com) @@ -150,9 +150,6 @@ pre[data-line] { margin-top: 1em; /* Same as .prism’s padding-top */ background: hsla(24, 20%, 50%,.08); - background: -moz-linear-gradient(to right, hsla(24, 20%, 50%,.1) 70%, hsla(24, 20%, 50%,0)); - background: -webkit-linear-gradient(to right, hsla(24, 20%, 50%,.1) 70%, hsla(24, 20%, 50%,0)); - background: -o-linear-gradient(to right, hsla(24, 20%, 50%,.1) 70%, hsla(24, 20%, 50%,0)); background: linear-gradient(to right, hsla(24, 20%, 50%,.1) 70%, hsla(24, 20%, 50%,0)); pointer-events: none; diff --git a/docs/css/shuffle-styles.css b/docs/css/shuffle-styles.css new file mode 100644 index 0000000..12eba13 --- /dev/null +++ b/docs/css/shuffle-styles.css @@ -0,0 +1 @@ +.picture-item{height:220px;margin-top:24px;margin-left:0}.picture-item img{display:block;width:100%}@supports ((-o-object-fit:cover) or (object-fit:cover)){.picture-item img{max-width:none;height:100%;-o-object-fit:cover;object-fit:cover}}.picture-item--h2{height:464px}.picture-item__inner{position:relative;height:100%;overflow:hidden;background:#ecf0f1}img.picture-item__blur{display:none}.picture-item__details{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:baseline;-ms-flex-align:baseline;align-items:baseline;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;width:100%;padding:1em}.picture-item__description{width:100%;padding:0 2em 1em 1em;margin:0}.picture-item__title{-ms-flex-negative:0;flex-shrink:0;margin-right:4px}.picture-item__tags{-ms-flex-negative:1;flex-shrink:1;text-align:right;margin:0}@media screen and (min-width:768px){.picture-item--overlay .picture-item__details{position:absolute;bottom:0;left:0;width:100%;background-color:rgba(0,0,0,.6);color:#fff;overflow:hidden}.picture-item--overlay .picture-item__description{display:none}@supports ((-webkit-filter:blur(1px)) or (filter:blur(1px))) and ((-webkit-clip-path:inset(0 0 0 0)) or (clip-path:inset(0 0 0 0))){.picture-item--overlay .picture-item__blur{position:absolute;z-index:1;top:0;left:0;display:block;-webkit-filter:blur(7px);filter:blur(7px);-webkit-clip-path:inset(170px 0 0 0);clip-path:inset(170px 0 0 0)}.picture-item--overlay .picture-item__details{background:none}.picture-item--overlay .picture-item__tags,.picture-item--overlay .picture-item__title{position:relative;z-index:2}}}.my-shuffle-container{position:relative;overflow:hidden}.my-sizer-element{position:absolute;opacity:0;visibility:hidden}.shuffle--animatein{overflow:visible}.shuffle--animatein .picture-item__inner{opacity:0;-webkit-transform:translateY(220px);transform:translateY(220px)}.shuffle--animatein .picture-item__inner--transition{transition:all .6s ease}.shuffle--animatein .picture-item.in .picture-item__inner{opacity:1;-webkit-transform:translate(0);transform:translate(0)}@media screen and (max-width:767px){.picture-item{height:auto;margin-top:20px}.picture-item__description,.picture-item__details{font-size:.875em;padding:.625em}.picture-item__description{padding-right:.875em;padding-bottom:1.25em}.picture-item--h2{height:auto}} \ No newline at end of file diff --git a/docs/css/style.css b/docs/css/style.css new file mode 100644 index 0000000..1b8c21b --- /dev/null +++ b/docs/css/style.css @@ -0,0 +1 @@ +@charset "UTF-8";*,:after,:before{box-sizing:border-box}main{overflow:hidden}pre.max-height{max-height:30em}img,picture{display:block}img{max-width:100%;height:auto}figure,ul ul{margin:0}ul ul{padding-left:1.25em;list-style-type:circle}li{line-height:1.4}li+li{margin-top:4px}nav>a{display:block;margin:5px 0}#demos{margin-top:1em}body{font-family:Open Sans,Helvetica Neue,Helvetica,sans-serif;color:#5d6d77}a{text-decoration:none}a,a:visited{color:#3498db}a:hover{text-decoration:underline}a:active{color:#2ecc71}h1,h2,h3,h4,h5,h6{color:#34495e;font-weight:700}h1{font-size:10vw;font-weight:400;line-height:1}h1,h2{margin:3vw 0}h2{position:relative;font-size:7vw}h3{font-size:6vw;margin:2vw 0}h4{font-size:1.25em}p{margin:1em 0;line-height:1.4}.intro-text{margin:.7em 0;font-size:1.125em}@media screen and (min-width:768px){h1{margin:.5em 0 .25em;font-size:3.5em}h2{margin:.45em 0;font-size:2.5em}h3{margin:.8em 0 .5em;font-size:1.5em}h1>a,h2>a,h3>a{display:none}h1:hover>a,h2:hover>a,h3:hover>a{position:absolute;display:inline-block;top:0;height:50px;width:50px;background:url(../img/link.svg) no-repeat;overflow:hidden;text-indent:-999em}.intro-text{font-size:1.25em}}.unstyled{list-style-type:none;padding:0;margin:0}.type--underline{text-decoration:underline}code:not([class*=language]){padding:.2em 0;margin:0;font-size:85%;color:#2c3e50;background-color:rgba(27,31,35,.05);border-radius:3px;font-family:Menlo,Consolas,Liberation Mono,Courier,monospace}code:not([class*=language]):after,code:not([class*=language]):before{content:"\00a0";letter-spacing:-.2em}.container{padding-left:3.5%;padding-right:3.5%}.container:after,.container:before{content:" ";display:table}.container:after{clear:both}.row{margin-left:auto;margin-right:auto}.row:after,.row:before{content:" ";display:table}.row:after{clear:both}.row .row{margin-left:-8px;margin-right:-8px}.row--centered{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.aspect{position:relative;width:100%;height:0;overflow:hidden;padding-bottom:100%}.aspect--16x9{padding-bottom:56.25%}.aspect--9x16{padding-bottom:177.77778%}.aspect--4x3{padding-bottom:75%}.aspect--3x4{padding-bottom:133.33333%}.aspect--3x2{padding-bottom:66.66667%}.aspect--3x1{padding-bottom:33.33333%}.aspect--2x3{padding-bottom:150%}.aspect--2x1{padding-bottom:50%}.aspect--1x2{padding-bottom:200%}.aspect--1x1{padding-bottom:100%}.aspect--none{height:auto;padding-bottom:0;overflow:visible}.aspect--none>.aspect__inner{position:static}.aspect>div,.aspect__inner{position:absolute;top:0;left:0;right:0;bottom:0}.col-1\@lg,.col-1\@md,.col-1\@sm,.col-1\@xs,.col-2\@lg,.col-2\@md,.col-2\@sm,.col-2\@xs,.col-3\@lg,.col-3\@md,.col-3\@sm,.col-3\@xs,.col-4\@lg,.col-4\@md,.col-4\@sm,.col-4\@xs,.col-5\@lg,.col-5\@md,.col-5\@sm,.col-5\@xs,.col-6\@lg,.col-6\@md,.col-6\@sm,.col-6\@xs,.col-7\@lg,.col-7\@md,.col-7\@sm,.col-7\@xs,.col-8\@lg,.col-8\@md,.col-8\@sm,.col-8\@xs,.col-9\@lg,.col-9\@md,.col-9\@sm,.col-9\@xs,.col-10\@lg,.col-10\@md,.col-10\@sm,.col-10\@xs,.col-11\@lg,.col-11\@md,.col-11\@sm,.col-11\@xs,.col-12\@lg,.col-12\@md,.col-12\@sm,.col-12\@xs{position:relative;box-sizing:border-box;min-height:1px;padding-left:8px;padding-right:8px}.col-1\@xs,.col-2\@xs,.col-3\@xs,.col-4\@xs,.col-5\@xs,.col-6\@xs,.col-7\@xs,.col-8\@xs,.col-9\@xs,.col-10\@xs,.col-11\@xs,.col-12\@xs{float:left}.aspect--16x9\@xs{padding-bottom:56.25%}.aspect--9x16\@xs{padding-bottom:177.77778%}.aspect--4x3\@xs{padding-bottom:75%}.aspect--3x4\@xs{padding-bottom:133.33333%}.aspect--3x2\@xs{padding-bottom:66.66667%}.aspect--3x1\@xs{padding-bottom:33.33333%}.aspect--2x3\@xs{padding-bottom:150%}.aspect--2x1\@xs{padding-bottom:50%}.aspect--1x2\@xs{padding-bottom:200%}.aspect--1x1\@xs{padding-bottom:100%}.aspect--none\@xs{height:auto;padding-bottom:0;overflow:visible}.aspect--none\@xs>.aspect__inner{position:static}.col-1\@xs{width:16.66667%}.col-2\@xs{width:33.33333%}.col-3\@xs{width:50%}.col-4\@xs{width:66.66667%}.col-5\@xs{width:83.33333%}.col-6\@xs{width:100%}.col-pull-0\@xs{right:auto}.col-pull-1\@xs{right:16.66667%}.col-pull-2\@xs{right:33.33333%}.col-pull-3\@xs{right:50%}.col-pull-4\@xs{right:66.66667%}.col-pull-5\@xs{right:83.33333%}.col-pull-6\@xs{right:100%}.col-push-0\@xs{left:auto}.col-push-1\@xs{left:16.66667%}.col-push-2\@xs{left:33.33333%}.col-push-3\@xs{left:50%}.col-push-4\@xs{left:66.66667%}.col-push-5\@xs{left:83.33333%}.col-push-6\@xs{left:100%}.col-offset-0\@xs{margin-left:0}.col-offset-1\@xs{margin-left:16.66667%}.col-offset-2\@xs{margin-left:33.33333%}.col-offset-3\@xs{margin-left:50%}.col-offset-4\@xs{margin-left:66.66667%}.col-offset-5\@xs{margin-left:83.33333%}.col-offset-6\@xs{margin-left:100%}@media screen and (min-width:768px){.col-1\@sm,.col-2\@sm,.col-3\@sm,.col-4\@sm,.col-5\@sm,.col-6\@sm,.col-7\@sm,.col-8\@sm,.col-9\@sm,.col-10\@sm,.col-11\@sm,.col-12\@sm{float:left}.aspect--16x9\@sm{padding-bottom:56.25%}.aspect--9x16\@sm{padding-bottom:177.77778%}.aspect--4x3\@sm{padding-bottom:75%}.aspect--3x4\@sm{padding-bottom:133.33333%}.aspect--3x2\@sm{padding-bottom:66.66667%}.aspect--3x1\@sm{padding-bottom:33.33333%}.aspect--2x3\@sm{padding-bottom:150%}.aspect--2x1\@sm{padding-bottom:50%}.aspect--1x2\@sm{padding-bottom:200%}.aspect--1x1\@sm{padding-bottom:100%}.aspect--none\@sm{height:auto;padding-bottom:0;overflow:visible}.aspect--none\@sm>.aspect__inner{position:static}.col-1\@sm{width:8.33333%}.col-2\@sm{width:16.66667%}.col-3\@sm{width:25%}.col-4\@sm{width:33.33333%}.col-5\@sm{width:41.66667%}.col-6\@sm{width:50%}.col-7\@sm{width:58.33333%}.col-8\@sm{width:66.66667%}.col-9\@sm{width:75%}.col-10\@sm{width:83.33333%}.col-11\@sm{width:91.66667%}.col-12\@sm{width:100%}.col-pull-0\@sm{right:auto}.col-pull-1\@sm{right:8.33333%}.col-pull-2\@sm{right:16.66667%}.col-pull-3\@sm{right:25%}.col-pull-4\@sm{right:33.33333%}.col-pull-5\@sm{right:41.66667%}.col-pull-6\@sm{right:50%}.col-pull-7\@sm{right:58.33333%}.col-pull-8\@sm{right:66.66667%}.col-pull-9\@sm{right:75%}.col-pull-10\@sm{right:83.33333%}.col-pull-11\@sm{right:91.66667%}.col-pull-12\@sm{right:100%}.col-push-0\@sm{left:auto}.col-push-1\@sm{left:8.33333%}.col-push-2\@sm{left:16.66667%}.col-push-3\@sm{left:25%}.col-push-4\@sm{left:33.33333%}.col-push-5\@sm{left:41.66667%}.col-push-6\@sm{left:50%}.col-push-7\@sm{left:58.33333%}.col-push-8\@sm{left:66.66667%}.col-push-9\@sm{left:75%}.col-push-10\@sm{left:83.33333%}.col-push-11\@sm{left:91.66667%}.col-push-12\@sm{left:100%}.col-offset-0\@sm{margin-left:0}.col-offset-1\@sm{margin-left:8.33333%}.col-offset-2\@sm{margin-left:16.66667%}.col-offset-3\@sm{margin-left:25%}.col-offset-4\@sm{margin-left:33.33333%}.col-offset-5\@sm{margin-left:41.66667%}.col-offset-6\@sm{margin-left:50%}.col-offset-7\@sm{margin-left:58.33333%}.col-offset-8\@sm{margin-left:66.66667%}.col-offset-9\@sm{margin-left:75%}.col-offset-10\@sm{margin-left:83.33333%}.col-offset-11\@sm{margin-left:91.66667%}.col-offset-12\@sm{margin-left:100%}.container{padding-left:7%;padding-right:7%}.row{max-width:1200px}}@media screen and (min-width:1024px){.col-1\@md,.col-2\@md,.col-3\@md,.col-4\@md,.col-5\@md,.col-6\@md,.col-7\@md,.col-8\@md,.col-9\@md,.col-10\@md,.col-11\@md,.col-12\@md{float:left}.aspect--16x9\@md{padding-bottom:56.25%}.aspect--9x16\@md{padding-bottom:177.77778%}.aspect--4x3\@md{padding-bottom:75%}.aspect--3x4\@md{padding-bottom:133.33333%}.aspect--3x2\@md{padding-bottom:66.66667%}.aspect--3x1\@md{padding-bottom:33.33333%}.aspect--2x3\@md{padding-bottom:150%}.aspect--2x1\@md{padding-bottom:50%}.aspect--1x2\@md{padding-bottom:200%}.aspect--1x1\@md{padding-bottom:100%}.aspect--none\@md{height:auto;padding-bottom:0;overflow:visible}.aspect--none\@md>.aspect__inner{position:static}.col-1\@md{width:8.33333%}.col-2\@md{width:16.66667%}.col-3\@md{width:25%}.col-4\@md{width:33.33333%}.col-5\@md{width:41.66667%}.col-6\@md{width:50%}.col-7\@md{width:58.33333%}.col-8\@md{width:66.66667%}.col-9\@md{width:75%}.col-10\@md{width:83.33333%}.col-11\@md{width:91.66667%}.col-12\@md{width:100%}.col-pull-0\@md{right:auto}.col-pull-1\@md{right:8.33333%}.col-pull-2\@md{right:16.66667%}.col-pull-3\@md{right:25%}.col-pull-4\@md{right:33.33333%}.col-pull-5\@md{right:41.66667%}.col-pull-6\@md{right:50%}.col-pull-7\@md{right:58.33333%}.col-pull-8\@md{right:66.66667%}.col-pull-9\@md{right:75%}.col-pull-10\@md{right:83.33333%}.col-pull-11\@md{right:91.66667%}.col-pull-12\@md{right:100%}.col-push-0\@md{left:auto}.col-push-1\@md{left:8.33333%}.col-push-2\@md{left:16.66667%}.col-push-3\@md{left:25%}.col-push-4\@md{left:33.33333%}.col-push-5\@md{left:41.66667%}.col-push-6\@md{left:50%}.col-push-7\@md{left:58.33333%}.col-push-8\@md{left:66.66667%}.col-push-9\@md{left:75%}.col-push-10\@md{left:83.33333%}.col-push-11\@md{left:91.66667%}.col-push-12\@md{left:100%}.col-offset-0\@md{margin-left:0}.col-offset-1\@md{margin-left:8.33333%}.col-offset-2\@md{margin-left:16.66667%}.col-offset-3\@md{margin-left:25%}.col-offset-4\@md{margin-left:33.33333%}.col-offset-5\@md{margin-left:41.66667%}.col-offset-6\@md{margin-left:50%}.col-offset-7\@md{margin-left:58.33333%}.col-offset-8\@md{margin-left:66.66667%}.col-offset-9\@md{margin-left:75%}.col-offset-10\@md{margin-left:83.33333%}.col-offset-11\@md{margin-left:91.66667%}.col-offset-12\@md{margin-left:100%}}.code-block{position:relative;overflow:visible;margin:.5em calc(-3.5vw - 8px)}.code-block pre{position:relative;z-index:1;min-height:56px;padding:1em calc(3.5vw + 8px);margin:0}@media screen and (min-width:768px){.code-block{margin-left:calc(-7vw - 8px);margin-right:calc(-7vw - 8px)}.code-block pre{position:relative;z-index:1;padding-left:calc(7vw + 8px);padding-right:calc(7vw + 8px)}}@media (min-width:1395px){.code-block{margin-left:calc(-50vw + 592px);margin-right:calc(-50vw + 592px)}.code-block pre{padding-left:calc(50vw - 592px);padding-right:calc(50vw - 592px)}}.textfield{-webkit-appearance:none;box-sizing:border-box;width:100%;border:2px solid #95a5a6;border-radius:4px;padding:.5em;font-size:1rem;color:#34495e;transition:.15s}.textfield::-webkit-input-placeholder{color:#95a5a6;transition:.15s}.textfield:-ms-input-placeholder{color:#95a5a6;transition:.15s}.textfield::placeholder{color:#95a5a6;transition:.15s}.textfield:hover{outline-width:0;color:#5d6d77;border-color:#5d6d77}.textfield:hover::-webkit-input-placeholder{color:#5d6d77}.textfield:hover:-ms-input-placeholder{color:#5d6d77}.textfield:hover::placeholder{color:#5d6d77}.textfield:focus{outline-width:0;border-color:#34495e}.textfield:focus::-webkit-input-placeholder{color:#34495e}.textfield:focus:-ms-input-placeholder{color:#34495e}.textfield:focus::placeholder{color:#34495e}.textfield--large{font-size:1.125em}.text-center{text-align:center}.ib{display:inline-block}@media screen and (max-width:767px){.hidden\@xs{display:none}}@media screen and (min-width:768px){.visible\@xs{display:none}}.hidden{display:none!important;visibility:hidden}.visuallyhidden{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.clearfix,.clearfix:after{content:" ";display:table;clear:both}.pull-left{float:left}.pull-right{float:right}.full-width{width:100%}.full-height{height:100%}.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.table-center-wrap{display:table;table-layout:fixed}.table-center{display:table-cell;vertical-align:middle}.btn-group:after,.btn-group:before{content:" ";display:table}.btn-group:after{clear:both}.btn-group .btn{float:left;border-radius:0}.btn-group .btn:first-child{border-radius:3px 0 0 3px}.btn-group .btn:not(:first-child){margin-left:-1px}.btn-group .btn:last-child{border-radius:0 3px 3px 0}.btn-group label.btn input[type=radio]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.btn{display:inline-block;padding:.75em .8em;text-align:center;border-radius:3px;border:1px solid #34495e;color:#34495e;font-size:1rem;background-color:rgba(52,73,94,0);transition:.2s ease-out;cursor:pointer;-webkit-appearance:none}@media (-moz-touch-enabled:0),(pointer:fine){.btn:hover{color:#fff;text-decoration:none;background-color:#34495e}}.btn:focus{outline-width:0;box-shadow:0 0 0 2px rgba(52,73,94,.4)}.btn.active,.btn:active{box-shadow:inset 0 1px 2px rgba(0,0,0,.3);color:#fff;background-color:#34495e}.btn:focus.active{box-shadow:inset 0 1px 2px rgba(0,0,0,.3),0 0 0 2px rgba(52,73,94,.4)}.btn--warning{color:#e67e22;border-color:#e67e22;background-color:rgba(230,126,34,0)}@media (-moz-touch-enabled:0),(pointer:fine){.btn--warning:hover{background-color:#e67e22}}.btn--warning:focus{box-shadow:0 0 0 2px rgba(230,126,34,.4)}.btn--warning.active,.btn--warning:active{background-color:#e67e22}.btn--warning:focus.active{box-shadow:inset 0 1px 2px rgba(0,0,0,.3),0 0 0 2px rgba(230,126,34,.4)}.btn--primary{color:#3498db;border-color:#3498db;background-color:rgba(52,152,219,0)}@media (-moz-touch-enabled:0),(pointer:fine){.btn--primary:hover{background-color:#3498db}}.btn--primary:focus{box-shadow:0 0 0 2px rgba(52,152,219,.4)}.btn--primary.active,.btn--primary:active{background-color:#3498db}.btn--primary:focus.active{box-shadow:inset 0 1px 2px rgba(0,0,0,.3),0 0 0 2px rgba(52,152,219,.4)}.btn--danger{color:#e74c3c;border-color:#e74c3c;background-color:rgba(231,76,60,0)}@media (-moz-touch-enabled:0),(pointer:fine){.btn--danger:hover{background-color:#e74c3c}}.btn--danger:focus{box-shadow:0 0 0 2px rgba(231,76,60,.4)}.btn--danger.active,.btn--danger:active{background-color:#e74c3c}.btn--danger:focus.active{box-shadow:inset 0 1px 2px rgba(0,0,0,.3),0 0 0 2px rgba(231,76,60,.4)}.btn--go{color:#2ecc71;border-color:#2ecc71;background-color:rgba(46,204,113,0)}@media (-moz-touch-enabled:0),(pointer:fine){.btn--go:hover{background-color:#2ecc71}}.btn--go:focus{box-shadow:0 0 0 2px rgba(46,204,113,.4)}.btn--go.active,.btn--go:active{background-color:#2ecc71}.btn--go:focus.active{box-shadow:inset 0 1px 2px rgba(0,0,0,.3),0 0 0 2px rgba(46,204,113,.4)}@media screen and (max-width:767px){.btn{font-size:.875rem}}.filter-group .btn{position:relative}.filter-group .btn.active:after,.filter-group .btn.active:before{content:"";position:absolute;top:50%;left:50%;width:20px;height:20px;margin-left:-10px;margin-top:-10px;opacity:0;transition:.2s}.filter-group .btn:before{background-color:#2c3e50;border-radius:50%}.filter-group .btn:after{background-size:60%;background-position:50%;background-repeat:no-repeat;background-image:url(../img/check.svg)}.filter-group .btn.active:after,.filter-group .btn.active:before{opacity:1}.demo-list .figure-wrap{position:relative;z-index:1}.demo-list .figure-wrap,.demo-list .figure-wrap img{-webkit-transform:translateZ(0);transform:translateZ(0);transition:.1s ease}.demo-list:hover .figure-wrap{-webkit-transform:scaleX(1);transform:scaleX(1)}.demo-list:hover .figure-wrap img{-webkit-filter:grayscale(1);filter:grayscale(1)}.demo-list:hover .figure-wrap:hover{z-index:2;-webkit-transform:scale3d(1.05,1.05,1);transform:scale3d(1.05,1.05,1)}.demo-list:hover .figure-wrap:hover img{-webkit-filter:none;filter:none}.demo-list .figure-wrap:nth-child(4n+1){margin-left:0}.demo-list .figure-wrap>a{display:block}.demo-list .figure-wrap figcaption{height:2em;margin-top:.5em;margin-bottom:1em}.demo-link-container:before{content:"➜";color:#2ecc71;margin-right:5px}span.demo-link-container:before{margin-left:5px}@media screen and (max-width:47.9375em){.demo-list+.demo-list{margin-top:1em}.figure-wrap:nth-child(odd){margin-left:0}.figure-wrap:nth-child(n+3){margin-top:1em}}.site-nav{padding:10px 0;border-bottom:1px solid #e1e5e6;margin-bottom:28px;background:#ecf0f1}.site-nav__content{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}.site-nav__logo{font-size:20px}.site-nav__logo,.site-nav__logo:visited{color:#34495e}.site-nav__logo:hover,.site-nav__logo:visited:hover{text-decoration:none}.site-nav__links,.site-nav__logo{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.site-nav__logo svg{display:block;width:24px;height:24px;margin-right:4px}.site-nav__logo rect{transition:.18s cubic-bezier(.4,0,.2,1)}.site-nav__link{position:relative;z-index:3}.site-nav__link:not(:last-of-type){margin-right:8px}.site-nav__dropdown{position:absolute;z-index:2;top:40px;right:0;opacity:0;visibility:hidden;max-height:100vh;transition:.3s cubic-bezier(.165,.84,.44,1);background-color:#fff;-webkit-transform:translateY(10px);transform:translateY(10px);box-shadow:0 7px 10px -1px rgba(0,0,0,.12)}.site-nav__dropdown:before{content:"";position:absolute;top:-8px;right:32px;display:block;border-bottom:8px solid #fff;border-left:9px solid transparent;border-right:9px solid transparent}.site-nav__dropdown li+li{margin-top:8px}.site-nav__dropdown a{display:block;color:#5d6d77}.site-nav__dropdown a:hover{background-color:#ecf0f1;text-decoration:none;color:#5d6d77}.site-nav__dropdown figure{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.site-nav__dropdown picture{-ms-flex-negative:0;flex-shrink:0;width:100px;height:75px}.site-nav__dropdown figcaption{padding-left:8px;padding-right:8px}.site-nav__dropdown--simple-links a{padding:8px 16px}.site-nav__dropdown--simple-links li+li{margin-top:0}.site-nav__link-toggle{padding:6px 8px}.site-nav__link-toggle:after{content:"";display:inline-block;vertical-align:middle;margin-top:-1px;margin-left:4px;border-top:6px solid;border-left:5px solid transparent;border-right:5px solid transparent;transition:-webkit-transform .18s cubic-bezier(.4,0,.2,1);transition:transform .18s cubic-bezier(.4,0,.2,1);transition:transform .18s cubic-bezier(.4,0,.2,1),-webkit-transform .18s cubic-bezier(.4,0,.2,1)}.site-nav__link--dropdown-active .site-nav__link-toggle:after{-webkit-transform:rotate(-180deg);transform:rotate(-180deg)}.site-nav__link--dropdown-active .site-nav__dropdown{visibility:visible;opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}@media (-moz-touch-enabled:0),(pointer:fine){.site-nav__logo:hover rect:first-of-type{-webkit-transform:translate(20px,10px);transform:translate(20px,10px);transition-delay:0ms}.site-nav__logo:hover rect:nth-of-type(2){-webkit-transform:translateY(20px);transform:translateY(20px);transition-delay:10ms}.site-nav__logo:hover rect:nth-of-type(3){-webkit-transform:translate(-20px,6px);transform:translate(-20px,6px);transition-delay:20ms}.site-nav__logo:hover rect:nth-of-type(4){-webkit-transform:translate(10px,-10px);transform:translate(10px,-10px);transition-delay:30ms}.site-nav__logo:hover rect:nth-of-type(5){-webkit-transform:translate(-10px,10px);transform:translate(-10px,10px);transition-delay:40ms}.site-nav__logo:hover rect:nth-of-type(6){-webkit-transform:translate(-20px,-14px);transform:translate(-20px,-14px);transition-delay:50ms}.site-nav__logo:hover rect:nth-of-type(7){-webkit-transform:translateY(-20px);transform:translateY(-20px);transition-delay:60ms}.site-nav__link-toggle:hover{border-color:#34495e}}@media screen and (max-width:767px){body.site-nav--open{padding-top:51px}body.site-nav--open .site-nav{position:fixed;z-index:4;top:0;left:0;width:100%}.site-nav__dropdown{position:fixed;left:0;right:0;top:51px;width:100vw;padding:8px calc(3.5vw + 8px);overflow:auto;-webkit-overflow-scrolling:touch}}@media screen and (min-width:768px){.site-nav{padding:16px 0}.site-nav__logo{font-size:24px}.site-nav__logo svg{width:32px;height:32px}.site-nav__link:not(:last-child){margin-right:16px}.site-nav__link--dropdown:not(:last-child){margin-right:12px}.site-nav__dropdown{max-height:none!important;right:-100px;padding:16px;box-shadow:0 0 10px rgba(0,0,0,.12)}.site-nav__dropdown:before{right:132px}.site-nav__dropdown ul{-webkit-column-count:2;column-count:2;-webkit-column-gap:16px;column-gap:16px}.site-nav__dropdown li{-webkit-column-break-inside:avoid;break-inside:avoid}.site-nav__dropdown figcaption{white-space:nowrap}@supports ((-webkit-filter:drop-shadow(0 0 5px rgba(0,0,0,0.12))) or (filter:drop-shadow(0 0 5px rgba(0,0,0,0.12)))){.site-nav__dropdown{box-shadow:none;-webkit-filter:drop-shadow(0 0 5px rgba(0,0,0,.12));filter:drop-shadow(0 0 5px rgba(0,0,0,.12))}}.site-nav__link-img{width:24px;height:24px}.site-nav__dropdown--simple-links{right:0;padding:0}.site-nav__dropdown--simple-links:before{right:24px}.site-nav__dropdown--simple-links a{width:200px}}@media screen and (min-width:1024px){.site-nav__dropdown{right:0}.site-nav__dropdown:before{right:32px}.site-nav__dropdown--simple-links:before{right:24px}}.site-footer{margin-top:2em;padding:1em 0;background-color:#34495e}.site-footer p{color:#ecf0f1}.site-footer a{color:#fff;text-decoration:underline}.site-footer a:hover{color:#3498db}.has-code-block .code-block pre{margin-bottom:0}.has-code-block+.site-footer{margin-top:0}@media screen and (min-width:768px){.site-footer__credit{text-align:right}}.filter-label{display:block;margin-top:0;color:#95a5a6}.filter-label,.filters-group{margin-bottom:4px}@media screen and (min-width:768px){.filters-group-wrap{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}}.compound-filter-options{margin-top:20px;margin-bottom:40px}.filter-group--compound button{width:40px;height:40px;padding:0;background-color:currentColor}.filter-group--compound label{cursor:pointer}.filter-group--compound .ib+.ib{margin-left:8px}.shape-shuffle-container{position:relative;overflow:hidden}.shape{position:relative;margin-left:0;margin-top:10px}.shape .shape__space{width:100%;height:100%;background-color:#000;border:0 solid transparent}.shape--blue .shape__space{background-color:#3498db;border-bottom-color:#3498db}.shape--red .shape__space{background-color:#e74c3c;border-bottom-color:#e74c3c}.shape--orange .shape__space{background-color:#f39c12;border-bottom-color:#f39c12}.shape--green .shape__space{background-color:#2ecc71;border-bottom-color:#2ecc71}.shape--circle .shape__space{border-radius:50%}.shape--diamond .shape__space{-webkit-transform:rotate(45deg) scale(.70711);transform:rotate(45deg) scale(.70711)}.shape--triangle .shape__space{padding-top:9px;height:0;width:0;border-width:0 66px 114px;background-color:transparent;margin:auto}@media (min-width:425px){.shape--triangle .shape__space{padding-top:12px;height:0;width:0;border-width:0 90px 156px}}@media (min-width:600px){.shape--triangle .shape__space{padding-top:17.5px;height:0;width:0;border-width:0 131px 227px}}@media (min-width:768px){.shape--triangle .shape__space{padding-top:10px;height:0;width:0;border-width:0 74px 128px}}@media (min-width:1024px){.shape--triangle .shape__space{padding-top:13.5px;height:0;width:0;border-width:0 102px 177px}}@media (min-width:1200px){.shape--triangle .shape__space{padding-top:18px;height:0;width:0;border-width:0 135px 234px}}@media (min-width:1392px){.shape--triangle .shape__space{padding-top:19px;height:0;width:0;border-width:0 142px 246px}}.search-section{margin-top:1em;margin-bottom:1em}.question{float:none;margin:2em 0;overflow:hidden;transition:.2s ease-out}.question--collapsed{height:0!important;margin:0;border-width:0}.question--collapsed+.question{margin-top:0}.question--unanswered{padding-top:1.25em;border-top:2px solid #2ecc71}.question__title{margin-top:0}.question__answer{padding-bottom:1px;margin-bottom:0} \ No newline at end of file diff --git a/docs/dist b/docs/dist new file mode 120000 index 0000000..85d8c32 --- /dev/null +++ b/docs/dist @@ -0,0 +1 @@ +../dist \ No newline at end of file diff --git a/favicon.png b/docs/favicon.png similarity index 100% rename from favicon.png rename to docs/favicon.png diff --git a/img/check.svg b/docs/img/check.svg similarity index 100% rename from img/check.svg rename to docs/img/check.svg diff --git a/docs/img/demos/adding-removing.jpg b/docs/img/demos/adding-removing.jpg new file mode 100644 index 0000000..55c0ae8 Binary files /dev/null and b/docs/img/demos/adding-removing.jpg differ diff --git a/docs/img/demos/adding-removing.webp b/docs/img/demos/adding-removing.webp new file mode 100644 index 0000000..afdb6b2 Binary files /dev/null and b/docs/img/demos/adding-removing.webp differ diff --git a/docs/img/demos/animated.jpg b/docs/img/demos/animated.jpg new file mode 100644 index 0000000..404d72c Binary files /dev/null and b/docs/img/demos/animated.jpg differ diff --git a/docs/img/demos/animated.webp b/docs/img/demos/animated.webp new file mode 100644 index 0000000..a08b906 Binary files /dev/null and b/docs/img/demos/animated.webp differ diff --git a/docs/img/demos/basic.jpg b/docs/img/demos/basic.jpg new file mode 100644 index 0000000..6479e5d Binary files /dev/null and b/docs/img/demos/basic.jpg differ diff --git a/docs/img/demos/basic.webp b/docs/img/demos/basic.webp new file mode 100644 index 0000000..aa6200a Binary files /dev/null and b/docs/img/demos/basic.webp differ diff --git a/docs/img/demos/bootstrap3-grid.jpg b/docs/img/demos/bootstrap3-grid.jpg new file mode 100644 index 0000000..266ee4e Binary files /dev/null and b/docs/img/demos/bootstrap3-grid.jpg differ diff --git a/docs/img/demos/bootstrap3-grid.webp b/docs/img/demos/bootstrap3-grid.webp new file mode 100644 index 0000000..414b154 Binary files /dev/null and b/docs/img/demos/bootstrap3-grid.webp differ diff --git a/docs/img/demos/codepen-template.jpg b/docs/img/demos/codepen-template.jpg new file mode 100644 index 0000000..6a238d1 Binary files /dev/null and b/docs/img/demos/codepen-template.jpg differ diff --git a/docs/img/demos/codepen-template.webp b/docs/img/demos/codepen-template.webp new file mode 100644 index 0000000..94b5c46 Binary files /dev/null and b/docs/img/demos/codepen-template.webp differ diff --git a/docs/img/demos/compound-filters.jpg b/docs/img/demos/compound-filters.jpg new file mode 100644 index 0000000..6ee299e Binary files /dev/null and b/docs/img/demos/compound-filters.jpg differ diff --git a/docs/img/demos/compound-filters.webp b/docs/img/demos/compound-filters.webp new file mode 100644 index 0000000..b6d906d Binary files /dev/null and b/docs/img/demos/compound-filters.webp differ diff --git a/docs/img/demos/flexbox-grid.jpg b/docs/img/demos/flexbox-grid.jpg new file mode 100644 index 0000000..f55ee5b Binary files /dev/null and b/docs/img/demos/flexbox-grid.jpg differ diff --git a/docs/img/demos/flexbox-grid.webp b/docs/img/demos/flexbox-grid.webp new file mode 100644 index 0000000..383e140 Binary files /dev/null and b/docs/img/demos/flexbox-grid.webp differ diff --git a/docs/img/demos/images.jpg b/docs/img/demos/images.jpg new file mode 100644 index 0000000..0ddf7f8 Binary files /dev/null and b/docs/img/demos/images.jpg differ diff --git a/docs/img/demos/images.webp b/docs/img/demos/images.webp new file mode 100644 index 0000000..de3a930 Binary files /dev/null and b/docs/img/demos/images.webp differ diff --git a/docs/img/demos/requirejs.jpg b/docs/img/demos/requirejs.jpg new file mode 100644 index 0000000..818d444 Binary files /dev/null and b/docs/img/demos/requirejs.jpg differ diff --git a/docs/img/demos/requirejs.webp b/docs/img/demos/requirejs.webp new file mode 100644 index 0000000..57e2a6b Binary files /dev/null and b/docs/img/demos/requirejs.webp differ diff --git a/docs/img/demos/shuffle-with-react.jpg b/docs/img/demos/shuffle-with-react.jpg new file mode 100644 index 0000000..9ea36b8 Binary files /dev/null and b/docs/img/demos/shuffle-with-react.jpg differ diff --git a/docs/img/demos/shuffle-with-react.webp b/docs/img/demos/shuffle-with-react.webp new file mode 100644 index 0000000..6397e6c Binary files /dev/null and b/docs/img/demos/shuffle-with-react.webp differ diff --git a/img/favicon-sprite.png b/docs/img/favicon-sprite.png similarity index 100% rename from img/favicon-sprite.png rename to docs/img/favicon-sprite.png diff --git a/img/favicon-sprite@2x.png b/docs/img/favicon-sprite@2x.png similarity index 100% rename from img/favicon-sprite@2x.png rename to docs/img/favicon-sprite@2x.png diff --git a/img/favicon.psd b/docs/img/favicon.psd similarity index 100% rename from img/favicon.psd rename to docs/img/favicon.psd diff --git a/docs/img/favicon.svg b/docs/img/favicon.svg new file mode 100644 index 0000000..8de3579 --- /dev/null +++ b/docs/img/favicon.svg @@ -0,0 +1,10 @@ + + Shuffle.js logo + + + + + + + + diff --git a/docs/img/github.svg b/docs/img/github.svg new file mode 100644 index 0000000..e850b94 --- /dev/null +++ b/docs/img/github.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/img/link.svg b/docs/img/link.svg similarity index 100% rename from img/link.svg rename to docs/img/link.svg diff --git a/img/shuffle.png b/docs/img/shuffle.png similarity index 100% rename from img/shuffle.png rename to docs/img/shuffle.png diff --git a/index.html b/docs/index.html similarity index 66% rename from index.html rename to docs/index.html index aa14024..04c9d26 100644 --- a/index.html +++ b/docs/index.html @@ -2,34 +2,18 @@ layout: default title: Shuffle.js bodyClass: home -extraJS: [ "demos/homepage.js" ] +extraJS: [ "demos/homepage.js", "animated-favicon.js" ] includeHeader: true prism: true ---
    -
    -

    Install

    -
    -
    -
    -
    npm install shufflejs --save
    -
    -

    Shuffle is also available on bower as shufflejs.

    -
    -
    -
    -
    @@ -39,31 +23,41 @@ prism: true
    -
    +
    -
    - + +
    + +
    +
    -
    -

    Filter:

    -
    - - - - + +
    +
    +

    Filter

    +
    + + + + +
    -
    -
    -
    -

    Sort:

    - +
    +

    Sort

    +
    + + + +
    @@ -72,10 +66,10 @@ prism: true
    - {% for item in site.data.items %} - {% assign item = item %} - {% include picture-item.html %} - {% endfor %} + {%- for item in site.data.items -%} + {%- assign item = item -%} + {%- include picture-item.html -%} + {%- endfor -%}
    @@ -122,11 +116,21 @@ prism: true
    -
    +
    - {% include events.html %} + {% include filters.html %} +
    +
    +
    +
    + +
    +
    +
    +
    + {% include advanced-filters.html %}
    @@ -142,11 +146,11 @@ prism: true
    -
    +
    - {% include advanced-filters.html %} + {% include events.html %}
    @@ -200,17 +204,17 @@ prism: true

    Dependencies

    Shuffle's dependencies are bundled with the dist file.

    +

    Shuffle does, however, expect the following ES6/7 features: Set, Array.from, Object.assign, Array.prototype.find, and Array.prototype.includes. In order to support browsers like IE11 and Safari 8, you must include a polyfill for these features. You can use a service like polyfill.io to only load the polyfills that specific browser needs, or a polyfill script like babel-polyfill (which uses core-js internally).

    - -
    +
    -

    Supported Browsers

    +

    Supported Browsers

    • Chrome
    • @@ -220,7 +224,7 @@ prism: true
    • Safari
    -

    Support for other browsers may be added with polyfills for ES5 features. If you require broader browser support, use the most recent v3 release of Shuffle.

    +

    Depending on what browsers you support, you may need to polyfill features used by Shuffle.

    @@ -243,7 +247,6 @@ prism: true
    -
    @@ -254,9 +257,6 @@ prism: true
    - -{% include credit-jake.html %} - + diff --git a/test/test.js b/test/test.js index ea2c23e..ad36006 100644 --- a/test/test.js +++ b/test/test.js @@ -8,7 +8,7 @@ var sinon = window.sinon; describe('shuffle', function () { - var Shuffle = window.shuffle; + var Shuffle = window.Shuffle; var fixtures = {}; var fixture; var instance; @@ -62,19 +62,6 @@ describe('shuffle', function () { fixture = null; } - function once(element, eventType, fn) { - var handler = function (e) { - element.removeEventListener(eventType, handler); - fn(e); - }; - - element.addEventListener(eventType, handler); - } - - function toArray(thing) { - return Array.prototype.slice.call(thing); - } - function id(id) { return document.getElementById(id); } @@ -110,7 +97,6 @@ describe('shuffle', function () { expect(instance.options.delimeter).to.equal(null); expect(instance.options.initialSort).to.equal(null); expect(instance.options.throttleTime).to.equal(300); - expect(instance.useSizer).to.equal(false); expect(instance.id).to.equal('shuffle_0'); expect(instance.isInitialized).to.be.true; @@ -128,13 +114,13 @@ describe('shuffle', function () { instance.items.forEach(function (item) { expect(item.element).to.have.class('shuffle-item'); expect(item.element).to.have.class('shuffle-item--visible'); - expect(item.element.style.opacity).to.be.defined; + expect(item.element.style.opacity).to.be.exist; expect(item.element.style.position).to.equal('absolute'); expect(item.element.style.visibility).to.equal('visible'); expect(item.isVisible).to.equal(true); expect(item.scale).to.equal(Shuffle.ShuffleItem.Scale.VISIBLE); - expect(item.point.x).to.be.defined; - expect(item.point.y).to.be.defined; + expect(item.point.x).to.be.exist; + expect(item.point.y).to.be.exist; }); }); @@ -237,7 +223,7 @@ describe('shuffle', function () { expect(element.style.visibility).to.equal('visible'); }); - once(fixture, Shuffle.EventType.LAYOUT, third); + instance.once(Shuffle.EventType.LAYOUT, third); // Filter by green. instance.filter('green'); @@ -266,7 +252,7 @@ describe('shuffle', function () { done(); } - once(fixture, Shuffle.EventType.LAYOUT, second); + instance.once(Shuffle.EventType.LAYOUT, second); instance.filter('design'); }); @@ -317,6 +303,42 @@ describe('shuffle', function () { expect(Shuffle.__getAvailablePositions(positions, 2, 4)).to.deep.equal([150, 0, 0]); }); + it('can center already-positioned items', function() { + // 4-2-1 even heights + expect(Shuffle.__getCenteredPositions([ + new Shuffle.Rect(0, 0, 250, 100, 0), + new Shuffle.Rect(250, 0, 250, 100, 1), + new Shuffle.Rect(500, 0, 250, 100, 2), + new Shuffle.Rect(750, 0, 250, 100, 3), + new Shuffle.Rect(0, 100, 600, 100, 4), + new Shuffle.Rect(600, 100, 300, 100, 5), + new Shuffle.Rect(0, 200, 250, 100, 6), + ], 1000)).to.deep.equal([ + new Shuffle.Point(0, 0), + new Shuffle.Point(250, 0), + new Shuffle.Point(500, 0), + new Shuffle.Point(750, 0), + new Shuffle.Point(50, 100), + new Shuffle.Point(650, 100), + new Shuffle.Point(375, 200), + ]); + + // 4 columns: + // 2x2 1x1 + // 2x1 + // Centers the first row, but then finds that the 3rd item will overlap + // the 2x2 and resets the first row. + expect(Shuffle.__getCenteredPositions([ + new Shuffle.Rect(0, 0, 500, 200, 0), + new Shuffle.Rect(500, 0, 250, 100, 1), + new Shuffle.Rect(500, 100, 500, 100, 2), + ], 1000)).to.deep.equal([ + new Shuffle.Point(0, 0), + new Shuffle.Point(500, 0), + new Shuffle.Point(500, 100), + ]); + }); + it('can get an element option', function () { instance = new Shuffle(fixture); var first = fixture.firstElementChild; @@ -393,13 +415,13 @@ describe('shuffle', function () { instance.destroy(); expect(instance.element).to.be.null; - expect(instance.items).to.be.null; + expect(instance.items).to.have.lengthOf(0); expect(instance.options.sizer).to.be.null; expect(instance.isDestroyed).to.be.true; expect(fixture).to.not.have.class('shuffle'); - toArray(fixture.children).forEach(function (child) { + Array.from(fixture.children).forEach(function (child) { expect(child).to.not.have.class('shuffle-item'); expect(child).to.not.have.class('shuffle-item--visible'); expect(child).to.not.have.class('shuffle-item--hidden'); @@ -425,20 +447,20 @@ describe('shuffle', function () { expect(update.called).to.be.false; }); - it('should not update when the container is the same size', function () { + it('should still update when the container is the same size', function () { instance = new Shuffle(fixture); var update = sinon.spy(instance, 'update'); instance._onResize(); - expect(update.called).to.be.false; + expect(update.called).to.be.true; }); describe('removing elements', function () { var children; beforeEach(function () { - children = toArray(fixture.children); + children = Array.from(fixture.children); }); afterEach(function () { @@ -450,12 +472,11 @@ describe('shuffle', function () { speed: 16, }); - once(fixture, Shuffle.EventType.REMOVED, function (evt) { - var detail = evt.detail; - expect(detail.shuffle.visibleItems).to.equal(8); - expect(detail.collection[0].id).to.equal('item1'); - expect(detail.collection[1].id).to.equal('item2'); - expect(detail.shuffle.element.children).to.have.lengthOf(8); + instance.once(Shuffle.EventType.REMOVED, function (data) { + expect(data.shuffle.visibleItems).to.equal(8); + expect(data.collection[0].id).to.equal('item1'); + expect(data.collection[1].id).to.equal('item2'); + expect(data.shuffle.element.children).to.have.lengthOf(8); expect(instance.isTransitioning).to.be.false; done(); }); @@ -470,13 +491,12 @@ describe('shuffle', function () { useTransforms: false, }); - once(fixture, Shuffle.EventType.REMOVED, function (evt) { - var detail = evt.detail; - expect(detail.shuffle.visibleItems).to.equal(8); - expect(detail.collection[0].id).to.equal('item2'); - expect(detail.collection[1].id).to.equal('item3'); - expect(detail.shuffle.element.children).to.have.lengthOf(8); - expect(detail.shuffle.isTransitioning).to.be.false; + instance.once(Shuffle.EventType.REMOVED, function (data) { + expect(data.shuffle.visibleItems).to.equal(8); + expect(data.collection[0].id).to.equal('item2'); + expect(data.collection[1].id).to.equal('item3'); + expect(data.shuffle.element.children).to.have.lengthOf(8); + expect(data.shuffle.isTransitioning).to.be.false; done(); }); @@ -538,14 +558,11 @@ describe('shuffle', function () { }); }); - afterEach(function (done) { - once(fixture, Shuffle.EventType.LAYOUT, function () { - items.length = 0; - done(); - }); + afterEach(function () { + items.length = 0; }); - it('can add items', function () { + it('can add items', function (done) { fixture.appendChild(items[0]); fixture.appendChild(items[1]); instance.add(items); @@ -553,9 +570,13 @@ describe('shuffle', function () { // Already 2 in the items, plus number 11. expect(instance.visibleItems).to.equal(3); expect(instance.items).to.have.lengthOf(12); + + instance.once(Shuffle.EventType.LAYOUT, function () { + done(); + }); }); - it('can prepend items', function () { + it('can prepend items', function (done) { fixture.insertBefore(items[1], fixture.firstElementChild); fixture.insertBefore(items[0], fixture.firstElementChild); instance.add(items); @@ -563,6 +584,23 @@ describe('shuffle', function () { expect(instance.items[0].element).to.equal(items[0]); expect(instance.items[1].element).to.equal(items[1]); expect(instance.items).to.have.lengthOf(12); + + instance.once(Shuffle.EventType.LAYOUT, function () { + done(); + }); + }); + + it('can reset items', function () { + fixture.textContent = ''; + fixture.appendChild(items[0]); + fixture.appendChild(items[1]); + + instance.resetItems(); + + expect(instance.isInitialized).to.be.true; + expect(instance.items[0].element).to.equal(items[0]); + expect(instance.items[1].element).to.equal(items[1]); + expect(instance.items).to.have.lengthOf(2); }); }); @@ -632,11 +670,11 @@ describe('shuffle', function () { beforeEach(function (done) { appendFixture('regular').then(function () { - items = toArray(fixture.children).map(function (element) { + items = Array.from(fixture.children).map(function (element) { return { element: element }; }); - clone = toArray(items); + clone = Array.from(items); done(); }); @@ -656,7 +694,7 @@ describe('shuffle', function () { expect(items).to.have.lengthOf(10); expect(Shuffle.__sorter(items)).to.deep.equal(items); - var clone = toArray(items); + var clone = Array.from(items); expect(Shuffle.__sorter(clone, { randomize: true })).to.not.deep.equal(items); });