pull/380/head
Glen Cheney 2 years ago
parent 34b086274b
commit 8a4911e100

@ -1,13 +1,3 @@
{
"presets": [
[
"@babel/preset-env",
{
"targets": {
"browsers": "> 1%, not dead, not IE < 11, IE 11, not OperaMini all",
"node": "current"
}
}
]
]
"presets": [["@babel/preset-env"]]
}

@ -0,0 +1,4 @@
> 1%
not dead
not ie <= 11
not OperaMini all

@ -4,7 +4,6 @@ about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
**Shuffle version**
@ -18,6 +17,7 @@ A minimal JSBin, JSFiddle, Codepen, or a GitHub repository that can reproduce th
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
@ -30,15 +30,17 @@ A clear and concise description of what you expected to happen.
If applicable, add screenshots to help explain your problem.
**Desktop (please complete the following information):**
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
**Smartphone (please complete the following information):**
- Device: [e.g. iPhone6]
- OS: [e.g. iOS8.1]
- Browser [e.g. stock browser, safari]
- Version [e.g. 22]
- Device: [e.g. iPhone6]
- OS: [e.g. iOS8.1]
- Browser [e.g. stock browser, safari]
- Version [e.g. 22]
**Additional context**
Add any other context about the problem here.

@ -4,7 +4,6 @@ about: Suggest an idea for this project
title: ''
labels: enhancement
assignees: ''
---
**Is your feature request related to a problem? Please describe.**

@ -1,12 +1,12 @@
version: 2
updates:
- package-ecosystem: npm
directory: "/"
schedule:
interval: weekly
time: "13:00"
open-pull-requests-limit: 10
ignore:
- dependency-name: cssnano
versions:
- 5.0.0
- package-ecosystem: npm
directory: '/'
schedule:
interval: weekly
time: '13:00'
open-pull-requests-limit: 10
ignore:
- dependency-name: cssnano
versions:
- 5.0.0

@ -0,0 +1,14 @@
node_modules
dist
coverage
docs/dist
docs/css
docs/_site
prism.js
prism.css
.jekyll-cache
# Prettier can't handle liquid templates AND changes the JSON attributes to use
# double quotes, breaking the parser.
*.html

