Copy environment

Filter

<div class="filter js-filter">
    <ul class="filter__list">
        <li class="filter__list-item">

            <button class="filter-item js-filter-item is-selected" type="button" data-key="all">
                <span class="filter-item__inner">
                    <span class="filter-item__text">Kõik</span>
                </span>
            </button>
        </li>
        <li class="filter__list-item">

            <button class="filter-item js-filter-item" type="button" data-key="awaiting">
                <span class="filter-item__inner">
                    <span class="filter-item__bullet">
                        <span class="filter-item__count">2</span>
                    </span>
                    <span class="filter-item__text">Kinnituse ootel</span>
                </span>
            </button>
        </li>
        <li class="filter__list-item">

            <button class="filter-item js-filter-item" type="button" data-key="in-progress">
                <span class="filter-item__inner">
                    <span class="filter-item__bullet">
                        <span class="filter-item__count">3</span>
                    </span>
                    <span class="filter-item__text">Koostamisel</span>
                </span>
            </button>
        </li>
        <li class="filter__list-item">

            <button class="filter-item js-filter-item" type="button" data-key="confirmed">
                <span class="filter-item__inner">
                    <span class="filter-item__bullet">
                        <span class="filter-item__count">5</span>
                    </span>
                    <span class="filter-item__text">Kinnitatud</span>
                </span>
            </button>
        </li>
    </ul>
    <button class="filter__button filter__button--left is-hidden" type="button" aria-label="Scroll left">
        <svg class="icon  filter__button-icon" focusable="false">
            <use href="../../inc/svg/global.4609ec92109fc41e7ad4764ef897ea8e.svg#chevron-left"></use>
        </svg>
    </button>
    <button class="filter__button filter__button--right is-hidden" type="button" aria-label="Scroll right">
        <svg class="icon  filter__button-icon" focusable="false">
            <use href="../../inc/svg/global.4609ec92109fc41e7ad4764ef897ea8e.svg#chevron-right"></use>
        </svg>
    </button>
</div>
{% set BEM -%}
    filter js-filter
    {%- if modifier %} {{ modifier }}{% endif %}
    {%- if class %} {{ class }}{% endif %}
{% endset %}

<div class="{{ BEM }}">
    <ul class="filter__list">
        {% for item in data.items %}
            <li class="filter__list-item">
                {% include '@filter-item' with { data: item, class: 'js-filter-item', modifier: '' } %}
            </li>
        {% endfor %}
    </ul>
    <button class="filter__button filter__button--left is-hidden" type="button" aria-label="Scroll left">
        {% include '@icon' with { class: 'filter__button-icon', modifier: '', name: 'chevron-left' } %}
    </button>
    <button class="filter__button filter__button--right is-hidden" type="button" aria-label="Scroll right">
        {% include '@icon' with { class: 'filter__button-icon', modifier: '', name: 'chevron-right' } %}
    </button>
