Skip to content

Commit

Permalink
Merge pull request #2 from RCopeland/stepper-carousel
Browse files Browse the repository at this point in the history
Stepper carousel
  • Loading branch information
afebbraro committed Apr 10, 2019
2 parents 4d354e7 + 42ae657 commit 03b44e5
Show file tree
Hide file tree
Showing 15 changed files with 1,119 additions and 356 deletions.
5 changes: 1 addition & 4 deletions .eslintrc
Expand Up @@ -11,10 +11,7 @@
"ignoreUrls": true
}],
"prettier/prettier": ["error"],
"object-curly-newline": ["error", {
"ObjectPattern": { "multiline": true },
"ImportDeclaration": "never"
}],
"object-curly-newline": "off",
"react/jsx-filename-extension": "off",
"jsx-a11y/label-has-associated-control": [ 2, {
"labelComponents": ["label"],
Expand Down
970 changes: 659 additions & 311 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Expand Up @@ -52,7 +52,7 @@
"prettier-stylelint": "^0.4.2",
"request": "^2.88.0",
"sinon": "^7.2.2",
"stylelint": "^9.6.0",
"stylelint": "^9.10.1",
"stylelint-scss": "^3.3.1",
"suitcss-base": "^2.0.0",
"suitcss-components-arrange": "^1.1.1",
Expand Down
1 change: 1 addition & 0 deletions packages/spark-core/_spark-core.scss
Expand Up @@ -53,6 +53,7 @@
@import './components/accordions';
@import './components/alerts';
@import './components/buttons';
@import './components/carousel';
@import './components/datepicker';
@import './components/dividers';
@import './components/dropdown';
Expand Down
76 changes: 76 additions & 0 deletions packages/spark-core/components/_carousel.scss
@@ -0,0 +1,76 @@
.sprk-c-Carousel__frame {
width: 100%;
position: relative;
font-size: 0;
line-height: 0;
overflow: hidden;
white-space: nowrap;
}

.sprk-c-Carousel__frame-item {
position: relative;
display: inline-block;
font-family: 'Source Sans Pro', sans-serif;
text-align: center;
font-size: $sprk-font-size-body-two;
line-height: $sprk-line-height-body-two;
color: $sprk-white;
width: 100%;
}

.sprk-c-Carousel__slides {
display: inline-block;
}

.sprk-c-Carousel__controls {
justify-content: space-between;
display: flex;
width: 76px;
margin: 0 auto;

@media (min-width: 80rem) {
display: none;
}
}

.sprk-c-Carousel__prev,
.sprk-c-Carousel__next {
display: block;
cursor: pointer;
}

.sprk-c-Carousel__next {
right: 0;
}

.sprk-c-Carousel__prev {
left: 0;
}

.sprk-c-Carousel__dots {
display: flex;
justify-content: center;
margin: 1rem auto;

@media (min-width: 80rem) {
display: none;
}
}

.sprk-c-Carousel__dot {
border: 2px solid $sprk-white;
border-radius: 50%;
display: block;
height: 10px;
width: 10px;
margin-right: 20px;
}

.sprk-c-Carousel__dot:last-child {
margin-right: 0;
}

.sprk-c-Carousel__dot--active {
background-color: $sprk-white;
box-shadow: 0 0 0 8px $sprk-green;
}
2 changes: 1 addition & 1 deletion packages/spark-core/components/_stepper.scss
Expand Up @@ -188,4 +188,4 @@
.sprk-c-Stepper__step-description {
padding-top: $sprk-stepper-step-description-top-spacing;
transition: opacity 0.1s ease-in-out;
}
}
66 changes: 66 additions & 0 deletions packages/spark-core/components/carousel.js
@@ -0,0 +1,66 @@
import { lory } from 'lory.js';

const initDots = (dotContainer, count) => {
const dotListItem = document.createElement('li');
dotListItem.classList.add('sprk-c-Carousel__dot');
for (let i = 0; i < count; i += 1) {
dotContainer.appendChild(dotListItem.cloneNode());
}
dotContainer.childNodes[0].classList.add('sprk-c-Carousel__dot--active');
};

// init carousel
const carousel = item => {
let carouselInstance;
const slideCount = item.querySelectorAll('li').length;
const dotContainer = item.querySelector('[data-sprk-carousel-dots]');
// before init event
item.addEventListener('before.lory.init', () => {
if (dotContainer) {
initDots(dotContainer, slideCount);
}
});
// after init event
item.addEventListener('after.lory.init', () => {
if (dotContainer) {
const dots = dotContainer.querySelectorAll('li');
dots.forEach((dot, index) => {
dot.addEventListener('click', event => {
event.preventDefault();
carouselInstance.slideTo(index);
});
});
}
});
// after slide event
item.addEventListener('after.lory.slide', event => {
if (dotContainer) {
const dots = dotContainer.querySelectorAll('li');
dots.forEach(dot => {
dot.classList.remove('sprk-c-Carousel__dot--active');
});
dots[event.detail.currentSlide - 1].classList.add(
'sprk-c-Carousel__dot--active',
);
item.dispatchEvent(
new CustomEvent('sprk.carousel.slide', {
detail: {
index: [event.detail.currentSlide - 1],
},
}),
);
}
});

carouselInstance = lory(item, {
classNameFrame: 'sprk-c-Carousel__frame',
classNameSlideContainer: 'sprk-c-Carousel__slides',
classNamePrevCtrl: 'sprk-c-Carousel__prev',
classNameNextCtrl: 'sprk-c-Carousel__next',
infinite: 1,
enableMouseEvents: true,
});
return carouselInstance;
};

export { carousel, initDots };
40 changes: 25 additions & 15 deletions packages/spark-core/components/dropdown.js
Expand Up @@ -2,62 +2,72 @@
import getElements from '../utilities/getElements';
import { isEscPressed } from '../utilities/keypress';

const hideDropDown = (dropdown) => {
const hideDropDown = dropdown => {
dropdown.classList.remove('sprk-c-Dropdown--open');
dropdown.classList.add('sprk-u-Display--none');
};

const showDropDown = (dropdown) => {
const showDropDown = dropdown => {
dropdown.classList.add('sprk-c-Dropdown--open');
dropdown.classList.remove('sprk-u-Display--none');
};

const removeActiveStatus = (choices) => {
choices.forEach((choice) => {
const removeActiveStatus = choices => {
choices.forEach(choice => {
choice.classList.remove('sprk-c-Dropdown__link--active');
});
};

const toggleDropDown = (dropdown) => {
const toggleDropDown = dropdown => {
if (dropdown.classList.contains('sprk-c-Dropdown--open')) {
hideDropDown(dropdown);
} else {
showDropDown(dropdown);
}
};

const bindUIEvents = (dropdownTrigger) => {
const bindUIEvents = dropdownTrigger => {
const id = dropdownTrigger.getAttribute('data-sprk-dropdown-trigger');
const triggerText = dropdownTrigger.querySelector('[data-sprk-dropdown-trigger-text-container]');
const dropdownElement = document.querySelector(`[data-sprk-dropdown="${id}"]`);
const dropdownChoices = dropdownElement.querySelectorAll('[data-sprk-dropdown-choice]');
const triggerText = dropdownTrigger.querySelector(
'[data-sprk-dropdown-trigger-text-container]',
);
const dropdownElement = document.querySelector(
`[data-sprk-dropdown="${id}"]`,
);
const dropdownChoices = dropdownElement.querySelectorAll(
'[data-sprk-dropdown-choice]',
);

dropdownTrigger.addEventListener('click', () => {
toggleDropDown(dropdownElement);
});

document.addEventListener('click', (e) => {
if (!(dropdownElement.contains(e.target) || dropdownTrigger.contains(e.target))) {
document.addEventListener('click', e => {
if (
!(
dropdownElement.contains(e.target) || dropdownTrigger.contains(e.target)
)
) {
hideDropDown(dropdownElement);
}
});

document.addEventListener('keydown', (e) => {
document.addEventListener('keydown', e => {
if (isEscPressed(e)) {
hideDropDown(dropdownElement);
}
});

document.addEventListener('focusin', (e) => {
document.addEventListener('focusin', e => {
/* istanbul ignore else: jsdom cant fire focusin on an element */
if (!dropdownElement.contains(e.target)) {
hideDropDown(dropdownElement);
}
});

dropdownChoices.forEach((choice) => {
dropdownChoices.forEach(choice => {
const value = choice.getAttribute('data-sprk-dropdown-choice');
choice.addEventListener('click', (e) => {
choice.addEventListener('click', e => {
e.preventDefault();
if (triggerText) {
triggerText.textContent = value;
Expand Down
60 changes: 46 additions & 14 deletions packages/spark-core/components/stepper.js
@@ -1,6 +1,8 @@
/* global document */
import getElements from '../utilities/getElements';
import { carousel } from './carousel';
import {
getActiveTabIndex,
handleTabKeydown,
resetTabs,
setActiveTab,
Expand All @@ -12,17 +14,34 @@ import {
* Binds click listener to each step.
* Binds keydown listener to each step.
* @param {NodeList} stepper - Collection of stepper container.
*/
const bindUIEvents = (stepper) => {
*/
const bindUIEvents = (stepper, carouselContainer) => {
let carouselInstance;
const steps = stepper.querySelectorAll('[data-sprk-stepper="step"]');
if (!steps) {return;}
if (!steps) {
return;
}
if (carouselContainer) {
carouselInstance = carousel(carouselContainer);
}
const stepPanels = stepper.querySelectorAll('[role="tabpanel"]');
const activeClass = 'sprk-c-Stepper__step--selected';
const hasSlideEffect = stepper.querySelector('[data-sprk-stepper="description"]');
const hasSlideEffect = stepper.querySelector(
'[data-sprk-stepper="description"]',
);
let sliderEl;

steps[0].classList.add('sprk-c-Stepper__step--first');
steps[(steps.length - 1)].classList.add('sprk-c-Stepper__step--last');
steps[steps.length - 1].classList.add('sprk-c-Stepper__step--last');

if (carouselContainer) {
carouselContainer.addEventListener('sprk.carousel.slide', e => {
e.preventDefault();
const { index } = e.detail;
resetTabs(steps, stepPanels, activeClass, sliderEl);
setActiveTab(steps[index], stepPanels[index], activeClass, sliderEl);
});
}

// If the stepper has stepper descriptions then build slider
if (hasSlideEffect) {
Expand All @@ -34,27 +53,40 @@ const bindUIEvents = (stepper) => {

steps.forEach((step, index) => {
const stepTrigger = step.querySelector('[role="tab"]');
if (!stepTrigger) { return; }
if (!stepTrigger) {
return;
}
if (hasSlideEffect) step.classList.add('sprk-c-Stepper__step--has-slider');

stepTrigger.addEventListener('click', (e) => {
stepTrigger.addEventListener('click', e => {
e.preventDefault();
resetTabs(steps, stepPanels, activeClass, sliderEl);
setActiveTab(step, stepPanels[index], activeClass, sliderEl);
if (carouselInstance) {
carouselInstance.slideTo(index);
}
});
});

stepper.addEventListener('keydown', (event) => {
console.log(handleTabKeydown);
stepper.addEventListener('keydown', event => {
handleTabKeydown(event, steps, stepPanels, activeClass, sliderEl);
if (carouselInstance) {
carouselInstance.slideTo(getActiveTabIndex(steps, activeClass));
}
});
};

const stepper = () => {
getElements('[data-sprk-stepper="container"]', bindUIEvents);
getElements('[data-sprk-stepper="container"]', item => {
let carouselContainer;
const partnerCarouselID = item.getAttribute('data-sprk-stepper-carousel');
if (partnerCarouselID) {
carouselContainer = document.querySelector(
`[data-sprk-carousel=${partnerCarouselID}]`,
);
}
bindUIEvents(item, carouselContainer);
});
};

export {
stepper,
bindUIEvents,
};
export { stepper, bindUIEvents };

0 comments on commit 03b44e5

Please sign in to comment.