<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
  }
}
  • Content:
    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;
    
  • URL: /components/raw/horizontal-scroller/HorizontalScroller.js
  • Filesystem Path: src/components/horizontal-scroller/HorizontalScroller.js
  • Size: 4 KB
  • Content:
    .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;
        }
    }
    
  • URL: /components/raw/horizontal-scroller/horizontal-scroller.scss
  • Filesystem Path: src/components/horizontal-scroller/horizontal-scroller.scss
  • Size: 2.5 KB
  • Content:
    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
        });
    }
    
  • URL: /components/raw/horizontal-scroller/index.js
  • Filesystem Path: src/components/horizontal-scroller/index.js
  • Size: 288 Bytes

No notes defined.