<div class="
horizontal-scroller
" data-show-scroll-icon="">
<div class="horizontal-scroller__scroller">
Hello
</div>
</div>
<div
class="
horizontal-scroller
{{#if indicator}}
horizontal-scroller--{{indicator}}-indicator
{{/if}}
{{#if showScrollIcon}}
horizontal-scroller--show-icon
{{/if}} {{ scrollerAdditionalClasses }}"
data-show-scroll-icon="{{showScrollIcon}}"
>
{{#if withNavigation}}
<button class="horizontal-scroller__navigate horizontal-scroller__navigate--hidden horizontal-scroller__navigate--left">
{{> @icon id="chevron-left" additionalClasses="horizontal-scroller__navigate-icon"}}
</button>
{{/if}}
<div class="horizontal-scroller__scroller">
{{#> @partial-block}}
Hello
{{/@partial-block}}
</div>
{{#if withNavigation}}
<button class="horizontal-scroller__navigate horizontal-scroller__navigate--hidden horizontal-scroller__navigate--right">
{{> @icon id="chevron-right" additionalClasses="horizontal-scroller__navigate-icon"}}
</button>
{{/if}}
</div>
{
"attributes": {
"aria-controls": "content-container",
"data-show-scroll-icon": true
}
}
import throttle from 'lodash/throttle';
import { gsap } from 'gsap';
class HorizontalScroller {
constructor(el, opts) {
this.el = el;
this.opts = {
showScrollIcon: false,
...opts
};
this.scroller = this.el.querySelector('.horizontal-scroller__scroller');
this.contentContainer = this.scroller.querySelector(`.horizontal-scroller__scroller > *`);
this.navigateLeft = this.el.querySelector('.horizontal-scroller__navigate--left');
this.navigateRight = this.el.querySelector('.horizontal-scroller__navigate--right');
this.toggleIcon = this.toggleIcon.bind(this);
this.handleScroll = this.handleScroll.bind(this);
this.handleResize = this.handleResize.bind(this);
this.checkOverflow = this.checkOverflow.bind(this);
this.navigate = this.navigate.bind(this);
this.scrollPosition = 0;
this.contentWidth = 0;
this.hasScroll = false;
this.scrollPositionStart = true;
this.scrollPositionEnd = false;
this.hasNavigation = typeof this.navigateLeft !== 'undefined' && this.navigateLeft !== null &&
typeof this.navigateRight !== 'undefined' && this.navigateRight !== null;
this.init();
}
init() {
this.checkOverflow();
this.checkScrollPosition();
window.addEventListener('resize', throttle(this.handleResize, 100));
this.scroller.addEventListener('scroll', throttle(this.handleScroll, 100));
if (this.hasNavigation) {
this.navigateLeft.addEventListener('click', () => this.navigate('left'));
this.navigateRight.addEventListener('click', () => this.navigate('right'));
}
this.showHideElementsBasedOnScroll();
}
navigate(direction) {
let targetScrollValue = this.scroller.scrollLeft + this.contentContainer.scrollWidth;
gsap.to(this.scroller, {
duration: .3,
scrollTo: {
x: direction === 'right' ? targetScrollValue : -targetScrollValue
}
});
}
checkOverflow() {
this.isOverflow = this.el.offsetWidth < this.contentContainer.scrollWidth;
this.checkScrollPosition();
if (this.opts.showScrollIcon) {
this.toggleIcon(this.isOverflow);
}
}
handleScroll() {
this.checkScrollPosition();
if (this.opts.showScrollIcon) {
this.toggleIcon(false);
}
this.showHideElementsBasedOnScroll();
}
handleResize() {
this.checkScrollPosition();
this.checkOverflow();
this.showHideElementsBasedOnScroll();
}
showHideElementsBasedOnScroll() {
// show/hide navigation buttons
if (this.hasNavigation) {
this.navigateLeft.classList.toggle(
'horizontal-scroller__navigate--hidden',
this.scrollPositionStart
);
this.navigateRight.classList.toggle(
'horizontal-scroller__navigate--hidden',
this.scrollPositionEnd
);
}
// show/hide overflow indidators
this.el.classList.toggle(
'horizontal-scroller--overflow-right',
!this.scrollPositionEnd
);
this.el.classList.toggle(
'horizontal-scroller--overflow-left',
!this.scrollPositionStart
);
}
checkScrollPosition() {
this.scrollPosition = this.scroller.scrollLeft + this.scroller.getBoundingClientRect().width;
this.contentWidth = this.contentContainer.scrollWidth;
this.scrollPositionStart = this.scroller.scrollLeft === 0;
this.scrollPositionEnd = Math.abs(this.scrollPosition - this.contentWidth) < 1;
this.hasScroll = this.scroller.getBoundingClientRect().width < this.contentWidth;
}
toggleIcon(visible) {
this.el.classList.toggle('horizontal-scroller--show-icon', visible);
}
}
export default HorizontalScroller;
.horizontal-scroller {
position: relative;
overflow-x: hidden;
&.panel-full-width {
margin: 0 -32px;
@include breakpoint-down($m) {
margin: 0 -16px;
}
}
&.no-decore-shadows {
&:before,
&:after {
display: none !important;
}
}
&:before,
&:after {
content: '';
display: none;
width: 60px;
height: 100%;
position: absolute;
top: 0;
bottom: 0;
left: -60px;
box-shadow: #{size(2)} 0px #{size(2)} -#{size(2)} rgba($color-black, .4);
z-index: 1;
pointer-events: none;
}
&:after {
left: auto;
right: -60px;
box-shadow: -#{size(2)} 0px #{size(2)} -#{size(2)} rgba($color-black, .4);
}
&--gradient-indicator {
&:before, &:after {
box-shadow: none;
}
&:before {
left: 0;
background: linear-gradient(90deg, #FFFFFF 0%, rgba(255,255,255,0) 100%);
}
&:after {
right: 0;
background: linear-gradient(-90deg, #FFFFFF 0%, rgba(255,255,255,0) 100%);
}
}
&.horizontal-scroller--overflow-left:before, &.horizontal-scroller--overflow-right:after {
display: block;
}
}
.horizontal-scroller__navigate {
position: absolute;
top: 0;
background: white;
width: size(2);
height: 100%;
z-index: 2;
cursor: pointer;
&--hidden {
display: none;
}
&--left {
left: 0;
background: '../../assets';
}
&--right {
right: 0;
}
}
.horizontal-scroller__navigate-icon {
width: size(2);
height: size(2);
}
.horizontal-scroller__scroller {
position: relative;
overflow: hidden;
overflow-x: auto;
-webkit-overflow-scrolling: touch;
&:before,
&:after {
content: ' ';
display: none;
position: absolute;
top: 50%;
left: 50%;
transform: translateX(-50%) translateY(-50%);
.horizontal-scroller--show-icon & {
display: block;
}
}
&:before {
width: size(1 * 9);
height: size(1 * 9);
border-radius: 100%;
background-color: rgba($color-black, 0.5);
}
&:after {
width: size(6);
height: size(6);
background-image: url(./img/swipe.svg);
background-repeat: no-repeat;
background-position: center;
}
}
import HorizontalScroller from './HorizontalScroller';
const els = document.querySelectorAll('.horizontal-scroller');
for (let el of els) {
const showScrollIcon = el.getAttribute('data-show-scroll-icon') === 'true';
new HorizontalScroller(el, {
showScrollIcon
});
}
No notes defined.