diff --git a/src/cg-selectTS.ts b/src/cg-selectTS.ts index 9f0bc99..837dd52 100644 --- a/src/cg-selectTS.ts +++ b/src/cg-selectTS.ts @@ -2,8 +2,14 @@ import { createNativeSelect, createNativeSelectOption, } from './components/create-element/create-elementTs'; -import { IDataItem } from './components/utils/urils.interface'; -import { createSelected, getFormatItem, nativeOptionOrdinary } from './components/utils/utilsTs'; +import { IDataItem, ITextSelect } from './components/utils/urils.interface'; +import { + createSelected, + getFormatItem, + getSelectText, + nativeOptionMultiple, + nativeOptionOrdinary, +} from './components/utils/utilsTs'; import { ICgSelect } from './interfaces/cg-select.interface'; import { IItems } from './interfaces/items.interface'; import './main.scss'; @@ -227,7 +233,7 @@ export class CGSelect implements ICgSelect { * @description Закрывает список * @method #close */ - private close() { + private close(): void { this.list?.classList.remove('open'); this.caret?.classList.remove('caret_rotate'); } @@ -238,7 +244,7 @@ export class CGSelect implements ICgSelect { * @description Закрывает список по клику вне элемента * @method closeSelectClick */ - private closeSelectClick() { + private closeSelectClick(): void { const dropdown = document.querySelector(`${this.options.selector}`); document.addEventListener('click', (e) => { @@ -275,9 +281,15 @@ export class CGSelect implements ICgSelect { const select: HTMLElement | null | undefined = this.element?.querySelector('.selected'); const nativeOption = this.element?.querySelectorAll('.nativeSelect__nativeOption'); + const placeholderTextSelect: ITextSelect = { + placeholder: placeholder, + selected: selected, + }; + const ulMultipul = document.createElement('ul'); if (multiselect) { + this.selectedItems = []; ulMultipul.classList.add('multiselect-tag'); select?.classList.add('overflow-hidden'); } @@ -285,6 +297,7 @@ export class CGSelect implements ICgSelect { options?.forEach((option: Element, index: number) => { option.addEventListener('click', (event) => { const item: IItems = this.itemsSelect[index]; + const checkIndex = this.indexes.indexOf(index); if (closeOnSelect == false || multiselect) { @@ -292,15 +305,50 @@ export class CGSelect implements ICgSelect { event.preventDefault(); } - select!.textContent = item.title; - this.selectedItems = item.title; + if (multiselect) { + option.classList.toggle('active'); - nativeOptionOrdinary(nativeOption, item.title); + const checkBox: HTMLInputElement | null = option.querySelector('input[type="checkbox"]'); - options.forEach((option) => { - option.classList.remove('active'); - }); - option.classList.add('active'); + if (checkBox) { + if (!(event.target instanceof HTMLInputElement)) { + checkBox.checked = !checkBox.checked; + } + + if (checkIndex == -1) { + this.indexes.push(index); + nativeOptionMultiple(nativeOption, item.title, true); + select!.textContent = ''; + + if (Array.isArray(this.selectedItems)) { + this.selectedItems.push(item.title); + select!.innerText = this.selectedItems.join(','); + } + } else { + this.indexes.splice(checkIndex, 1); + nativeOptionMultiple(nativeOption, item.title, false); + + if (Array.isArray(this.selectedItems)) { + this.selectedItems.splice(checkIndex, 1); + select!.innerText = this.selectedItems.join(','); + } + } + + if (Array.isArray(this.selectedItems) && !this.selectedItems.length) { + getSelectText(placeholderTextSelect, select); + } + } + } else { + select!.textContent = item.title; + this.selectedItems = item.title; + + nativeOptionOrdinary(nativeOption, item.title); + + options.forEach((option) => { + option.classList.remove('active'); + }); + option.classList.add('active'); + } // if (multiselect) { // this.selectedItems = []; @@ -357,17 +405,6 @@ export class CGSelect implements ICgSelect { // } // } // } - // } else { - // select!.textContent = item.title; - // this.selectedItems = item.title; - - // nativeOptionOrdinary(nativeOption, item.title); - - // options.forEach((option) => { - // option.classList.remove('active'); - // }); - // option.classList.add('active'); - // } }); }); } diff --git a/src/components/create-element/create-element.interface.ts b/src/components/create-element/create-element.interface.ts new file mode 100644 index 0000000..c3d42a9 --- /dev/null +++ b/src/components/create-element/create-element.interface.ts @@ -0,0 +1,8 @@ +import { ICgSelect } from '../../interfaces/cg-select.interface'; + +export interface IcreateBreadCrumb { + element: Element | null; + option: ICgSelect; + indexes: number[]; + selectedItems: string[]; +} diff --git a/src/components/create-element/create-elementTs.ts b/src/components/create-element/create-elementTs.ts index bbfccb0..88cc128 100644 --- a/src/components/create-element/create-elementTs.ts +++ b/src/components/create-element/create-elementTs.ts @@ -1,3 +1,5 @@ +import { IcreateBreadCrumb } from './create-element.interface'; + /** * Метод который создает нативный селект * @returns {HTMLSelectElement} Возвращает созданный нативный селект @@ -29,12 +31,17 @@ export function createNativeSelectOption(): HTMLOptionElement { * @param {string} id уникальное id выбранного элемента * @returns {HTMLElement} возвращает сформированный HTMLElement chips item */ -export function createBreadcrumb(data: any, title: string, index: number, id: string) { +export function createBreadcrumb( + data: IcreateBreadCrumb, + title: string, + index: number, + id: string, +) { const { element, option, indexes, selectedItems } = data; const { placeholder, styles } = option; - const selected = element.querySelector('.selected'); - const nativeOption = element.querySelectorAll('.nativeSelect__nativeOption'); + const selected = element!.querySelector('.selected'); + const nativeOption = element!.querySelectorAll('.nativeSelect__nativeOption'); const liChip = document.createElement('li'); const textNode = document.createTextNode(title); @@ -55,7 +62,7 @@ export function createBreadcrumb(data: any, title: string, index: number, id: st liChip.appendChild(svgIcon); if (styles) { - const { chips } = styles; + // const { chips } = styles; // customStylesFormat(chips, liChip); } @@ -80,7 +87,7 @@ export function createBreadcrumb(data: any, title: string, index: number, id: st // checkBox.parentElement.classList.remove('active'); if (!selectedItems.length) { - selected.innerText = placeholder; + //selected?.textContent = placeholder; } // liChip.parentElement.removeChild(liChip); diff --git a/src/components/utils/urils.interface.ts b/src/components/utils/urils.interface.ts index b21d691..f0cfad8 100644 --- a/src/components/utils/urils.interface.ts +++ b/src/components/utils/urils.interface.ts @@ -1,7 +1,12 @@ -import { IItems } from "../../interfaces/items.interface"; +import { IItems } from '../../interfaces/items.interface'; -export interface IDataItem{ - category?: string; - categoryItems?: string; - ItemValue: string | IItems | number; -} \ No newline at end of file +export interface IDataItem { + category?: string; + categoryItems?: string; + ItemValue: string | IItems | number; +} + +export interface ITextSelect { + placeholder?: string; + selected?: string; +} diff --git a/src/components/utils/utilsTs.ts b/src/components/utils/utilsTs.ts index 0da297f..814e9e9 100644 --- a/src/components/utils/utilsTs.ts +++ b/src/components/utils/utilsTs.ts @@ -1,5 +1,6 @@ +import { ICgSelect } from '../../interfaces/cg-select.interface'; import { IItems } from '../../interfaces/items.interface'; -import { IDataItem } from './urils.interface'; +import { IDataItem, ITextSelect } from './urils.interface'; /** * Преобразование каждого елемента полученного из поля Items; @@ -25,6 +26,28 @@ export function getFormatItem(dataItem: any, index: number): IItems { } } +/** + * Вставка изначального текста селекта(до выбора) + * @param {ITextSelect} data объект в котором находяться title селекта + * @param {HTMLElement | null | undefined} select елемент селекта, куда будет вставляться title + * @returns {HTMLElement} возвращает сформированный елемент селекта + */ +export function getSelectText( + data: ITextSelect, + select: HTMLElement | null | undefined, +): HTMLElement { + const { placeholder, selected } = data; + + if (placeholder) { + select!.innerText = placeholder; + } else if (selected) { + select!.innerText = selected; + } else { + select!.innerText = 'Select...'; + } + return select!; +} + /** * Проверка содержит ли item указанные свойства, * @param {object} item проверяемый на определенную структуру элемент @@ -92,3 +115,29 @@ export function nativeOptionOrdinary(element: NodeListOf | undefined, i } }); } + +/** + * Поведение нативного(Multiple) селекта при выборе в кастомном + * @param {NodeListOf | undefined} element NodeList нативного селекта + * @param {string} item выбранный элемент в кастомном селекте + * @param {boolean} condition специальный флаг при котором добавляются/убераются атрибуты у нативного селекта + */ +export function nativeOptionMultiple( + element: NodeListOf | undefined, + item: string, + condition: boolean, +) { + element!.forEach((option) => { + if (condition == true) { + if (option.textContent === item) { + option.setAttribute('selected', 'selected'); + } + } else if (condition == false) { + if (option.textContent === item) { + option.removeAttribute('selected'); + } + } else { + return; + } + }); +}