@ -12,19 +12,19 @@ Without a reduced test case, your issue may be closed.
## Releasing a new version
* Update `changelog.html`.
* Run tests.
* Commit changes.
* `npm version major|minor|patch`.
* `npm publish`
* `git push && git push --tags`
* Create a [new release](https://github.com/Vestride/Shuffle/releases/new) on GitHub.
- Update `changelog.html`.
- Run tests.
- Commit changes.
- `npm version major|minor|patch`.
- `npm publish`
- `git push && git push --tags`
- Create a [new release](https://github.com/Vestride/Shuffle/releases/new) on GitHub.
## Running locally
This project uses [Jekyll](https://jekyllrb.com/).
* Head over to [their quickstart guide](https://jekyllrb.com/docs/quickstart/) to setup jekyll.
* Install npm dependencies `npm install`.
* Run `npm run watch` to rebuild, start the jekyll server, and watch for changes.
* go to `http://localhost:4000` to see it.
- Head over to [their quickstart guide](https://jekyllrb.com/docs/quickstart/) to setup jekyll.
- Install npm dependencies `npm install`.
- Run `npm run watch` to rebuild, start the jekyll server, and watch for changes.
- go to `http://localhost:4000` to see it.

2328
dist/shuffle.js vendored

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -1,10 +1,10 @@
source: .
source: .
destination: _site
plugins_dir: _plugins
layouts_dir: _layouts
data_dir: _data
include: ["dist"]
exclude: ["./_scss"]
data_dir: _data
include: ['dist']
exclude: ['./_scss']
permalink: /:title

@ -1,7 +1,6 @@
# Options in this file override ones set in _config.yml
host: 0.0.0.0
environment: "development"
environment: 'development'
url: http://localhost:4000
baseurl: ""
baseurl: ''

@ -8,7 +8,7 @@
* Create some DOM elements, append them to the shuffle container, then notify
* shuffle about the new items. You could also insert the HTML as a string.
*/
Demo.prototype.onAppendBoxes = function () {
onAppendBoxes() {
var elements = this._getArrayOfElementsToAdd();
elements.forEach(function (element) {

@ -13,12 +13,12 @@ shuffleInstance.filter(function (element) {
<h3>Searching</h3>
<div class="code-block">
<pre rel="JavaScript"><code class="language-javascript">// Advanced filtering
Demo.prototype.addSearchFilter = function () {
addSearchFilter() {
document.querySelector('.js-shuffle-search').addEventListener('keyup', this._handleSearchKeyup.bind(this));
};
// Filter the shuffle instance by items with a title that matches the search input.
Demo.prototype._handleSearchKeyup = function (evt) {
_handleSearchKeyup(evt) {
var searchText = evt.target.value.toLowerCase();
this.shuffle.filter(function (element, shuffle) {

@ -4,6 +4,7 @@
GitHub.
</p>
<ul>
<li><code>v6.0.0</code> 2022-02-01 - Drop IE 11, remove misspelled <code>delimeter</code> option, remove <code>matches-selector</code> package.</li>
<li>
<code>v5.4.1</code> 2021-05-29 - Add <code>sortedItems</code> property. Fix <code>getComputedStyle</code> bug for
Chrome on Windows.

@ -1,7 +1,6 @@
{% if page.requirejs %}
<script data-main="{{ site.baseurl }}/js/require-main.js" src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.3/require.min.js"></script>
{% else %}
<script crossorigin="anonymous" src="https://polyfill.io/v3/polyfill.min.js?features=default%2Ces5%2Ces6%2Ces7"></script>
<!-- Syntax highlighting via Prism -->
<script src="{{ site.baseurl }}/js/prism.js"></script>
<!-- Shuffle! -->

@ -15,11 +15,11 @@
</div>
<div class="code-block">
<pre rel="JavaScript"><code class="language-javascript">Demo.prototype.addSorting = function () {
<pre rel="JavaScript"><code class="language-javascript">addSorting() {
document.querySelector('.sort-options').addEventListener('change', this._handleSortChange.bind(this));
};
Demo.prototype._handleSortChange = function (evt) {
_handleSortChange(evt) {
var value = evt.target.value;
function sortByDate(element) {

@ -10,7 +10,7 @@
</div>
</header>
{% endif %}
<main role="main" id="main">
<main id="main">
{{ content }}
</main>
{% include footer.html %}

@ -150,7 +150,7 @@ photoCredit: false
<h3>Adding elements</h3>
<p>Wherever you add the element in the DOM is where it will show up in the grid (assuming you&rsquo;re using the default sort-by-dom-order). With this in mind, you can append, prepend, or insert elements wherever you need to get them to show up in the right order.</p>
<div class="code-block">
<pre rel="JavaScript"><code class="language-javascript">Demo.prototype.setupEvents = function () {
<pre rel="JavaScript"><code class="language-javascript">setupEvents() {
document.querySelector('#append').addEventListener('click', this.onAppendBoxes.bind(this));
};
@ -158,7 +158,7 @@ photoCredit: false
* Create some DOM elements, append them to the shuffle container, then notify
* shuffle about the new items. You could also insert the HTML as a string.
*/
Demo.prototype.onAppendBoxes = function () {
onAppendBoxes() {
var elements = this._getArrayOfElementsToAdd();
elements.forEach(function (element) {

@ -4,7 +4,7 @@ title: Animate In Demo
description: When elements enter the viewport, they transition in from zero opacity and from the bottom.
image: /demos/animated.jpg
prism: true
externalJS: [ "https://unpkg.com/intersection-observer" ]
externalJS: []
extraJS: [ "demos/animate-in.js" ]
---
<div class="container">
@ -38,7 +38,7 @@ extraJS: [ "demos/animate-in.js" ]
<div class="col-12@sm">
<h2>About this demo</h2>
<p>This was inspired by <a href="http://tympanus.net/codrops/">codrops</a>&rsquo; demo <a href="http://tympanus.net/codrops/2013/07/02/loading-effects-for-grid-items-with-css-animations/">Loading effects for grid items with css animations</a>.</p>
<p><code>IntersectionObserver</code> is used to determine when the elements enter the viewport. <a href="https://github.com/WICG/IntersectionObserver/tree/gh-pages/polyfill">A polyfill</a> is included on the page for browsers which don't support it.</p>
<p><code>IntersectionObserver</code> is used to determine when the elements enter the viewport.</p>
</div>
<div class="col-12@sm">
<h2>Source code for this demo</h2>

@ -18,7 +18,7 @@
border-radius: 0 3px 3px 0;
}
label.btn input[type=radio] {
label.btn input[type='radio'] {
position: absolute;
clip: rect(0, 0, 0, 0);
pointer-events: none;
@ -27,14 +27,14 @@
.btn {
display: inline-block;
padding: .75em .8em;
padding: 0.75em 0.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;
transition: 0.2s ease-out;
cursor: pointer;
-webkit-appearance: none;
@ -53,13 +53,13 @@
&.active,
&:active {
box-shadow: inset 0 1px 2px rgba(0,0,0,.3);
box-shadow: inset 0 1px 2px rgba(0, 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);
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.3), 0 0 0 2px rgba($gray20, 0.4);
}
&:disabled {
@ -99,7 +99,7 @@ $btn-variants: (
}
&:focus.active {
box-shadow: inset 0 1px 2px rgba(0,0,0,.3), 0 0 0 2px rgba($color, 0.4);
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.3), 0 0 0 2px rgba($color, 0.4);
}
&:disabled {
@ -128,10 +128,10 @@ $btn-variants: (
left: 50%;
width: $size;
height: $size;
margin-left: -$size / 2;
margin-top: -$size / 2;
margin-left: -$size * 0.5;
margin-top: -$size * 0.5;
opacity: 0;
transition: .2s;
transition: 0.2s;
}
// Circle

@ -7,21 +7,20 @@
.demo-list .figure-wrap img {
// Promote to its own layer. makes filters look ok on retina with images
transform: translateZ(0);
transition: .1s ease;
transition: 0.1s ease;
}
.demo-list:hover .figure-wrap {
transform: scale3d( 1, 1, 1 );
transform: scale3d(1, 1, 1);
img {
filter: grayscale(1);
}
}
.demo-list:hover .figure-wrap:hover {
z-index: 2;
transform: scale3d( 1.05, 1.05, 1 );
transform: scale3d(1.05, 1.05, 1);
img {
filter: none;
@ -38,11 +37,10 @@
.demo-list .figure-wrap figcaption {
height: 2em;
margin-top: .5em;
margin-top: 0.5em;
margin-bottom: 1em;
}
.demo-link-container::before {
content: '';
display: inline-block;
@ -59,7 +57,6 @@ span.demo-link-container::before {
}
@media screen and (max-width: 47.9375em) {
.demo-list + .demo-list {
margin-top: 1em;
}

@ -1,4 +1,7 @@
.site-nav {
position: sticky;
top: 0;
z-index: 40;
padding: 10px 0;
border-bottom: 1px solid $gray90;
margin-bottom: 28px;
@ -37,7 +40,7 @@
}
.site-nav__logo rect {
transition: 180ms cubic-bezier(0.4, 0.0, 0.2, 1);
transition: 180ms cubic-bezier(0.4, 0, 0.2, 1);
}
.site-nav__link {
@ -51,7 +54,7 @@
.site-nav__dropdown {
position: absolute;
z-index: 2;
z-index: 50;
top: 40px;
right: 0;
opacity: 0;
@ -130,7 +133,7 @@
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);
transition: transform 180ms cubic-bezier(0.4, 0, 0.2, 1);
}
.site-nav__link--dropdown-active {
@ -302,7 +305,6 @@
}
.site-nav__dropdown--simple-links {
&::before {
right: 24px;
}

@ -1,3 +1,5 @@
@use 'sass:math';
$grid-gutter-width: 16px;
$grid-columns: 12;
$grid-container: 'container';
@ -8,34 +10,23 @@ $grid-ratio-name: 'aspect';
$grid-ratio-inner-name: 'aspect__inner';
$grid-container-padding: (
xs: 3.5%,
sm: 7%
sm: 7%,
);
$grid-max-width--desktop: 1200px;
$grid-ratios: (
(16, 9),
(9, 16),
(4, 3),
(3, 4),
(3, 2),
(3, 1),
(2, 3),
(2, 1),
(1, 2),
(1, 1)
);
$grid-ratios: ((16, 9), (9, 16), (4, 3), (3, 4), (3, 2), (3, 1), (2, 3), (2, 1), (1, 2), (1, 1));
// 7% => 0.07
$_grid-padding-pct: map-get($grid-container-padding, "sm") / 100%;
$_grid-padding-pct: math.div(map-get($grid-container-padding, 'sm'), 100%);
// 0.07 => 0.14 => 0.86
$_grid-padding-value: 1 - $_grid-padding-pct * 2;
// Size of the window when the grid row has hit max-width.
$_viewport-at-max-grid-width: $grid-max-width--desktop / $_grid-padding-value;
$_viewport-at-max-grid-width: math.div($grid-max-width--desktop, $_grid-padding-value);
$viewport-at-max-grid-width: round($_viewport-at-max-grid-width) + 0px;
$padding-at-max-grid-width: round($_viewport-at-max-grid-width * $_grid-padding-pct) + 0px;
@function get-column-selector($number, $breakpoint) {
@return ".#{$grid-prefix}-#{$number}\\@#{$breakpoint}";
@return '.#{$grid-prefix}-#{$number}\\@#{$breakpoint}';
}
@function get-grid-breakpoint-selectors($breakpoint) {
@ -56,7 +47,6 @@ $padding-at-max-grid-width: round($_viewport-at-max-grid-width * $_grid-padding-
@return $selectors;
}
@mixin make-grid-columns() {
$selectors: get-all-grid-breakpoint-selectors();
@ -66,12 +56,11 @@ $padding-at-max-grid-width: round($_viewport-at-max-grid-width * $_grid-padding-
// Prevent columns from collapsing when empty
min-height: 1px;
// Inner gutter via padding
padding-left: ($grid-gutter-width / 2);
padding-right: ($grid-gutter-width / 2);
padding-left: ($grid-gutter-width * 0.5);
padding-right: ($grid-gutter-width * 0.5);
}
}
@mixin float-grid-columns($breakpoint) {
$selectors: get-grid-breakpoint-selectors($breakpoint);
@ -80,21 +69,20 @@ $padding-at-max-grid-width: round($_viewport-at-max-grid-width * $_grid-padding-
}
}
@mixin grid-ratios($breakpoint: "") {
@mixin grid-ratios($breakpoint: '') {
// If there is a grid breakpoint class here, prepend a @.
// e.g. "@sm" or "" when there isn't a class.
@if $breakpoint != "" {
$breakpoint: "\\@" + $breakpoint;
@if $breakpoint != '' {
$breakpoint: '\\@'+ $breakpoint;
}
// Note @extend isn't used because it cannot be used within @media directives.
@each $list in $grid-ratios {
$top: nth($list, 1);
$bottom: nth($list, 2);
$name: "#{$top}x#{$bottom}";
$name: '#{$top}x#{$bottom}';
.#{$grid-ratio-name}--#{$name}#{$breakpoint} {
padding-bottom: percentage($bottom / $top);
padding-bottom: percentage(math.div($bottom, $top));
}
}
@ -109,34 +97,34 @@ $padding-at-max-grid-width: round($_viewport-at-max-grid-width * $_grid-padding-
}
@mixin calc-grid-column($index, $columns, $breakpoint, $type) {
@if ($type == "width") and ($index > 0) {
@if ($type == 'width') and ($index > 0) {
.#{$grid-prefix}-#{$index}\@#{$breakpoint} {
width: percentage(($index / $columns));
width: percentage(math.div($index, $columns));
}
}
@if ($type == "push") and ($index > 0) {
@if ($type == 'push') and ($index > 0) {
.#{$grid-prefix}-push-#{$index}\@#{$breakpoint} {
left: percentage(($index / $columns));
left: percentage(math.div($index, $columns));
}
}
@if ($type == "push") and ($index == 0) {
@if ($type == 'push') and ($index == 0) {
.#{$grid-prefix}-push-0\@#{$breakpoint} {
left: auto;
}
}
@if ($type == "pull") and ($index > 0) {
@if ($type == 'pull') and ($index > 0) {
.#{$grid-prefix}-pull-#{$index}\@#{$breakpoint} {
right: percentage(($index / $columns));
right: percentage(math.div($index, $columns));
}
}
@if ($type == "pull") and ($index == 0) {
@if ($type == 'pull') and ($index == 0) {
.#{$grid-prefix}-pull-0\@#{$breakpoint} {
right: auto;
}
}
@if ($type == "offset") {
@if ($type == 'offset') {
.#{$grid-prefix}-offset-#{$index}\@#{$breakpoint} {
margin-left: percentage(($index / $columns));
margin-left: percentage(math.div($index, $columns));
}
}
}
@ -152,8 +140,8 @@ $padding-at-max-grid-width: round($_viewport-at-max-grid-width * $_grid-padding-
@include float-grid-columns($breakpoint);
@include grid-ratios($breakpoint);
@include loop-grid-columns($columns, $breakpoint, "width");
@include loop-grid-columns($columns, $breakpoint, "pull");
@include loop-grid-columns($columns, $breakpoint, "push");
@include loop-grid-columns($columns, $breakpoint, "offset");
@include loop-grid-columns($columns, $breakpoint, 'width');
@include loop-grid-columns($columns, $breakpoint, 'pull');
@include loop-grid-columns($columns, $breakpoint, 'push');
@include loop-grid-columns($columns, $breakpoint, 'offset');
}

@ -1,4 +1,3 @@
// @param {string} bp Breakpoint value. One of `xs, sm, md, lg`.
// @param {boolean} isMaxWidth By default, the media queries are mobile first,
// so they use `min-width: __px`. By passing `true`, the mixin will subtract
@ -6,11 +5,13 @@
// @param {boolean} isScreenOnly Whether to hide this media query from print styles.
//
// Note: For print media, we want the default styles and the xs breakpoint to take effect.
@use 'sass:math';
@mixin breakpoint($bp, $isMaxWidth: false, $isScreenOnly: true) {
$media-query: get-breakpoint-query($bp, $isMaxWidth);
@if $isScreenOnly {
$media-query: "screen and #{$media-query}";
$media-query: 'screen and #{$media-query}';
}
@media #{$media-query} {
@ -29,7 +30,7 @@
@mixin clearfix() {
&::before,
&::after {
content: " ";
content: ' ';
display: table;
}
@ -47,7 +48,7 @@
}
@mixin aspect($width, $height) {
padding-bottom: percentage($height / $width);
padding-bottom: percentage(math.div($height, $width));
}
@mixin no-aspect() {
@ -65,9 +66,9 @@
}
@if map-has-key($breakpoints, $bp) {
@return "(#{$media}: #{$breakpoint})";
@return '(#{$media}: #{$breakpoint})';
} @else {
@warn "#{$bp} not recognized. Valid breakpoints: #{map-keys($breakpoints)}";
@return "screen";
@return 'screen';
}
}

@ -3,38 +3,38 @@ $breakpoints: (
sm: 768px,
md: 1024px,
lg: 1392px,
xl: 1680px
xl: 1680px,
);
// Colors from Flat UI
$turqoise: #1ABC9C;
$greenSea: #16A085;
$emerald: #2ECC71;
$nephritis: #27AE60;
$river: #3498DB;
$belizeHole: #2980B9;
$amethyst: #9B59B6;
$wisteria: #8E44AD;
$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;
$turqoise: #1abc9c;
$greenSea: #16a085;
$emerald: #2ecc71;
$nephritis: #27ae60;
$river: #3498db;
$belizeHole: #2980b9;
$amethyst: #9b59b6;
$wisteria: #8e44ad;
$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: $wet-asphalt;
$gray30: #5D6D77;
$gray30: #5d6d77;
$gray50: $asbestos;
$gray60: $concrete;
$gray80: $silver;
$gray90: #E1E5E6;
$gray90: #e1e5e6;
$gray95: $clouds;
$white: #FFF;
$white: #fff;

@ -7,11 +7,11 @@
padding: 0.5em;
font-size: 1rem;
color: $gray20;
transition: .15s;
transition: 0.15s;
&::placeholder {
color: $gray60;
transition: .15s;
transition: 0.15s;
}
&:hover {

@ -1,9 +1,11 @@
@import "../extensions/grid-framework";
@use 'sass:math';
@import '../extensions/grid-framework';
// .container
.#{$grid-container} {
padding-left: map-get($grid-container-padding, "xs");
padding-right: map-get($grid-container-padding, "xs");
padding-left: map-get($grid-container-padding, 'xs');
padding-right: map-get($grid-container-padding, 'xs');
@include clearfix();
}
@ -14,8 +16,8 @@
@include clearfix();
.#{$grid-row} {
margin-left: $grid-gutter-width / -2;
margin-right: $grid-gutter-width / -2;
margin-left: math.div($grid-gutter-width, -2);
margin-right: math.div($grid-gutter-width, -2);
}
&--centered {
@ -50,13 +52,12 @@
@include make-grid(xs, 6);
@include breakpoint(sm) {
@include make-grid(sm);
// Add more padding to the container class.
.#{$grid-container} {
padding-left: map-get($grid-container-padding, "sm");
padding-right: map-get($grid-container-padding, "sm");
padding-left: map-get($grid-container-padding, 'sm');
padding-right: map-get($grid-container-padding, 'sm');
}
.#{$grid-row} {
@ -65,7 +66,6 @@
}
@include breakpoint(md) {
@include make-grid(md);
}
@ -73,9 +73,9 @@
position: relative;
overflow: visible;
margin-top: 0.5em;
margin-right: calc(-3.5vw - #{($grid-gutter-width / 2)});
margin-right: calc(-3.5vw - #{($grid-gutter-width * 0.5)});
margin-bottom: 0.5em;
margin-left: calc(-3.5vw - #{($grid-gutter-width / 2)});
margin-left: calc(-3.5vw - #{($grid-gutter-width * 0.5)});
pre {
position: relative;
@ -83,23 +83,22 @@
min-height: 56px;
padding-top: 1em;
padding-bottom: 1em;
padding-left: calc(3.5vw + #{($grid-gutter-width / 2)});
padding-right: calc(3.5vw + #{($grid-gutter-width / 2)});
padding-left: calc(3.5vw + #{($grid-gutter-width * 0.5)});
padding-right: calc(3.5vw + #{($grid-gutter-width * 0.5)});
margin: 0;
}
}
@include breakpoint(sm) {
.code-block {
margin-left: calc(-7vw - #{($grid-gutter-width / 2)});
margin-right: calc(-7vw - #{($grid-gutter-width / 2)});
margin-left: calc(-7vw - #{($grid-gutter-width * 0.5)});
margin-right: calc(-7vw - #{($grid-gutter-width * 0.5)});
pre {
position: relative;
z-index: 1;
padding-left: calc(7vw + #{($grid-gutter-width / 2)});
padding-right: calc(7vw + #{($grid-gutter-width / 2)});
padding-left: calc(7vw + #{($grid-gutter-width * 0.5)});
padding-right: calc(7vw + #{($grid-gutter-width * 0.5)});
}
}
}
@ -120,14 +119,13 @@
// }
@media (min-width: $viewport-at-max-grid-width) {
.code-block {
margin-left: calc(((100vw - #{$grid-max-width--desktop}) / -2) - #{$grid-gutter-width / 2});
margin-right: calc(((100vw - #{$grid-max-width--desktop}) / -2) - #{$grid-gutter-width / 2});
margin-left: calc(((100vw - #{$grid-max-width--desktop}) / -2) - #{$grid-gutter-width * 0.5});
margin-right: calc(((100vw - #{$grid-max-width--desktop}) / -2) - #{$grid-gutter-width * 0.5});
pre {
padding-left: calc(((100vw - #{$grid-max-width--desktop}) / 2) + #{$grid-gutter-width / 2});
padding-right: calc(((100vw - #{$grid-max-width--desktop}) / 2) + #{$grid-gutter-width / 2});
padding-left: calc(((100vw - #{$grid-max-width--desktop}) / 2) + #{$grid-gutter-width * 0.5});
padding-right: calc(((100vw - #{$grid-max-width--desktop}) / 2) + #{$grid-gutter-width * 0.5});
}
}
}

@ -1,15 +1,21 @@
.text-center { text-align: center; }
.text-center {
text-align: center;
}
.ib {
display: inline-block;
}
@include breakpoint(sm, true) {
.hidden\@xs { display: none; }
.hidden\@xs {
display: none;
}
}
@include breakpoint(sm) {
.visible\@xs { display: none; }
.visible\@xs {
display: none;
}
}
// Hide from both screenreaders and browsers.
@ -32,7 +38,7 @@
.clearfix,
.clearfix::after {
content: " ";
content: ' ';
display: table;
clear: both;
}
@ -45,8 +51,12 @@
float: right;
}
.full-width { width: 100%; }
.full-height { height: 100%; }
.full-width {
width: 100%;
}
.full-height {
height: 100%;
}
.hide-text {
font: 0/0 a;

@ -113,20 +113,20 @@ p {
text-decoration: underline;
}
code:not([class*="language"]) {
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);
background-color: rgba(27, 31, 35, 0.05);
border-radius: 3px;
font-family: Menlo, Consolas, "Liberation Mono", Courier, monospace;
font-family: Menlo, Consolas, 'Liberation Mono', Courier, monospace;
}
code:not([class*="language"])::before,
code:not([class*="language"])::after {
content: "\00a0";
letter-spacing: -.2em;
code:not([class*='language'])::before,
code:not([class*='language'])::after {
content: '\00a0';
letter-spacing: -0.2em;
}

@ -1,5 +1,4 @@
@import "../extensions/variables";
@import '../extensions/variables';
.compound-filter-options {
margin-top: 20px;
@ -7,7 +6,6 @@
}
.filter-group--compound {
button {
width: 40px;
height: 40px;
@ -73,14 +71,13 @@
transform: rotate(45deg) scale(0.707106781);
}
@mixin equilateralTriangle($size) {
$sqrt3: 1.73205080757;
$halfSize: $size / 2;
$halfSize: $size * 0.5;
$fullSideWidth: round($sqrt3 * $halfSize);
$leftOver: $size - $fullSideWidth;
padding-top: $leftOver / 2;
padding-top: $leftOver * 0.5;
height: 0;
width: 0;
border-width: 0 $halfSize $fullSideWidth $halfSize;

@ -9,7 +9,7 @@
float: none;
margin: 2em 0;
overflow: hidden;
transition: .2s ease-out;
transition: 0.2s ease-out;
}
.question--collapsed {
@ -18,7 +18,7 @@
border-width: 0;
}
.question--collapsed + .question {
.question--collapsed + .question {
margin-top: 0;
}

@ -1,4 +1,3 @@
// Filters
.filter-label {
display: block;

@ -1,5 +1,5 @@
@import "./extensions/variables";
@import "./extensions/mixins";
@import './extensions/variables';
@import './extensions/mixins';
/*=============================================*\
Some styles to show off masonry layout
@ -67,15 +67,13 @@ img.picture-item__blur {
}
@include breakpoint(sm) {
.picture-item--overlay {
.picture-item__details {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
background-color: rgba(black, .6);
background-color: rgba(black, 0.6);
color: white;
overflow: hidden;
}
@ -86,9 +84,7 @@ img.picture-item__blur {
}
@supports (filter: blur(1px)) and (clip-path: inset(0 0 0 0)) {
.picture-item--overlay {
.picture-item__blur {
position: absolute;
z-index: 1;
@ -112,7 +108,6 @@ img.picture-item__blur {
}
}
/*
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.
@ -129,7 +124,6 @@ img.picture-item__blur {
visibility: hidden;
}
/* Animate in styles */
.shuffle--animatein {
overflow: visible;
@ -141,7 +135,7 @@ img.picture-item__blur {
}
.shuffle--animatein .picture-item__inner--transition {
transition: all .6s ease;
transition: all 0.6s ease;
}
.shuffle--animatein .picture-item.in .picture-item__inner {
@ -149,10 +143,7 @@ img.picture-item__blur {
transform: translate(0, 0);
}
@include breakpoint(sm, true) {
.picture-item {
height: auto;
margin-top: 20px;
@ -160,12 +151,12 @@ img.picture-item__blur {
.picture-item__details,
.picture-item__description {
font-size: .875em;
padding: .625em;
font-size: 0.875em;
padding: 0.625em;
}
.picture-item__description {
padding-right: .875em;
padding-right: 0.875em;
padding-bottom: 1.25em;
}

@ -1,16 +1,16 @@
@import "./extensions/variables";
@import "./extensions/mixins";
@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 './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 './components/buttons';
@import './components/demo-list';
@import './components/site-nav';
@import "./pages/homepage-filters";
@import "./pages/compound-filters";
@import "./pages/faq";
@import './pages/homepage-filters';
@import './pages/compound-filters';
@import './pages/faq';

@ -1,183 +1,4 @@
/* 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)
* @author Lea Verou
*/
code[class*="language-"],
pre[class*="language-"] {
color: black;
background: none;
text-shadow: 0 1px white;
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
text-align: left;
white-space: pre;
word-spacing: normal;
word-break: normal;
word-wrap: normal;
line-height: 1.5;
-moz-tab-size: 4;
-o-tab-size: 4;
tab-size: 4;
-webkit-hyphens: none;
-moz-hyphens: none;
-ms-hyphens: none;
hyphens: none;
}
pre[class*="language-"]::-moz-selection, pre[class*="language-"] ::-moz-selection,
code[class*="language-"]::-moz-selection, code[class*="language-"] ::-moz-selection {
text-shadow: none;
background: #b3d4fc;
}
pre[class*="language-"]::selection, pre[class*="language-"] ::selection,
code[class*="language-"]::selection, code[class*="language-"] ::selection {
text-shadow: none;
background: #b3d4fc;
}
@media print {
code[class*="language-"],
pre[class*="language-"] {
text-shadow: none;
}
}
/* Code blocks */
pre[class*="language-"] {
padding: 1em;
margin: .5em 0;
overflow: auto;
}
:not(pre) > code[class*="language-"],
pre[class*="language-"] {
background: #f5f2f0;
}
/* Inline code */
:not(pre) > code[class*="language-"] {
padding: .1em;
border-radius: .3em;
white-space: normal;
}
.token.comment,
.token.prolog,
.token.doctype,
.token.cdata {
color: slategray;
}
.token.punctuation {
color: #999;
}
.namespace {
opacity: .7;
}
.token.property,
.token.tag,
.token.boolean,
.token.number,
.token.constant,
.token.symbol,
.token.deleted {
color: #905;
}
.token.selector,
.token.attr-name,
.token.string,
.token.char,
.token.builtin,
.token.inserted {
color: #690;
}
.token.operator,
.token.entity,
.token.url,
.language-css .token.string,
.style .token.string {
color: #a67f59;
background: hsla(0, 0%, 100%, .5);
}
.token.atrule,
.token.attr-value,
.token.keyword {
color: #07a;
}
.token.function {
color: #DD4A68;
}
.token.regex,
.token.important,
.token.variable {
color: #e90;
}
.token.important,
.token.bold {
font-weight: bold;
}
.token.italic {
font-style: italic;
}
.token.entity {
cursor: help;
}
pre[data-line] {
position: relative;
padding: 1em 0 1em 3em;
}
.line-highlight {
position: absolute;
left: 0;
right: 0;
padding: inherit 0;
margin-top: 1em; /* Same as .prisms padding-top */
background: hsla(24, 20%, 50%,.08);
background: linear-gradient(to right, hsla(24, 20%, 50%,.1) 70%, hsla(24, 20%, 50%,0));
pointer-events: none;
line-height: inherit;
white-space: pre;
}
.line-highlight:before,
.line-highlight[data-end]:after {
content: attr(data-start);
position: absolute;
top: .4em;
left: .6em;
min-width: 1em;
padding: 0 .5em;
background-color: hsla(24, 20%, 50%,.4);
color: hsl(24, 20%, 95%);
font: bold 65%/1.5 sans-serif;
text-align: center;
vertical-align: .3em;
border-radius: 999px;
text-shadow: none;
box-shadow: 0 1px white;
}
.line-highlight[data-end]:after {
content: attr(data-end);
top: auto;
bottom: .4em;
}
/* PrismJS 1.26.0
https://prismjs.com/download.html?#themes=prism&languages=markup+css+clike+javascript+jsx+scss&plugins=line-highlight+file-highlight */
code[class*=language-],pre[class*=language-]{color:#000;background:0 0;text-shadow:0 1px #fff;font-family:Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none}code[class*=language-] ::-moz-selection,code[class*=language-]::-moz-selection,pre[class*=language-] ::-moz-selection,pre[class*=language-]::-moz-selection{text-shadow:none;background:#b3d4fc}code[class*=language-] ::selection,code[class*=language-]::selection,pre[class*=language-] ::selection,pre[class*=language-]::selection{text-shadow:none;background:#b3d4fc}@media print{code[class*=language-],pre[class*=language-]{text-shadow:none}}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto}:not(pre)>code[class*=language-],pre[class*=language-]{background:#f5f2f0}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#708090}.token.punctuation{color:#999}.token.namespace{opacity:.7}.token.boolean,.token.constant,.token.deleted,.token.number,.token.property,.token.symbol,.token.tag{color:#905}.token.attr-name,.token.builtin,.token.char,.token.inserted,.token.selector,.token.string{color:#690}.language-css .token.string,.style .token.string,.token.entity,.token.operator,.token.url{color:#9a6e3a;background:hsla(0,0%,100%,.5)}.token.atrule,.token.attr-value,.token.keyword{color:#07a}.token.class-name,.token.function{color:#dd4a68}.token.important,.token.regex,.token.variable{color:#e90}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}
pre[data-line]{position:relative;padding:1em 0 1em 3em}.line-highlight{position:absolute;left:0;right:0;padding:inherit 0;margin-top:1em;background:hsla(24,20%,50%,.08);background:linear-gradient(to right,hsla(24,20%,50%,.1) 70%,hsla(24,20%,50%,0));pointer-events:none;line-height:inherit;white-space:pre}@media print{.line-highlight{-webkit-print-color-adjust:exact;color-adjust:exact}}.line-highlight:before,.line-highlight[data-end]:after{content:attr(data-start);position:absolute;top:.4em;left:.6em;min-width:1em;padding:0 .5em;background-color:hsla(24,20%,50%,.4);color:#f4f1ef;font:bold 65%/1.5 sans-serif;text-align:center;vertical-align:.3em;border-radius:999px;text-shadow:none;box-shadow:0 1px #fff}.line-highlight[data-end]:after{content:attr(data-end);top:auto;bottom:.4em}.line-numbers .line-highlight:after,.line-numbers .line-highlight:before{content:none}pre[id].linkable-line-numbers span.line-numbers-rows{pointer-events:all}pre[id].linkable-line-numbers span.line-numbers-rows>span:before{cursor:pointer}pre[id].linkable-line-numbers span.line-numbers-rows>span:hover:before{background-color:rgba(128,128,128,.2)}

@ -1 +1 @@
.picture-item{height:220px;margin-left:0;margin-top:24px}.picture-item img{display:block;width:100%}@supports ((-o-object-fit:cover) or (object-fit:cover)){.picture-item img{height:100%;max-width:none;-o-object-fit:cover;object-fit:cover}}.picture-item--h2{height:464px}.picture-item__inner{background:#ecf0f1;height:100%;overflow:hidden;position:relative}img.picture-item__blur{display:none}.picture-item__details{align-items:baseline;display:flex;justify-content:space-between;padding:1em;width:100%}.picture-item__description{margin:0;padding:0 2em 1em 1em;width:100%}.picture-item__title{flex-shrink:0;margin-right:4px}.picture-item__tags{flex-shrink:1;margin:0;text-align:right}@media screen and (min-width:768px){.picture-item--overlay .picture-item__details{background-color:rgba(0,0,0,.6);bottom:0;color:#fff;left:0;overflow:hidden;position:absolute;width:100%}.picture-item--overlay .picture-item__description{display:none}@supports (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{-webkit-clip-path:inset(170px 0 0 0);clip-path:inset(170px 0 0 0);display:block;filter:blur(7px);left:0;position:absolute;top:0;z-index:1}.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{overflow:hidden;position:relative}.my-sizer-element{opacity:0;position:absolute;visibility:hidden}.shuffle--animatein{overflow:visible}.shuffle--animatein .picture-item__inner{opacity:0;transform:translateY(220px)}.shuffle--animatein .picture-item__inner--transition{transition:all .6s ease}.shuffle--animatein .picture-item.in .picture-item__inner{opacity:1;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-bottom:1.25em;padding-right:.875em}.picture-item--h2{height:auto}}
.picture-item{height:220px;margin-left:0;margin-top:24px}.picture-item img{display:block;width:100%}@supports (object-fit:cover){.picture-item img{height:100%;max-width:none;object-fit:cover}}.picture-item--h2{height:464px}.picture-item__inner{background:#ecf0f1;height:100%;overflow:hidden;position:relative}img.picture-item__blur{display:none}.picture-item__details{align-items:baseline;display:flex;justify-content:space-between;padding:1em;width:100%}.picture-item__description{margin:0;padding:0 2em 1em 1em;width:100%}.picture-item__title{flex-shrink:0;margin-right:4px}.picture-item__tags{flex-shrink:1;margin:0;text-align:right}@media screen and (min-width:768px){.picture-item--overlay .picture-item__details{background-color:#0009;bottom:0;color:#fff;left:0;overflow:hidden;position:absolute;width:100%}.picture-item--overlay .picture-item__description{display:none}@supports (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{-webkit-clip-path:inset(170px 0 0 0);clip-path:inset(170px 0 0 0);display:block;filter:blur(7px);left:0;position:absolute;top:0;z-index:1}.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{overflow:hidden;position:relative}.my-sizer-element{opacity:0;position:absolute;visibility:hidden}.shuffle--animatein{overflow:visible}.shuffle--animatein .picture-item__inner{opacity:0;transform:translateY(220px)}.shuffle--animatein .picture-item__inner--transition{transition:all .6s ease}.shuffle--animatein .picture-item.in .picture-item__inner{opacity:1;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-bottom:1.25em;padding-right:.875em}.picture-item--h2{height:auto}}

File diff suppressed because one or more lines are too long

2328
docs/dist/shuffle.js vendored

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -214,7 +214,6 @@ prism: true
<div class="col-12@sm">
<h2>Dependencies<a href="#dependencies"></a></h2>
<p>Shuffle's <a href="https://github.com/Vestride/Shuffle/blob/master/package.json">dependencies</a> are bundled with the dist file.</p>
<p id="polyfills">Shuffle does, however, expect the following ES6/7 features: <code>Set</code>, <code>Array.from</code>, <code>Object.assign</code>, <code>Array.prototype.find</code>, and <code>Array.prototype.includes</code>. In order to support browsers like IE11 and Safari 8, <strong class="type--underline">you must include a polyfill</strong> for these features. You can use a service like <a href="https://polyfill.io">polyfill.io</a> to only load the polyfills that specific browser needs, or a polyfill script like <a href="https://www.npmjs.com/package/@babel/polyfill">@babel/polyfill</a> (which uses <code>core-js</code> internally).</p>
</div>
</div>
</div>
@ -230,27 +229,28 @@ prism: true
<li>Chrome</li>
<li>Firefox</li>
<li>Edge</li>
<li>IE 11</li>
<li>Safari</li>
</ul>
<p>Depending on what browsers you support, you may <a href="#polyfills">need to polyfill features used by Shuffle</a>.</p>
<p>If you still need to support IE 11, you can use Shuffle v5.</p>
</div>
</div>
</div>
</section>
<section id="be-social">
<section id="share">
<div class="container">
<div class="row">
<div class="col-12@sm">
<h2>Be Social<a href="#be-social"></a></h2>
<div class="text-center">
<h2>Share<a href="#share"></a></h2>
<div>
<a href="https://www.buymeacoffee.com/glen.cheney" target="_blank" style="display:inline-block;">
<img loading="lazy" src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" style="height: 45px !important;width: 160px !important;" />
</a>
<iframe src="https://ghbtns.com/github-btn.html?user=Vestride&repo=Shuffle&type=star&size=large" frameborder="0" scrolling="0" width="76px" height="30px" title="Star this repository on GitHub"></iframe>
<a href="https://twitter.com/share" class="twitter-share-button" data-via="Vestride" data-size="large">Tweet</a>
<div class="g-plusone" data-annotation="none"></div>
</div>
</div>
</div>
@ -268,12 +268,5 @@ prism: true
</section>
<script>
!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0],p=/^http:/.test(d.location)?'http':'https';if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src=p+'://platform.twitter.com/widgets.js';fjs.parentNode.insertBefore(js,fjs);}}(document, 'script', 'twitter-wjs');
(function() {
var po = document.createElement('script'); po.type = 'text/javascript'; po.async = true;
po.src = 'https://apis.google.com/js/platform.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(po, s);
})();
</script>

@ -1,151 +1,140 @@
'use strict';
var Sprite = function (context, img, size) {
this.ctx = context;
this.img = img;
this.width = size;
this.height = size;
this.frameWidth = size;
this.frameHeight = size;
};
// Assuming horizontal sprite
Sprite.prototype.getFrame = function (frame) {
return {
x: frame * this.frameWidth,
y: 0,
};
};
Sprite.prototype.clearCanvas = function () {
this.ctx.clearRect(0, 0, this.width, this.height);
};
Sprite.prototype.drawFrame = function (frameNumber) {
var frame = this.getFrame(frameNumber);
// Clear out the last frame
this.clearCanvas();
// Draw to the context. This method is really confusing...
this.ctx.drawImage(
this.img,
frame.x,
frame.y,
this.width,
this.height,
0,
0,
this.width,
this.height
);
};
var Favicon = function (src, numFrames, framesPerAnimation, animationDelay) {
// Variables based on params
this.src = src;
this.numFrames = numFrames;
this.framesPerAnimation = framesPerAnimation;
this.animationDelay = animationDelay;
// Elements
this.canvas = document.createElement('canvas');
this.img = document.createElement('img');
this.html = document.documentElement;
// Calculations
this.size = window.devicePixelRatio > 1 ? 32 : 16;
// If it's not a data url, pick apart the filename and add @2x for retina
if (!this.src.match(/data:/) && window.devicePixelRatio > 1) {
var dot = this.src.lastIndexOf('.');
this.src = this.src.substring(0, dot) + '@2x' + this.src.substring(dot);
class Sprite {
constructor(context, img, size) {
this.ctx = context;
this.img = img;
this.width = size;
this.height = size;
this.frameWidth = size;
this.frameHeight = size;
}
this.currentFrame = 0;
// Assuming horizontal sprite
getFrame(frame) {
return {
x: frame * this.frameWidth,
y: 0,
};
}
clearCanvas() {
this.ctx.clearRect(0, 0, this.width, this.height);
}
drawFrame(frameNumber) {
var frame = this.getFrame(frameNumber);
// Chrome chokes on this. It looks like it can handle 4 frames per second
this.fps = 24;
// Clear out the last frame
this.clearCanvas();
// No #favicon element, stop
if (!document.getElementById('favicon')) {
return;
// Draw to the context. This method is really confusing...
this.ctx.drawImage(this.img, frame.x, frame.y, this.width, this.height, 0, 0, this.width, this.height);
}
}
class Favicon {
constructor(src, numFrames, framesPerAnimation, animationDelay) {
// Variables based on params
this.src = src;
this.numFrames = numFrames;
this.framesPerAnimation = framesPerAnimation;
this.animationDelay = animationDelay;
// Elements
this.canvas = document.createElement('canvas');
this.img = document.createElement('img');
this.html = document.documentElement;
// Calculations
this.size = window.devicePixelRatio > 1 ? 32 : 16;
// If it's not a data url, pick apart the filename and add @2x for retina
if (!this.src.match(/data:/) && window.devicePixelRatio > 1) {
var dot = this.src.lastIndexOf('.');
this.src = this.src.substring(0, dot) + '@2x' + this.src.substring(dot);
}
// Save context
this.ctx = this.canvas.getContext('2d');
this.currentFrame = 0;
// Set canvas dimensions based on device DPI
this.canvas.height = this.canvas.width = this.size;
// Chrome chokes on this. It looks like it can handle 4 frames per second
this.fps = 24;
// Create a new sprite 32x32 size with 32x32 sprites
this.sprite = new Sprite(this.ctx, this.img, this.size);
// No #favicon element, stop
if (!document.getElementById('favicon')) {
return;
}
// Bind the image load handler
this.img.onload = this.onSpriteLoaded.bind(this);
// Save context
this.ctx = this.canvas.getContext('2d');
// Trigger image to load
this.img.src = this.src;
};
// Set canvas dimensions based on device DPI
this.canvas.height = this.canvas.width = this.size;
Favicon.prototype.getData = function () {
return this.canvas.toDataURL('image/png');
};
// Create a new sprite 32x32 size with 32x32 sprites
this.sprite = new Sprite(this.ctx, this.img, this.size);
// Clone the current #favicon and replace it with a new element
// which has the updated data URI href
Favicon.prototype.setFavicon = function () {
var data = this.getData();
var originalFavicon = document.getElementById('favicon');
var clone = originalFavicon.cloneNode(true);
// Bind the image load handler
this.img.onload = this.onSpriteLoaded.bind(this);
clone.setAttribute('href', data);
originalFavicon.parentNode.replaceChild(clone, originalFavicon);
};
// Trigger image to load
this.img.src = this.src;
}
// Request Animation Frame Loop
Favicon.prototype.loop = function (timestamp) {
// If not enough time has elapse since the last call
// immediately call the next rAF
if (timestamp - this.lastExecuted < this.timeToElapse) {
return requestAnimationFrame(this.loop.bind(this));
getData() {
return this.canvas.toDataURL('image/png');
}
// Increment current frame
this.currentFrame += 1;
if (this.currentFrame === this.numFrames) {
this.currentFrame = 0;
// Clone the current #favicon and replace it with a new element
// which has the updated data URI href
setFavicon() {
var data = this.getData();
var originalFavicon = document.getElementById('favicon');
var clone = originalFavicon.cloneNode(true);
clone.setAttribute('href', data);
originalFavicon.parentNode.replaceChild(clone, originalFavicon);
}
// Completed an animation state
this.timeToElapse = this.currentFrame % this.framesPerAnimation === 0 ?
this.animationDelay :
1000 / this.fps;
// Request Animation Frame Loop
loop(timestamp) {
// If not enough time has elapse since the last call
// immediately call the next rAF
if (timestamp - this.lastExecuted < this.timeToElapse) {
return requestAnimationFrame(this.loop.bind(this));
}
// Draw current frame from sprite
this.sprite.drawFrame(this.currentFrame);
// Increment current frame
this.currentFrame += 1;
if (this.currentFrame === this.numFrames) {
this.currentFrame = 0;
}
// Swap <link>
this.setFavicon();
// Completed an animation state
this.timeToElapse = this.currentFrame % this.framesPerAnimation === 0 ? this.animationDelay : 1000 / this.fps;
// Set a timeout to draw again
this.lastExecuted = timestamp;
// Draw current frame from sprite
this.sprite.drawFrame(this.currentFrame);
// Continue loop
return requestAnimationFrame(this.loop.bind(this));
};
// Swap <link>
this.setFavicon();
// Sprite loaded
Favicon.prototype.onSpriteLoaded = function () {
// Draw the first frame when the image loads
this.sprite.drawFrame(this.currentFrame);
// Set a timeout to draw again
this.lastExecuted = timestamp;
// Swap <link>
this.setFavicon();
// Continue loop
return requestAnimationFrame(this.loop.bind(this));
}
// Start loop
requestAnimationFrame(this.loop.bind(this));
};
// Sprite loaded
onSpriteLoaded() {
// Draw the first frame when the image loads
this.sprite.drawFrame(this.currentFrame);
// Swap <link>
this.setFavicon();
// Start loop
requestAnimationFrame(this.loop.bind(this));
}
}
new Favicon(window.site_url + '/img/favicon-sprite.png', 21, 7, 3000 * 1);

@ -2,263 +2,262 @@
var Shuffle = window.Shuffle;
var Demo = function (element) {
this.element = element;
this.initShuffle();
this.setupEvents();
};
// Column width and gutter width options can be functions
Demo.prototype.initShuffle = function () {
this.shuffle = new Shuffle(this.element, {
itemSelector: '.box',
speed: 250,
easing: 'ease',
columnWidth: function (containerWidth) {
// .box's have a width of 18%
return 0.18 * containerWidth;
},
gutterWidth: function (containerWidth) {
// .box's have a margin-left of 2.5%
return 0.025 * containerWidth;
},
});
};
Demo.prototype.setupEvents = function () {
document.querySelector('#append').addEventListener('click', this.onAppendBoxes.bind(this));
document.querySelector('#prepend').addEventListener('click', this.onPrependBoxes.bind(this));
document.querySelector('#randomize').addEventListener('click', this.onRandomize.bind(this));
document.querySelector('#remove').addEventListener('click', this.onRemoveClick.bind(this));
document.querySelector('#sorter').addEventListener('change', this.onSortChange.bind(this));
document.querySelector('#filterer').addEventListener('change', this.onFilterChange.bind(this));
this.shuffle.element.addEventListener('click', this.onContainerClick.bind(this));
// Show off some shuffle events
this.shuffle.on(Shuffle.EventType.REMOVED, function (data) {
console.log(data);
});
};
/**
* Generate random DOM elements.
* @param {number} itemsToCreate Number of items to create.
* @return {Array.<Element>} Array of elements.
*/
Demo.prototype._generateBoxes = function (itemsToCreate) {
// Creating random elements. You could use an ajax request or clone elements instead.
var items = [];
var modifierClasses = ['w2', 'h2', 'w3'];
var i = 0;
for (i = 0; i < itemsToCreate; i++) {
var random = Math.random();
var box = document.createElement('div');
box.className = 'box';
box.style.backgroundColor = this.getRandomColor();
box.setAttribute('data-reviews', this.getRandomInt(1, 150));
// Randomly add a class
if (random > 0.8) {
var randomClass = Math.floor(Math.random() * 3);
box.className = box.className + ' ' + modifierClasses[randomClass];
class Demo {
constructor(element) {
this.element = element;
this.initShuffle();
this.setupEvents();
}
// Column width and gutter width options can be functions
initShuffle() {
this.shuffle = new Shuffle(this.element, {
itemSelector: '.box',
speed: 250,
easing: 'ease',
columnWidth: function (containerWidth) {
// .box's have a width of 18%
return 0.18 * containerWidth;
},
gutterWidth: function (containerWidth) {
// .box's have a margin-left of 2.5%
return 0.025 * containerWidth;
},
});
}
setupEvents() {
document.querySelector('#append').addEventListener('click', this.onAppendBoxes.bind(this));
document.querySelector('#prepend').addEventListener('click', this.onPrependBoxes.bind(this));
document.querySelector('#randomize').addEventListener('click', this.onRandomize.bind(this));
document.querySelector('#remove').addEventListener('click', this.onRemoveClick.bind(this));
document.querySelector('#sorter').addEventListener('change', this.onSortChange.bind(this));
document.querySelector('#filterer').addEventListener('change', this.onFilterChange.bind(this));
this.shuffle.element.addEventListener('click', this.onContainerClick.bind(this));
// Show off some shuffle events
this.shuffle.on(Shuffle.EventType.REMOVED, function (data) {
console.log(data);
});
}
/**
* Generate random DOM elements.
* @param {number} itemsToCreate Number of items to create.
* @return {Array.<Element>} Array of elements.
*/
_generateBoxes(itemsToCreate) {
// Creating random elements. You could use an ajax request or clone elements instead.
var items = [];
var modifierClasses = ['w2', 'h2', 'w3'];
var i = 0;
for (i = 0; i < itemsToCreate; i++) {
var random = Math.random();
var box = document.createElement('div');
box.className = 'box';
box.style.backgroundColor = this.getRandomColor();
box.setAttribute('data-reviews', this.getRandomInt(1, 150));
// Randomly add a class
if (random > 0.8) {
var randomClass = Math.floor(Math.random() * 3);
box.className = box.className + ' ' + modifierClasses[randomClass];
}
items.push(box);
}
items.push(box);
return items;
}
/**
* Return an array of elements which have already been added to the DOM.
* @return {Array.<Element>}
*/
_getArrayOfElementsToAdd() {
return this._generateBoxes(5);
}
/**
* Create an HTML string to insert. This could, for example, come from an XHR request.
* @return {string} A mock HTML string.
*/
_getHtmlMarkupToAdd() {
var fragment = document.createDocumentFragment();
this._generateBoxes(5).forEach(function (item) {
fragment.appendChild(item);
});
var dummy = document.createElement('div');
dummy.appendChild(fragment);
return dummy.innerHTML;
}
return items;
};
/**
* Return an array of elements which have already been added to the DOM.
* @return {Array.<Element>}
*/
Demo.prototype._getArrayOfElementsToAdd = function () {
return this._generateBoxes(5);
};
/**
* Create an HTML string to insert. This could, for example, come from an XHR request.
* @return {string} A mock HTML string.
*/
Demo.prototype._getHtmlMarkupToAdd = function () {
var fragment = document.createDocumentFragment();
this._generateBoxes(5).forEach(function (item) {
fragment.appendChild(item);
});
var dummy = document.createElement('div');
dummy.appendChild(fragment);
return dummy.innerHTML;
};
/**
* Create some DOM elements, append them to the shuffle container, then notify
* shuffle about the new items. You could also insert the HTML as a string.
*/
Demo.prototype.onAppendBoxes = function () {
var elements = this._getArrayOfElementsToAdd();
elements.forEach(function (element) {
this.shuffle.element.appendChild(element);
}, this);
// Tell shuffle items have been appended.
// It expects an array of elements as the parameter.
this.shuffle.add(elements);
};
/**
* Show that you can prepend elements by inserting before other elements. You
* can either insert a string like in this method or prepend real elements like
* the `onAppendBoxes` method.
*/
Demo.prototype.onPrependBoxes = function () {
var markup = this._getHtmlMarkupToAdd();
// Prepend HTML string.
this.element.insertAdjacentHTML('afterbegin', markup);
// Get the first 5 children of the container (we are inserting 5 items).
var items = Array.prototype.slice.call(this.element.children, 0, 5);
// Notify the instance.
this.shuffle.add(items);
};
Demo.prototype.getRandomInt = function (min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
};
Demo.prototype.getRandomColor = function () {
return '#' + Math.random().toString(16).slice(2, 8);
};
// Randomly choose some elements to remove
Demo.prototype.onRemoveClick = function () {
var total = this.shuffle.visibleItems;
// None left
if (!total) {
return;
/**
* Create some DOM elements, append them to the shuffle container, then notify
* shuffle about the new items. You could also insert the HTML as a string.
*/
onAppendBoxes() {
var elements = this._getArrayOfElementsToAdd();
elements.forEach(function (element) {
this.shuffle.element.appendChild(element);
}, this);
// Tell shuffle items have been appended.
// It expects an array of elements as the parameter.
this.shuffle.add(elements);
}
var numberToRemove = Math.min(3, total);
var indiciesToRemove = [];
/**
* Show that you can prepend elements by inserting before other elements. You
* can either insert a string like in this method or prepend real elements like
* the `onAppendBoxes` method.
*/
onPrependBoxes() {
var markup = this._getHtmlMarkupToAdd();
// Prepend HTML string.
this.element.insertAdjacentHTML('afterbegin', markup);
// Get the first 5 children of the container (we are inserting 5 items).
var items = Array.prototype.slice.call(this.element.children, 0, 5);
// Notify the instance.
this.shuffle.add(items);
}
// This has the possibility to choose the same index for more than
// one in the array, meaning sometimes less than 3 will be removed
for (var i = 0; i < numberToRemove; i++) {
indiciesToRemove.push(this.getRandomInt(0, total - 1));
getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
// Make an array of elements to remove.
var collection = indiciesToRemove.map(function (index) {
return this.shuffle.items[index].element;
}, this);
// Tell shuffle to remove them
this.shuffle.remove(collection);
};
Demo.prototype.onRandomize = function () {
var label = document.getElementById('sorter').querySelector('label.btn.active');
if (label) {
var radio = label.querySelector('input');
radio.checked = false;
label.classList.remove('active');
getRandomColor() {
return '#' + Math.random().toString(16).slice(2, 8);
}
this.sortBy('random');
};
// Randomly choose some elements to remove
onRemoveClick() {
var total = this.shuffle.visibleItems;
Demo.prototype.toggleActiveClasses = function (event) {
// Add and remove `active` class from buttons.
var buttons = Array.from(event.currentTarget.children);
buttons.forEach(function (button) {
if (button.querySelector('input').value === event.target.value) {
button.classList.add('active');
} else {
button.classList.remove('active');
// None left
if (!total) {
return;
}
});
}
Demo.prototype.onSortChange = function (evt) {
this.toggleActiveClasses(evt);
this.sortBy(evt.target.value);
};
var numberToRemove = Math.min(3, total);
var indiciesToRemove = [];
Demo.prototype.sortBy = function (value) {
var sortOptions;
// This has the possibility to choose the same index for more than
// one in the array, meaning sometimes less than 3 will be removed
for (var i = 0; i < numberToRemove; i++) {
indiciesToRemove.push(this.getRandomInt(0, total - 1));
}
if (value === 'most-reviews') {
sortOptions = {
reverse: true,
by: this.getReviews,
};
// Make an array of elements to remove.
var collection = indiciesToRemove.map(function (index) {
return this.shuffle.items[index].element;
}, this);
} else if (value === 'least-reviews') {
sortOptions = {
by: this.getReviews,
};
// Tell shuffle to remove them
this.shuffle.remove(collection);
}
} else if (value === 'random') {
sortOptions = { randomize: true };
onRandomize() {
var label = document.getElementById('sorter').querySelector('label.btn.active');
if (label) {
var radio = label.querySelector('input');
radio.checked = false;
label.classList.remove('active');
}
} else {
sortOptions = {};
this.sortBy('random');
}
// Filter elements
this.shuffle.sort(sortOptions);
};
toggleActiveClasses(event) {
// Add and remove `active` class from buttons.
var buttons = Array.from(event.currentTarget.children);
buttons.forEach(function (button) {
if (button.querySelector('input').value === event.target.value) {
button.classList.add('active');
} else {
button.classList.remove('active');
}
});
}
Demo.prototype.getReviews = function (element) {
return parseInt(element.getAttribute('data-reviews'), 10);
}
onSortChange(evt) {
this.toggleActiveClasses(evt);
this.sortBy(evt.target.value);
}
sortBy(value) {
var sortOptions;
if (value === 'most-reviews') {
sortOptions = {
reverse: true,
by: this.getReviews,
};
} else if (value === 'least-reviews') {
sortOptions = {
by: this.getReviews,
};
} else if (value === 'random') {
sortOptions = { randomize: true };
} else {
sortOptions = {};
}
Demo.prototype.onFilterChange = function (event) {
this.toggleActiveClasses(event);
this.filterBy(event.target.value);
};
Demo.prototype.filterBy = function (value) {
var filterBy;
var _this = this;
if (value === 'none') {
filterBy = Shuffle.ALL_ITEMS;
} else if (value === 'odd-reviews') {
filterBy = function (element) {
return _this.getReviews(element) % 2 === 1;
};
} else {
filterBy = function (element) {
return _this.getReviews(element) % 2 === 0;
};
// Filter elements
this.shuffle.sort(sortOptions);
}
this.shuffle.filter(filterBy);
};
/**
* Remove a shuffle item when it's clicked.
* @param {Object} event Event object.
*/
Demo.prototype.onContainerClick = function (event) {
// Bail in older browsers. https://caniuse.com/#feat=element-closest
if (typeof event.target.closest !== 'function') {
return;
getReviews(element) {
return parseInt(element.getAttribute('data-reviews'), 10);
}
var element = event.target.closest('.box');
if (element !== null) {
this.shuffle.remove([element]);
onFilterChange(event) {
this.toggleActiveClasses(event);
this.filterBy(event.target.value);
}
};
filterBy(value) {
var filterBy;
var _this = this;
if (value === 'none') {
filterBy = Shuffle.ALL_ITEMS;
} else if (value === 'odd-reviews') {
filterBy = function (element) {
return _this.getReviews(element) % 2 === 1;
};
} else {
filterBy = function (element) {
return _this.getReviews(element) % 2 === 0;
};
}
this.shuffle.filter(filterBy);
}
/**
* Remove a shuffle item when it's clicked.
* @param {Object} event Event object.
*/
onContainerClick(event) {
// Bail in older browsers. https://caniuse.com/#feat=element-closest
if (typeof event.target.closest !== 'function') {
return;
}
var element = event.target.closest('.box');
if (element !== null) {
this.shuffle.remove([element]);
}
}
}
document.addEventListener('DOMContentLoaded', function () {
window.demo = new Demo(document.getElementById('my-shuffle'));

@ -6,8 +6,6 @@ var loadMoreButton = document.getElementById('load-more-button');
var shuffleInstance;
// Fetch first page of results from the API.
// You should probably polyfill `fetch` if you're going to copy this demo.
// https://github.com/github/fetch
fetch('https://reqres.in/api/users?page=' + currentPage)
.then(function (response) {
return response.json();

@ -1,56 +1,56 @@
'use strict';
var Shuffle = window.Shuffle;
var Demo = function () {
this.element = document.getElementById('grid');
this.gridItems = this.element.querySelectorAll('.picture-item');
var sizer = this.element.querySelector('.my-sizer-element');
this.shuffle = new Shuffle(this.element, {
itemSelector: '.picture-item',
sizer: sizer,
});
class Demo {
constructor() {
this.element = document.getElementById('grid');
this.gridItems = this.element.querySelectorAll('.picture-item');
var sizer = this.element.querySelector('.my-sizer-element');
this.shuffle = new Shuffle(this.element, {
itemSelector: '.picture-item',
sizer: sizer,
});
var callback = this.showItemsInViewport.bind(this);
this.observer = new IntersectionObserver(callback, {
threshold: 0.5,
});
// Loop through each grid item and add it to the viewport watcher.
for (var i = 0; i < this.gridItems.length; i++) {
this.observer.observe(this.gridItems[i]);
}
var callback = this.showItemsInViewport.bind(this);
this.observer = new window.IntersectionObserver(callback, {
threshold: 0.5,
});
// Add the transition class to the items after ones that are in the viewport
// have received the `in` class.
setTimeout(() => {
this.addTransitionToItems();
}, 100);
}
// Loop through each grid item and add it to the viewport watcher.
for (var i = 0; i < this.gridItems.length; i++) {
this.observer.observe(this.gridItems[i]);
/**
* Add the `in` class to the element after it comes into view.
*/
showItemsInViewport(changes) {
changes.forEach(function (change) {
if (change.isIntersecting) {
change.target.classList.add('in');
}
});
}
// Add the transition class to the items after ones that are in the viewport
// have received the `in` class.
setTimeout(function () {
this.addTransitionToItems();
}.bind(this), 100);
};
/**
* Add the `in` class to the element after it comes into view.
*/
Demo.prototype.showItemsInViewport = function (changes) {
changes.forEach(function (change) {
if (change.isIntersecting) {
change.target.classList.add('in');
/**
* Only the items out of the viewport should transition. This way, the first
* visible ones will snap into place.
*/
addTransitionToItems() {
for (var i = 0; i < this.gridItems.length; i++) {
var inner = this.gridItems[i].querySelector('.picture-item__inner');
inner.classList.add('picture-item__inner--transition');
}
});
};
/**
* Only the items out of the viewport should transition. This way, the first
* visible ones will snap into place.
*/
Demo.prototype.addTransitionToItems = function () {
for (var i = 0; i < this.gridItems.length; i++) {
var inner = this.gridItems[i].querySelector('.picture-item__inner');
inner.classList.add('picture-item__inner--transition');
}
};
}
document.addEventListener('DOMContentLoaded', function () {
document.addEventListener('DOMContentLoaded', () => {
window.demo = new Demo();
});

@ -2,139 +2,135 @@
var Shuffle = window.Shuffle;
var Demo = function (element) {
this.shapes = Array.from(document.querySelectorAll('.js-shapes input'));
this.colors = Array.from(document.querySelectorAll('.js-colors button'));
this.shuffle = new Shuffle(element, {
easing: 'cubic-bezier(0.165, 0.840, 0.440, 1.000)', // easeOutQuart
sizer: '.the-sizer',
});
this.filters = {
shapes: [],
colors: [],
};
this._bindEventListeners();
};
/**
* Bind event listeners for when the filters change.
*/
Demo.prototype._bindEventListeners = function () {
this._onShapeChange = this._handleShapeChange.bind(this);
this._onColorChange = this._handleColorChange.bind(this);
this.shapes.forEach(function (input) {
input.addEventListener('change', this._onShapeChange);
}, this);
this.colors.forEach(function (button) {
button.addEventListener('click', this._onColorChange);
}, this);
};
/**
* Get the values of each checked input.
* @return {Array.<string>}
*/
Demo.prototype._getCurrentShapeFilters = function () {
return this.shapes.filter(function (input) {
return input.checked;
}).map(function (input) {
return input.value;
});
};
/**
* Get the values of each `active` button.
* @return {Array.<string>}
*/
Demo.prototype._getCurrentColorFilters = function () {
return this.colors.filter(function (button) {
return button.classList.contains('active');
}).map(function (button) {
return button.getAttribute('data-value');
});
};
/**
* A shape input check state changed, update the current filters and filte.r
*/
Demo.prototype._handleShapeChange = function () {
this.filters.shapes = this._getCurrentShapeFilters();
this.filter();
};
/**
* A color button was clicked. Update filters and display.
* @param {Event} evt Click event object.
*/
Demo.prototype._handleColorChange = function (evt) {
var button = evt.currentTarget;
// Treat these buttons like radio buttons where only 1 can be selected.
if (button.classList.contains('active')) {
button.classList.remove('active');
} else {
this.colors.forEach(function (btn) {
btn.classList.remove('active');
class Demo {
constructor(element) {
this.shapes = Array.from(document.querySelectorAll('.js-shapes input'));
this.colors = Array.from(document.querySelectorAll('.js-colors button'));
this.shuffle = new Shuffle(element, {
easing: 'cubic-bezier(0.165, 0.840, 0.440, 1.000)',
sizer: '.the-sizer',
});
button.classList.add('active');
this.filters = {
shapes: [],
colors: [],
};
this._bindEventListeners();
}
this.filters.colors = this._getCurrentColorFilters();
this.filter();
};
/**
* Filter shuffle based on the current state of filters.
*/
Demo.prototype.filter = function () {
if (this.hasActiveFilters()) {
this.shuffle.filter(this.itemPassesFilters.bind(this));
} else {
this.shuffle.filter(Shuffle.ALL_ITEMS);
/**
* Bind event listeners for when the filters change.
*/
_bindEventListeners() {
this._onShapeChange = this._handleShapeChange.bind(this);
this._onColorChange = this._handleColorChange.bind(this);
this.shapes.forEach((input) => {
input.addEventListener('change', this._onShapeChange);
}, this);
this.colors.forEach((button) => {
button.addEventListener('click', this._onColorChange);
}, this);
}
};
/**
* If any of the arrays in the `filters` property have a length of more than zero,
* that means there is an active filter.
* @return {boolean}
*/
Demo.prototype.hasActiveFilters = function () {
return Object.keys(this.filters).some(function (key) {
return this.filters[key].length > 0;
}, this);
};
/**
* Determine whether an element passes the current filters.
* @param {Element} element Element to test.
* @return {boolean} Whether it satisfies all current filters.
*/
Demo.prototype.itemPassesFilters = function (element) {
var shapes = this.filters.shapes;
var colors = this.filters.colors;
var shape = element.getAttribute('data-shape');
var color = element.getAttribute('data-color');
// If there are active shape filters and this shape is not in that array.
if (shapes.length > 0 && !shapes.includes(shape)) {
return false;
/**
* Get the values of each checked input.
* @return {Array.<string>}
*/
_getCurrentShapeFilters() {
return this.shapes.filter((input) => input.checked).map((input) => input.value);
}
// If there are active color filters and this color is not in that array.
if (colors.length > 0 && !colors.includes(color)) {
return false;
/**
* Get the values of each `active` button.
* @return {Array.<string>}
*/
_getCurrentColorFilters() {
return this.colors
.filter((button) => button.classList.contains('active'))
.map((button) => button.getAttribute('data-value'));
}
return true;
};
/**
* A shape input check state changed, update the current filters and filte.r
*/
_handleShapeChange() {
this.filters.shapes = this._getCurrentShapeFilters();
this.filter();
}
/**
* A color button was clicked. Update filters and display.
* @param {Event} evt Click event object.
*/
_handleColorChange(evt) {
var button = evt.currentTarget;
// Treat these buttons like radio buttons where only 1 can be selected.
if (button.classList.contains('active')) {
button.classList.remove('active');
} else {
this.colors.forEach((btn) => {
btn.classList.remove('active');
});
button.classList.add('active');
}
this.filters.colors = this._getCurrentColorFilters();
this.filter();
}
/**
* Filter shuffle based on the current state of filters.
*/
filter() {
if (this.hasActiveFilters()) {
this.shuffle.filter(this.itemPassesFilters.bind(this));
} else {
this.shuffle.filter(Shuffle.ALL_ITEMS);
}
}
/**
* If any of the arrays in the `filters` property have a length of more than zero,
* that means there is an active filter.
* @return {boolean}
*/
hasActiveFilters() {
return Object.keys(this.filters).some((key) => {
return this.filters[key].length > 0;
}, this);
}
/**
* Determine whether an element passes the current filters.
* @param {Element} element Element to test.
* @return {boolean} Whether it satisfies all current filters.
*/
itemPassesFilters(element) {
var shapes = this.filters.shapes;
var colors = this.filters.colors;
var shape = element.getAttribute('data-shape');
var color = element.getAttribute('data-color');
// If there are active shape filters and this shape is not in that array.
if (shapes.length > 0 && !shapes.includes(shape)) {
return false;
}
// If there are active color filters and this color is not in that array.
if (colors.length > 0 && !colors.includes(color)) {
return false;
}
return true;
}
}
document.addEventListener('DOMContentLoaded', function () {
document.addEventListener('DOMContentLoaded', () => {
window.demo = new Demo(document.querySelector('.js-shuffle'));
});

@ -2,194 +2,194 @@
var Shuffle = window.Shuffle;
var Demo = function (element) {
this.element = element;
class Demo {
constructor(element) {
this.element = element;
this.shuffle = new Shuffle(element, {
itemSelector: '.picture-item',
sizer: element.querySelector('.my-sizer-element'),
});
this.shuffle = new Shuffle(element, {
itemSelector: '.picture-item',
sizer: element.querySelector('.my-sizer-element'),
});
// Log events.
this.addShuffleEventListeners();
// Log events.
this.addShuffleEventListeners();
this._activeFilters = [];
this._activeFilters = [];
this.addFilterButtons();
this.addSorting();
this.addSearchFilter();
this.addFilterButtons();
this.addSorting();
this.addSearchFilter();
this.mode = 'exclusive';
};
Demo.prototype.toggleMode = function () {
if (this.mode === 'additive') {
this.mode = 'exclusive';
} else {
this.mode = 'additive';
}
};
/**
* Shuffle uses the CustomEvent constructor to dispatch events. You can listen
* for them like you normally would (with jQuery for example).
*/
Demo.prototype.addShuffleEventListeners = function () {
this.shuffle.on(Shuffle.EventType.LAYOUT, function (data) {
console.log('layout. data:', data);
});
this.shuffle.on(Shuffle.EventType.REMOVED, function (data) {
console.log('removed. data:', data);
});
};
Demo.prototype.addFilterButtons = function () {
var options = document.querySelector('.filter-options');
if (!options) {
return;
toggleMode() {
if (this.mode === 'additive') {
this.mode = 'exclusive';
} else {
this.mode = 'additive';
}
}
var filterButtons = Array.from(options.children);
/**
* Shuffle uses the CustomEvent constructor to dispatch events. You can listen
* for them like you normally would (with jQuery for example).
*/
addShuffleEventListeners() {
this.shuffle.on(Shuffle.EventType.LAYOUT, (data) => {
console.log('layout. data:', data);
});
this.shuffle.on(Shuffle.EventType.REMOVED, (data) => {
console.log('removed. data:', data);
});
}
filterButtons.forEach(function (button) {
button.addEventListener('click', this._handleFilterClick.bind(this), false);
}, this);
};
addFilterButtons() {
var options = document.querySelector('.filter-options');
Demo.prototype._handleFilterClick = function (evt) {
var btn = evt.currentTarget;
var isActive = btn.classList.contains('active');
var btnGroup = btn.getAttribute('data-group');
if (!options) {
return;
}
// You don't need _both_ of these modes. This is only for the demo.
var filterButtons = Array.from(options.children);
// For this custom 'additive' mode in the demo, clicking on filter buttons
// doesn't remove any other filters.
if (this.mode === 'additive') {
// If this button is already active, remove it from the list of filters.
if (isActive) {
this._activeFilters.splice(this._activeFilters.indexOf(btnGroup));
} else {
this._activeFilters.push(btnGroup);
}
filterButtons.forEach((button) => {
button.addEventListener('click', this._handleFilterClick.bind(this), false);
}, this);
}
btn.classList.toggle('active');
_handleFilterClick(evt) {
var btn = evt.currentTarget;
var isActive = btn.classList.contains('active');
var btnGroup = btn.getAttribute('data-group');
// You don't need _both_ of these modes. This is only for the demo.
// For this custom 'additive' mode in the demo, clicking on filter buttons
// doesn't remove any other filters.
if (this.mode === 'additive') {
// If this button is already active, remove it from the list of filters.
if (isActive) {
this._activeFilters.splice(this._activeFilters.indexOf(btnGroup));
} else {
this._activeFilters.push(btnGroup);
}
// Filter elements
this.shuffle.filter(this._activeFilters);
btn.classList.toggle('active');
// 'exclusive' mode lets only one filter button be active at a time.
} else {
this._removeActiveClassFromChildren(btn.parentNode);
// Filter elements
this.shuffle.filter(this._activeFilters);
var filterGroup;
if (isActive) {
btn.classList.remove('active');
filterGroup = Shuffle.ALL_ITEMS;
// 'exclusive' mode lets only one filter button be active at a time.
} else {
btn.classList.add('active');
filterGroup = btnGroup;
}
this.shuffle.filter(filterGroup);
}
};
this._removeActiveClassFromChildren(btn.parentNode);
var filterGroup;
if (isActive) {
btn.classList.remove('active');
filterGroup = Shuffle.ALL_ITEMS;
} else {
btn.classList.add('active');
filterGroup = btnGroup;
}
Demo.prototype._removeActiveClassFromChildren = function (parent) {
var children = parent.children;
for (var i = children.length - 1; i >= 0; i--) {
children[i].classList.remove('active');
this.shuffle.filter(filterGroup);
}
}
};
Demo.prototype.addSorting = function () {
var buttonGroup = document.querySelector('.sort-options');
if (!buttonGroup) {
return;
_removeActiveClassFromChildren(parent) {
var children = parent.children;
for (var i = children.length - 1; i >= 0; i--) {
children[i].classList.remove('active');
}
}
buttonGroup.addEventListener('change', this._handleSortChange.bind(this));
};
addSorting() {
var buttonGroup = document.querySelector('.sort-options');
Demo.prototype._handleSortChange = function (evt) {
// Add and remove `active` class from buttons.
var buttons = Array.from(evt.currentTarget.children);
buttons.forEach(function (button) {
if (button.querySelector('input').value === evt.target.value) {
button.classList.add('active');
} else {
button.classList.remove('active');
if (!buttonGroup) {
return;
}
});
// Create the sort options to give to Shuffle.
var value = evt.target.value;
var options = {};
function sortByDate(element) {
return Date.parse(element.getAttribute('data-date-created'));
buttonGroup.addEventListener('change', this._handleSortChange.bind(this));
}
function sortByTitle(element) {
return element.getAttribute('data-title').toLowerCase();
}
_handleSortChange(evt) {
// Add and remove `active` class from buttons.
var buttons = Array.from(evt.currentTarget.children);
buttons.forEach((button) => {
if (button.querySelector('input').value === evt.target.value) {
button.classList.add('active');
} else {
button.classList.remove('active');
}
});
if (value === 'date-created') {
options = {
reverse: true,
by: sortByDate,
};
} else if (value === 'title') {
options = {
by: sortByTitle,
};
}
// Create the sort options to give to Shuffle.
var value = evt.target.value;
var options = {};
this.shuffle.sort(options);
};
function sortByDate(element) {
return Date.parse(element.getAttribute('data-date-created'));
}
// Advanced filtering
Demo.prototype.addSearchFilter = function () {
var searchInput = document.querySelector('.js-shuffle-search');
function sortByTitle(element) {
return element.getAttribute('data-title').toLowerCase();
}
if (!searchInput) {
return;
}
if (value === 'date-created') {
options = {
reverse: true,
by: sortByDate,
};
} else if (value === 'title') {
options = {
by: sortByTitle,
};
}
searchInput.addEventListener('input', this._handleSearchKeyup.bind(this));
};
this.shuffle.sort(options);
}
/**
* Filter the shuffle instance by items with a title that matches the search input.
* @param {Event} evt Event object.
*/
Demo.prototype._handleSearchKeyup = function (evt) {
var searchText = evt.target.value.toLowerCase();
// Advanced filtering
addSearchFilter() {
var searchInput = document.querySelector('.js-shuffle-search');
this.shuffle.filter(function (element, shuffle) {
if (!searchInput) {
return;
}
// If there is a current filter applied, ignore elements that don't match it.
if (shuffle.group !== Shuffle.ALL_ITEMS) {
// Get the item's groups.
var groups = JSON.parse(element.getAttribute('data-groups'));
var isElementInCurrentGroup = groups.indexOf(shuffle.group) !== -1;
searchInput.addEventListener('input', this._handleSearchKeyup.bind(this));
}
// Only search elements in the current group
if (!isElementInCurrentGroup) {
return false;
/**
* Filter the shuffle instance by items with a title that matches the search input.
* @param {Event} evt Event object.
*/
_handleSearchKeyup(evt) {
var searchText = evt.target.value.toLowerCase();
this.shuffle.filter((element, shuffle) => {
// If there is a current filter applied, ignore elements that don't match it.
if (shuffle.group !== Shuffle.ALL_ITEMS) {
// Get the item's groups.
var groups = JSON.parse(element.getAttribute('data-groups'));
var isElementInCurrentGroup = groups.indexOf(shuffle.group) !== -1;
// Only search elements in the current group
if (!isElementInCurrentGroup) {
return false;
}
}
}
var titleElement = element.querySelector('.picture-item__title');
var titleText = titleElement.textContent.toLowerCase().trim();
var titleElement = element.querySelector('.picture-item__title');
var titleText = titleElement.textContent.toLowerCase().trim();
return titleText.indexOf(searchText) !== -1;
});
};
return titleText.indexOf(searchText) !== -1;
});
}
}
document.addEventListener('DOMContentLoaded', function () {
document.addEventListener('DOMContentLoaded', () => {
window.demo = new Demo(document.getElementById('grid'));
});

@ -25,7 +25,8 @@ class PhotoGrid extends Component {
// use that here while waiting on a network request.
const grayPixel = 'data:image/gif;base64,R0lGODlhAQABAIAAAMLCwgAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==';
const blackPixel = 'data:image/gif;base64,R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs=';
const greenPixel = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mO02Vz4HwAE9AJhcLBN6AAAAABJRU5ErkJggg==';
const greenPixel =
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mO02Vz4HwAE9AJhcLBN6AAAAABJRU5ErkJggg==';
this.state = {
photos: [
@ -47,12 +48,42 @@ class PhotoGrid extends Component {
return new Promise((resolve) => {
setTimeout(() => {
resolve([
{ id: 4, username: '@stickermule', name: 'Sticker Mule', src: 'https://images.unsplash.com/photo-1484244233201-29892afe6a2c?ixlib=rb-0.3.5&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=800&h=600&fit=crop&s=14d236624576109b51e85bd5d7ebfbfc' },
{ id: 5, username: '@prostoroman', name: 'Roman Logov', src: 'https://images.unsplash.com/photo-1465414829459-d228b58caf6e?ixlib=rb-0.3.5&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=800&h=600&fit=crop&s=7a7080fc0699869b1921cb1e7047c5b3' },
{ id: 6, username: '@richienolan', name: 'Richard Nolan', src: 'https://images.unsplash.com/photo-1478033394151-c931d5a4bdd6?ixlib=rb-0.3.5&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=800&h=600&fit=crop&s=3c74d594a86e26c5a319f4e17b36146e' },
{ id: 7, username: '@wexor', name: 'Wexor Tmg', src: 'https://images.unsplash.com/photo-1437622368342-7a3d73a34c8f?ixlib=rb-0.3.5&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=800&h=600&fit=crop&s=11ff283143c782980861a442a957da8e' },
{ id: 8, username: '@dnevozhai', name: 'Denys Nevozhai', src: 'https://images.unsplash.com/photo-1465447142348-e9952c393450?ixlib=rb-0.3.5&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=800&h=600&fit=crop&s=ea06c0f0700ec469fdcb32e0d4c2928e' },
{ id: 9, username: '@aronvandepol', name: 'Aron Van de Pol', src: 'https://images.unsplash.com/photo-1469719847081-4757697d117a?ixlib=rb-0.3.5&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=800&h=600&fit=crop&s=9a568bc48e42d3bb60c97c0eb3dc20ac' },
{
id: 4,
username: '@stickermule',
name: 'Sticker Mule',
src: 'https://images.unsplash.com/photo-1484244233201-29892afe6a2c?ixlib=rb-0.3.5&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=800&h=600&fit=crop&s=14d236624576109b51e85bd5d7ebfbfc',
},
{
id: 5,
username: '@prostoroman',
name: 'Roman Logov',
src: 'https://images.unsplash.com/photo-1465414829459-d228b58caf6e?ixlib=rb-0.3.5&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=800&h=600&fit=crop&s=7a7080fc0699869b1921cb1e7047c5b3',
},
{
id: 6,
username: '@richienolan',
name: 'Richard Nolan',
src: 'https://images.unsplash.com/photo-1478033394151-c931d5a4bdd6?ixlib=rb-0.3.5&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=800&h=600&fit=crop&s=3c74d594a86e26c5a319f4e17b36146e',
},
{
id: 7,
username: '@wexor',
name: 'Wexor Tmg',
src: 'https://images.unsplash.com/photo-1437622368342-7a3d73a34c8f?ixlib=rb-0.3.5&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=800&h=600&fit=crop&s=11ff283143c782980861a442a957da8e',
},
{
id: 8,
username: '@dnevozhai',
name: 'Denys Nevozhai',
src: 'https://images.unsplash.com/photo-1465447142348-e9952c393450?ixlib=rb-0.3.5&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=800&h=600&fit=crop&s=ea06c0f0700ec469fdcb32e0d4c2928e',
},
{
id: 9,
username: '@aronvandepol',
name: 'Aron Van de Pol',
src: 'https://images.unsplash.com/photo-1469719847081-4757697d117a?ixlib=rb-0.3.5&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=800&h=600&fit=crop&s=9a568bc48e42d3bb60c97c0eb3dc20ac',
},
]);
}, 300);
});
@ -64,18 +95,23 @@ class PhotoGrid extends Component {
* @return {Promise<Object[]>} Loaded images.
*/
_whenPhotosLoaded(photos) {
return Promise.all(photos.map(photo => new Promise((resolve) => {
const image = document.createElement('img');
image.src = photo.src;
if (image.naturalWidth > 0 || image.complete) {
resolve(photo);
} else {
image.onload = () => {
resolve(photo);
};
}
})));
return Promise.all(
photos.map(
(photo) =>
new Promise((resolve) => {
const image = document.createElement('img');
image.src = photo.src;
if (image.naturalWidth > 0 || image.complete) {
resolve(photo);
} else {
image.onload = () => {
resolve(photo);
};
}
}),
),
);
}
componentDidMount() {
@ -108,7 +144,9 @@ class PhotoGrid extends Component {
render() {
return (
<div ref={this.element} className="row my-shuffle">
{this.state.photos.map(image => <PhotoItem {...image}/>)}
{this.state.photos.map((image) => (
<PhotoItem {...image} />
))}
<div ref={this.sizer} className="col-1@xs col-1@sm photo-grid__sizer"></div>
</div>
);
@ -130,7 +168,7 @@ function PhotoItem({ id, username, src, name }) {
</div>
</div>
</div>
)
);
}
/**

@ -1,7 +1,5 @@
(function () {
'use strict';
var Questions = function () {
class Questions {
constructor() {
this.searchInput = document.querySelector('#search');
this.questions = document.querySelectorAll('.js-question');
@ -15,9 +13,9 @@
window.addEventListener('resize', this.onWindowResize.bind(this));
this.setHeights();
};
}
Questions.prototype._handleInput = function (evt) {
_handleInput(evt) {
var val = evt.target.value.toLowerCase();
// Filter elements based on if their string exists in the product model
@ -32,27 +30,26 @@
el.classList.remove('question--collapsed');
}
}
};
}
Questions.prototype.setHeights = function () {
setHeights() {
var elements = Array.from(this.questions);
elements.forEach(function (element) {
elements.forEach((element) => {
element.style.height = '';
});
var heights = elements.map(function (element) {
var heights = elements.map((element) => {
return element.firstElementChild.offsetHeight;
});
elements.forEach(function (element, i) {
elements.forEach((element, i) => {
element.style.height = heights[i] + 'px';
});
};
Questions.prototype.onWindowResize = function () {
}
onWindowResize() {
this.setHeights();
};
}
}
new Questions();
}());
new Questions();

File diff suppressed because one or more lines are too long

@ -2,14 +2,6 @@ requirejs.config({
baseUrl: window.site_url + '/js',
paths: {
shufflejs: '../dist/shuffle',
polyfill: 'https://polyfill.io/v3/polyfill.min.js?features=default%2Ces5%2Ces6%2Ces7',
},
// Load the polyfill before Shuffle.
shim: {
shufflejs: {
deps: ['polyfill'],
},
},
});

@ -1,5 +1,5 @@
(function () {
var SiteNav = function (element) {
class SiteNav {
constructor(element) {
this.element = element;
var buttons = Array.from(document.querySelectorAll('.site-nav__link-toggle'));
var dropdowns = buttons.map(function (button) {
@ -15,9 +15,9 @@
this.handleResize = this.handleResize.bind(this);
window.addEventListener('resize', this.handleResize);
window.addEventListener('load', this.handleResize);
};
}
SiteNav.prototype.toggle = function (event) {
toggle(event) {
var button = event.currentTarget;
var wrapper = button.parentNode;
var willOpen = !wrapper.classList.contains('site-nav__link--dropdown-active');
@ -36,16 +36,16 @@
} else {
document.body.classList.toggle('site-nav--open');
}
};
}
SiteNav.prototype.handleResize = function () {
handleResize() {
var viewportHeight = window.innerHeight;
var navHeight = this.element.offsetHeight;
var dropdowns = Array.from(document.querySelectorAll('.site-nav__dropdown'));
dropdowns.forEach(function (dropdown) {
dropdown.style.maxHeight = (viewportHeight - navHeight) + 'px';
dropdown.style.maxHeight = viewportHeight - navHeight + 'px';
});
};
}
}
new SiteNav(document.querySelector('.site-nav'));
})();
new SiteNav(document.querySelector('.site-nav'));

@ -9,6 +9,7 @@ const commonjsOptions = {
const babelOptions = {
exclude: 'node_modules/**',
babelHelpers: 'bundled',
};
const minifyOptions = {

@ -2,6 +2,5 @@ const gulp = require('gulp');
// Copy dist directory to docs. GitHub pages don't work with symlinks.
module.exports = function copyDist() {
return gulp.src('dist/*')
.pipe(gulp.dest('docs/dist/'));
return gulp.src('dist/*').pipe(gulp.dest('docs/dist/'));
};

@ -5,6 +5,5 @@ const shell = require('gulp-shell');
module.exports = function jekyll() {
const cmd = 'jekyll serve --config _config.yml,_config_dev.yml';
return gulp.src('docs/_config.yml', { read: false })
.pipe(shell([cmd], { cwd: path.join(process.cwd(), 'docs') }));
return gulp.src('docs/_config.yml', { read: false }).pipe(shell([cmd], { cwd: path.join(process.cwd(), 'docs') }));
};

@ -2,10 +2,12 @@ const { rollup } = require('rollup');
const { configs } = require('../config');
module.exports = function scripts() {
const bundles = configs.map(config => rollup(config).then((bundle) => {
config.cache = bundle;
return bundle.write(config.output);
}));
const bundles = configs.map((config) =>
rollup(config).then((bundle) => {
config.cache = bundle;
return bundle.write(config.output);
}),
);
return Promise.all(bundles);
};

@ -2,8 +2,9 @@ const gulp = require('gulp');
const shell = require('gulp-shell');
module.exports = function test() {
return gulp.src('package.json', {
read: false,
})
return gulp
.src('package.json', {
read: false,
})
.pipe(shell(['npx jest']));
};

@ -7,11 +7,6 @@ gulp.task('css', require('./gulp/tasks/css'));
gulp.task('jekyll', require('./gulp/tasks/jekyll'));
gulp.task('test', require('./gulp/tasks/test'));
gulp.task('watch', gulp.series(
'set-watching',
gulp.parallel('css', 'scripts'),
'copy-dist',
'jekyll',
));
gulp.task('watch', gulp.series('set-watching', gulp.parallel('css', 'scripts'), 'copy-dist', 'jekyll'));
gulp.task('default', gulp.series('scripts', 'css', 'test', 'copy-dist'));

5
index.d.ts vendored

@ -1,4 +1,4 @@
// Type definitions for Shuffle 5.2.2
// Type definitions for Shuffle 6.0.0
// Project: https://github.com/Vestride/Shuffle
// Definitions by: Glen Cheney <https://github.com/Vestride>
@ -32,9 +32,6 @@ export interface ShuffleOptions {
*/
delimiter?: string;
/** @deprecated Misspelling that will be removed in v6 */
delimeter?: string;
/**
* CSS easing function to use.
*/

@ -1,6 +1,6 @@
{
"name": "shufflejs",
"version": "5.4.1",
"version": "6.0.0",
"description": "Categorize, sort, and filter a responsive grid of items",
"keywords": [
"gallery",
@ -47,7 +47,6 @@
],
"dependencies": {
"array-parallel": "^0.1.3",
"matches-selector": "^1.0.0",
"throttleit": "^1.0.0",
"tiny-emitter": "^2.1.0"
},
@ -69,6 +68,7 @@
"gulp-shell": "^0.8.0",
"jest": "^27.4.7",
"postcss": "^8.4.5",
"prettier": "^2.5.1",
"rollup": "^2.66.1",
"rollup-plugin-terser": "^7.0.0",
"sass": "^1.49.0",

@ -0,0 +1,7 @@
module.exports = {
printWidth: 120,
trailingComma: 'all',
semi: true,
tabWidth: 2,
singleQuote: true,
};

@ -1,3 +1,3 @@
export default function arrayMax(array) {
return Math.max.apply(Math, array); // eslint-disable-line prefer-spread
return Math.max(...array);
}

2
src/array-min.js vendored

@ -1,3 +1,3 @@
export default function arrayMin(array) {
return Math.min.apply(Math, array); // eslint-disable-line prefer-spread
return Math.min(...array);
}

@ -11,23 +11,22 @@ import testComputedSize from './computed-size';
* will return 'auto' when the element doesn't have margins instead of
* the computed style.
*/
export default function getNumberStyle(
element, style,
styles = window.getComputedStyle(element, null),
) {
export default function getNumberStyle(element, style, styles = window.getComputedStyle(element, null)) {
let value = getNumber(styles[style]);
// Support IE<=11 and W3C spec.
if (!testComputedSize() && style === 'width') {
value += getNumber(styles.paddingLeft)
+ getNumber(styles.paddingRight)
+ getNumber(styles.borderLeftWidth)
+ getNumber(styles.borderRightWidth);
value +=
getNumber(styles.paddingLeft) +
getNumber(styles.paddingRight) +
getNumber(styles.borderLeftWidth) +
getNumber(styles.borderRightWidth);
} else if (!testComputedSize() && style === 'height') {
value += getNumber(styles.paddingTop)
+ getNumber(styles.paddingBottom)
+ getNumber(styles.borderTopWidth)
+ getNumber(styles.borderBottomWidth);
value +=
getNumber(styles.paddingTop) +
getNumber(styles.paddingBottom) +
getNumber(styles.borderTopWidth) +
getNumber(styles.borderBottomWidth);
}
return value;

@ -100,9 +100,7 @@ export function getShortColumn(positions, buffer) {
* @param {number} buffer Vertical buffer for the height of items.
* @return {Point}
*/
export function getItemPosition({
itemSize, positions, gridSize, total, threshold, buffer,
}) {
export function getItemPosition({ itemSize, positions, gridSize, total, threshold, buffer }) {
const span = getColumnSpan(itemSize.width, gridSize, total, threshold);
const setY = getAvailablePositions(positions, span, total);
const shortColumnIndex = getShortColumn(setY, buffer);
@ -183,13 +181,15 @@ export function getCenteredPositions(itemRects, containerWidth) {
// elements could be in the way).
if (!canMove) {
let intersectingRect;
const hasOverlap = itemRects.some((itemRect) => rects.some((r) => {
const intersects = Rect.intersects(itemRect, r);
if (intersects) {
intersectingRect = r;
}
return intersects;
}));
const hasOverlap = itemRects.some((itemRect) =>
rects.some((r) => {
const 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) {
@ -206,7 +206,8 @@ export function getCenteredPositions(itemRects, containerWidth) {
// 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((a, b) => (a.id - b.id))
return centeredRows
.flat()
.sort((a, b) => a.id - b.id)
.map((itemRect) => new Point(itemRect.left, itemRect.top));
}

@ -33,7 +33,7 @@ export default class Rect {
*/
static 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);
a.left < b.left + b.width && b.left < a.left + a.width && a.top < b.top + b.height && b.top < a.top + a.height
);
}
}

@ -69,11 +69,7 @@ class ShuffleItem {
}
dispose() {
this.removeClasses([
Classes.HIDDEN,
Classes.VISIBLE,
Classes.SHUFFLE_ITEM,
]);
this.removeClasses([Classes.HIDDEN, Classes.VISIBLE, Classes.SHUFFLE_ITEM]);
this.element.removeAttribute('style');
this.element = null;

@ -1,5 +1,4 @@
import TinyEmitter from 'tiny-emitter';
import matches from 'matches-selector';
import throttle from 'throttleit';
import parallel from 'array-parallel';
@ -31,14 +30,7 @@ class Shuffle extends TinyEmitter {
*/
constructor(element, options = {}) {
super();
// eslint-disable-next-line prefer-object-spread
this.options = Object.assign({}, Shuffle.options, options);
// Allow misspelling of delimiter since that's how it used to be.
// Remove in v6.
if (this.options.delimeter) {
this.options.delimiter = this.options.delimeter;
}
this.options = { ...Shuffle.options, ...options };
this.lastSort = {};
this.group = Shuffle.ALL_ITEMS;
@ -327,7 +319,7 @@ class Shuffle extends TinyEmitter {
_getItems() {
return Array.from(this.element.children)
.filter((el) => matches(el, this.options.itemSelector))
.filter((el) => el.matches(this.options.itemSelector))
.map((el) => new ShuffleItem(el, this.options.isRTL));
}
@ -641,8 +633,7 @@ class Shuffle extends TinyEmitter {
*/
getStylesForTransition(item, styleObject) {
// Clone the object to avoid mutating the original.
// eslint-disable-next-line prefer-object-spread
const styles = Object.assign({}, styleObject);
const styles = { ...styleObject };
if (this.options.useTransforms) {
const sign = this.options.isRTL ? '-' : '';

@ -44,8 +44,7 @@ const defaults = {
* @return {Array<T>}
*/
export default function sorter(arr, options) {
// eslint-disable-next-line prefer-object-spread
const opts = Object.assign({}, defaults, options);
const opts = { ...defaults, ...options };
const original = Array.from(arr);
let revert = false;

@ -623,15 +623,6 @@ describe('shuffle', () => {
expect(instance.visibleItems).toBe(3);
});
it('can use the old misspelled delimiter option', () => {
instance = new Shuffle(fixture, {
delimeter: ',',
group: 'design',
});
expect(instance.visibleItems).toBe(3);
});
});
describe('Custom shuffle item styles', () => {

@ -2,7 +2,7 @@
"compilerOptions": {
/* Basic Options */
// "incremental": true, /* Enable incremental compilation */
"target": "ES2018", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
"target": "ES2018" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */,
// "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
// "lib": [], /* Specify library files to be included in the compilation. */
// "allowJs": true, /* Allow javascript files to be compiled. */
@ -12,7 +12,7 @@
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
// "sourceMap": true, /* Generates corresponding '.map' file. */
// "outFile": "./", /* Concatenate and emit output to single file. */
"outDir": "./build", /* Redirect output structure to the directory. */
"outDir": "./build" /* Redirect output structure to the directory. */,
// "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
// "composite": true, /* Enable project compilation */
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
@ -23,14 +23,14 @@
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
/* Strict Type-Checking Options */
"strict": true, /* Enable all strict type-checking options. */
"noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
"strictNullChecks": true, /* Enable strict null checks. */
"strictFunctionTypes": true, /* Enable strict checking of function types. */
"strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
"strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
"noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
"alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
"strict": true /* Enable all strict type-checking options. */,
"noImplicitAny": true /* Raise error on expressions and declarations with an implied 'any' type. */,
"strictNullChecks": true /* Enable strict null checks. */,
"strictFunctionTypes": true /* Enable strict checking of function types. */,
"strictBindCallApply": true /* Enable strict 'bind', 'call', and 'apply' methods on functions. */,
"strictPropertyInitialization": true /* Enable strict checking of property initialization in classes. */,
"noImplicitThis": true /* Raise error on 'this' expressions with an implied 'any' type. */,
"alwaysStrict": true /* Parse in strict mode and emit "use strict" for each source file. */,
/* Additional Checks */
// "noUnusedLocals": true, /* Report errors on unused locals. */
@ -39,14 +39,14 @@
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
/* Module Resolution Options */
"moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
"moduleResolution": "node" /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */,
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
// "typeRoots": [], /* List of folders to include type definitions from. */
// "types": [], /* Type declaration files to be included in compilation. */
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
"esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
"esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */

Loading…
Cancel
Save