</div>
{
  "language": "en-US",
  "data": {
    "items": [
      {
        "key": "all",
        "isSelected": true,
        "text": "Kõik"
      },
      {
        "key": "awaiting",
        "text": "Kinnituse ootel",
        "count": 2
      },
      {
        "key": "in-progress",
        "text": "Koostamisel",
        "count": 3
      },
      {
        "key": "confirmed",
        "text": "Kinnitatud",
        "count": 5
      }
    ]
  }
}
  • Content:
    .filter {
        position: relative;
        padding: 12px $container-padding;
    
        @include bp(md-min) {
            padding: 0;
        }
    }
    
    .filter__list {
        display: flex;
        gap: 8px;
        overflow: auto hidden;
        -ms-overflow-style: scroll;
        scrollbar-width: none;
    
        &::-webkit-scrollbar {
            display: none;
        }
    }
    
    .filter__list-item {
        flex: 0 0 auto;
    }
    
    .filter__button {
        position: absolute;
        top: 50%;
        width: 48px;
        height: 48px;
        padding: 0;
        border: none;
        outline: none;
        -webkit-appearance: none;
        cursor: pointer;
        transform: translateY(-44%);
        transition: opacity $transition-duration-xs $transition-easing,
            visibility $transition-duration-xs $transition-easing;
    
        &.is-hidden {
            opacity: 0;
            visibility: hidden;
        }
    }
    
    .filter__button--left {
        left: 0;
        background: linear-gradient(270deg, rgba(248, 249, 250, 0) 0, #f8f9fa 76.86%); /* stylelint-disable-line plugin/no-unsupported-browser-features */
    }
    
    .filter__button--right {
        right: 0;
        background: linear-gradient(90deg, rgba(248, 249, 250, 0) 0, #f8f9fa 76.86%); /* stylelint-disable-line plugin/no-unsupported-browser-features */
    }
    
    .filter__button-icon {
        position: absolute;
        top: 50%;
        left: 50%;
        font-size: 24px;
        color: $L-text;
        transform: translate(-50%, -50%);
    }
    
  • URL: /components/raw/filter/filter.scss
  • Filesystem Path: src/patterns/components/filter/filter/filter.scss
  • Size: 1.3 KB
  • Content:
    import {debounce} from 'throttle-debounce';
    
    import Component from '../../component/component';
    
    import './filter.scss';
    
    export interface IFilterSettings {
        itemSelector?: string;
        listSelector?: string;
        navBtnLeftSelector?: string;
        navBtnRightSelector?: string;
        scrollSpeed?: number,
        scrollStep?: number;
        selectedClass?: string;
    }
    
    export const profileSettings: IFilterSettings = {
        itemSelector: '.js-filter-item',
        listSelector: '.filter__list',
        navBtnLeftSelector: '.filter__button--left',
        navBtnRightSelector: '.filter__button--right',
        scrollSpeed: 50,
        scrollStep: 10,
        selectedClass: 'is-selected',
    };
    
    export default class Filter extends Component {
        static initSelector: string = '.js-filter';
    
        readonly debounceUpdate: debounce<() => void>;
    
        items: JQuery<HTMLElement>;
        list: JQuery<HTMLElement>;
        navBtnLeft: JQuery<HTMLElement>;
        navBtnRight: JQuery<HTMLElement>;
        scrollAmount: number;
        settings: IFilterSettings;
    
        constructor(target: HTMLElement) {
            super(target);
    
            this.settings = profileSettings;
            this.scrollAmount = 0;
    
            this.items = this.element.find(this.settings.itemSelector);
            this.list = this.element.find(this.settings.listSelector);
    
            this.navBtnLeft = this.element.find(this.settings.navBtnLeftSelector);
            this.navBtnRight = this.element.find(this.settings.navBtnRightSelector);
    
            this.items.on('click', this.onItemClick.bind(this));
    
            this.navBtnLeft.on('click', this.scroll.bind(this, 'left'));
            this.navBtnRight.on('click', this.scroll.bind(this, 'right'));
    
            this.checkForOverflow();
    
            this.debounceUpdate = debounce(100, this.checkForOverflow.bind(this));
    
            $(window).on('resize', this.debounceUpdate);
    
            this.list.on('scroll', this.checkForOverflow.bind(this));
        }
    
        checkForOverflow(): void {
            const frameWidth: number = this.list.width(); // width of div showed on display
            const scrollElmtWidth: number = this.list[0].scrollWidth; // width of div including hidden part
            const maxDistance: number = Math.floor(scrollElmtWidth - frameWidth);
            const scrollLeft: number = this.list.scrollLeft();
    
            if (maxDistance <= 0) {
                // Hide both buttons if no scroll available
                this.navBtnRight.addClass('is-hidden');
                this.navBtnLeft.addClass('is-hidden');
            } else {
                // Show both buttons if there is scroll available
                this.navBtnRight.removeClass('is-hidden');
                this.navBtnLeft.removeClass('is-hidden');
    
                // Hide the appropriate button(s) if the scroll has reached an end
                if (scrollLeft >= maxDistance) {
                    this.navBtnRight.addClass('is-hidden');
                }
                if (scrollLeft <= 0) {
                    this.navBtnLeft.addClass('is-hidden');
                }
            }
        }
    
        onItemClick(event: JQuery.ClickEvent): void {
            const target: JQuery = $(event.currentTarget);
            const targetKey: string = target.data('key');
            const isSelected: boolean = target.hasClass(this.settings.selectedClass);
    
            if (!isSelected) {
                target.addClass(this.settings.selectedClass);
    
                this.items.each((_index: number, item: HTMLElement) => {
                    const $item: JQuery = $(item);
                    const itemKey: string = $item.data('key');
    
                    if (itemKey !== targetKey) {
                        $item.removeClass(this.settings.selectedClass);
                    }
                });
            }
        }
    
        scroll(direction: 'right' | 'left'): void {
            const step: number = this.settings.scrollStep;
            let scroll: number = 0;
    
            const slideTimer: number = window.setInterval(() => {
                if (direction === 'left') {
                    this.list.scrollLeft(this.list.scrollLeft() - step);
                    this.scrollAmount = this.list.scrollLeft();
                } else {
                    this.list.scrollLeft(this.list.scrollLeft() + step);
                    this.scrollAmount = this.list.scrollLeft();
                }
    
                this.checkForOverflow();
    
                const maxDistance: number = Math.floor(this.list[0].scrollWidth - this.list.width());
    
                if (this.list.scrollLeft() === 0) {
                    this.navBtnLeft.addClass('is-hidden');
                } else {
                    this.navBtnLeft.removeClass('is-hidden');
                }
                if (this.list.scrollLeft() >= maxDistance) {
                    this.navBtnRight.addClass('is-hidden');
                } else {
                    this.navBtnRight.removeClass('is-hidden');
                }
    
                scroll += step;
    
                if (scroll >= 100) {
                    window.clearInterval(slideTimer);
                }
            }, this.settings.scrollSpeed);
        }
    
    }
    
  • URL: /components/raw/filter/filter.ts
  • Filesystem Path: src/patterns/components/filter/filter/filter.ts
  • Size: 4.9 KB
  • Handle: @filter--default
  • Filesystem Path: src/patterns/components/filter/filter/filter.twig
  • References (2): @filter-item, @icon
  • Referenced by (1): @table-filter