From ce3b928635cf293e992a1d4543ac835215f5c1b7 Mon Sep 17 00:00:00 2001 From: MaxOvs Date: Thu, 5 Jan 2023 18:21:10 +0300 Subject: [PATCH 01/21] Start of the trasition to TS --- CHANGELOG.md | 5 + README.md | 2 +- example/index.html | 1 + example/index.js | 48 +-- example/indexTs.ts | 18 + package-lock.json | 562 +++++++++++++++++++++++++- package.json | 5 +- src/cg-select.js | 2 + src/cg-selectTS.ts | 65 +++ src/components/utilsTs.ts | 48 +++ src/interfaces/cg-select.interface.ts | 20 + src/interfaces/items.interface.ts | 5 + 12 files changed, 733 insertions(+), 48 deletions(-) create mode 100644 example/indexTs.ts create mode 100644 src/cg-selectTS.ts create mode 100644 src/components/utilsTs.ts create mode 100644 src/interfaces/cg-select.interface.ts create mode 100644 src/interfaces/items.interface.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 6796be1..f179c9c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,3 +20,8 @@ - Исправленны выявленные баги. - Исправленно отображение страницы с примером на мобильных устройствах. - Обновленна документация! + +### 00.00.2023 - обновление 0.2.1 + +- Весь селект переписан на ts. +- Документация и реадми переписаны на Английский. diff --git a/README.md b/README.md index 72986a5..0fcabf1 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # CG-SELECT -## version ~ 0.1.171 +## version ~ 0.2.1 Этот компонент позволяет создать кастомный селект. Он предлагает более гибкую настройку и использование селекта. Доступна кастомизация, мультивыбор и живой поиск по елементам. diff --git a/example/index.html b/example/index.html index fc867c5..4a483c4 100644 --- a/example/index.html +++ b/example/index.html @@ -356,4 +356,5 @@ + diff --git a/example/index.js b/example/index.js index 97649f8..a440293 100644 --- a/example/index.js +++ b/example/index.js @@ -2,30 +2,30 @@ import DropDown from '../index'; import './example'; // ------------------------------Обычный селект-------------------- -const dropdown = new DropDown({ - selector: '.cg-dropdown_one', - placeholder: 'Выберите авто', - lable: 'EXAMPLE', - items: [ - 'BMW', - { - id: '213sade', - title: 'Opel', - value: 1, - }, - 'Mersedes', - 'MAN', - 'Ferari', - ], - styles: { - head: { - width: '830px', - }, - list: { - width: '824px', - }, - }, -}); +// const dropdown = new DropDown({ +// selector: '.cg-dropdown_one', +// placeholder: 'Выберите авто', +// lable: 'EXAMPLE', +// items: [ +// 'BMW', +// { +// id: '213sade', +// title: 'Opel', +// value: 1, +// }, +// 'Mersedes', +// 'MAN', +// 'Ferari', +// ], +// styles: { +// head: { +// width: '830px', +// }, +// list: { +// width: '824px', +// }, +// }, +// }); // ------------------------------NativeSelect----------------------- const dropdownNativeSelect = new DropDown({ diff --git a/example/indexTs.ts b/example/indexTs.ts new file mode 100644 index 0000000..aebfdd1 --- /dev/null +++ b/example/indexTs.ts @@ -0,0 +1,18 @@ +import { SGSelect } from "../src/cg-selectTS"; + +const dropdn = new SGSelect({ + selector: '.cg-dropdown_one', + placeholder: 'Выберите авто', + // lable: 'EXAMPLE', + items: [ + 'BMW', + { + id: '213sade', + title: 'Opel', + value: 'ds', + }, + 'Mersedes', + 'MAN', + 'Ferari', + ] +}) \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 75f0f49..65d6fdc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,8 @@ "license": "ISC", "dependencies": { "@parcel/optimizer-css": "^2.8.0", - "gh-pages": "^4.0.0" + "gh-pages": "^4.0.0", + "typescript": "^4.9.4" }, "devDependencies": { "@parcel/transformer-sass": "^2.7.0", @@ -799,6 +800,304 @@ "url": "https://opencollective.com/parcel" } }, + "node_modules/@parcel/optimizer-css/node_modules/@parcel/core": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/@parcel/core/-/core-2.8.2.tgz", + "integrity": "sha512-ZGuq6p+Lzx6fgufaVsuOBwgpU3hgskTvIDIMdIDi9gOZyhGPK7U2srXdX+VYUL5ZSGbX04/P6QlB9FMAXK+nEg==", + "peer": true, + "dependencies": { + "@mischnic/json-sourcemap": "^0.1.0", + "@parcel/cache": "2.8.2", + "@parcel/diagnostic": "2.8.2", + "@parcel/events": "2.8.2", + "@parcel/fs": "2.8.2", + "@parcel/graph": "2.8.2", + "@parcel/hash": "2.8.2", + "@parcel/logger": "2.8.2", + "@parcel/package-manager": "2.8.2", + "@parcel/plugin": "2.8.2", + "@parcel/source-map": "^2.1.1", + "@parcel/types": "2.8.2", + "@parcel/utils": "2.8.2", + "@parcel/workers": "2.8.2", + "abortcontroller-polyfill": "^1.1.9", + "base-x": "^3.0.8", + "browserslist": "^4.6.6", + "clone": "^2.1.1", + "dotenv": "^7.0.0", + "dotenv-expand": "^5.1.0", + "json5": "^2.2.0", + "msgpackr": "^1.5.4", + "nullthrows": "^1.1.1", + "semver": "^5.7.1" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/optimizer-css/node_modules/@parcel/core/node_modules/@parcel/cache": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/@parcel/cache/-/cache-2.8.2.tgz", + "integrity": "sha512-kiyoOgh1RXp5qp+wlb8Pi/Z7o9D82Oj5RlHnKSAauyR7jgnI8Vq8JTeBmlLqrf+kHxcDcp2p86hidSeANhlQNg==", + "peer": true, + "dependencies": { + "@parcel/fs": "2.8.2", + "@parcel/logger": "2.8.2", + "@parcel/utils": "2.8.2", + "lmdb": "2.5.2" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "peerDependencies": { + "@parcel/core": "^2.8.2" + } + }, + "node_modules/@parcel/optimizer-css/node_modules/@parcel/core/node_modules/@parcel/codeframe": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/@parcel/codeframe/-/codeframe-2.8.2.tgz", + "integrity": "sha512-U2GT9gq1Zs3Gr83j8JIs10bLbGOHFl57Y8D57nrdR05F4iilV/UR6K7jkhdoiFc9WiHh3ewvrko5+pSdAVFPgQ==", + "peer": true, + "dependencies": { + "chalk": "^4.1.0" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/optimizer-css/node_modules/@parcel/core/node_modules/@parcel/diagnostic": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/@parcel/diagnostic/-/diagnostic-2.8.2.tgz", + "integrity": "sha512-tGSMwM2rSYLjJW0fCd9gb3tNjfCX/83PZ10/5u2E33UZVkk8OIHsQmsrtq2H2g4oQL3rFxkfEx6nGPDGHwlx7A==", + "peer": true, + "dependencies": { + "@mischnic/json-sourcemap": "^0.1.0", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/optimizer-css/node_modules/@parcel/core/node_modules/@parcel/events": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/@parcel/events/-/events-2.8.2.tgz", + "integrity": "sha512-o5etrsKm16y8iRPnjtEBNy4lD0WAigD66yt/RZl9Rx0vPVDly/63Rr9+BrXWVW7bJ7x0S0VVpWW4j3f/qZOsXg==", + "peer": true, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/optimizer-css/node_modules/@parcel/core/node_modules/@parcel/fs": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/@parcel/fs/-/fs-2.8.2.tgz", + "integrity": "sha512-aN8znbMndSqn1xwZEmMblzqmJsxcExv2jKLl/a9RUHAP7LaPYcPZIykDL3YwGCiKTCzjmRpXnNoyosjFFeBaHA==", + "peer": true, + "dependencies": { + "@parcel/fs-search": "2.8.2", + "@parcel/types": "2.8.2", + "@parcel/utils": "2.8.2", + "@parcel/watcher": "^2.0.7", + "@parcel/workers": "2.8.2" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "peerDependencies": { + "@parcel/core": "^2.8.2" + } + }, + "node_modules/@parcel/optimizer-css/node_modules/@parcel/core/node_modules/@parcel/fs-search": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/@parcel/fs-search/-/fs-search-2.8.2.tgz", + "integrity": "sha512-ovQnupRm/MoE/tbgH0Ivknk0QYenXAewjcog+T5umDmUlTmnIRZjURrgDf5Xtw8T/CD5Xv+HmIXpJ9Ez/LzJpw==", + "peer": true, + "dependencies": { + "detect-libc": "^1.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/optimizer-css/node_modules/@parcel/core/node_modules/@parcel/hash": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/@parcel/hash/-/hash-2.8.2.tgz", + "integrity": "sha512-NBnP8Hu0xvAqAfZXRaMM66i8nJyxpKS86BbhwkbgTGbwO1OY87GERliHeREJfcER0E0ZzwNow7MNR8ZDm6IvJQ==", + "peer": true, + "dependencies": { + "detect-libc": "^1.0.3", + "xxhash-wasm": "^0.4.2" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/optimizer-css/node_modules/@parcel/core/node_modules/@parcel/logger": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/@parcel/logger/-/logger-2.8.2.tgz", + "integrity": "sha512-zlhK6QHxfFJMlVJxxcCw0xxBDrYPFPOhMxSD6p6b0z9Yct1l3NdpmfabgjKX8wnZmHokFsil6daleM+M80n2Ew==", + "peer": true, + "dependencies": { + "@parcel/diagnostic": "2.8.2", + "@parcel/events": "2.8.2" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/optimizer-css/node_modules/@parcel/core/node_modules/@parcel/markdown-ansi": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/@parcel/markdown-ansi/-/markdown-ansi-2.8.2.tgz", + "integrity": "sha512-5y29TXgRgG0ybuXaDsDk4Aofg/nDUeAAyVl9/toYCDDhxpQV4yZt8WNPu4PaNYKGLuNgXwsmz+ryZQHGmfbAIQ==", + "peer": true, + "dependencies": { + "chalk": "^4.1.0" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/optimizer-css/node_modules/@parcel/core/node_modules/@parcel/package-manager": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/@parcel/package-manager/-/package-manager-2.8.2.tgz", + "integrity": "sha512-hx4Imi0yhsSS0aNZkEANPYNNKqBuR63EUNWSxMyHh4ZOvbHoOXnMn1ySGdx6v0oi9HvKymNsLMQ1T5CuI4l4Bw==", + "peer": true, + "dependencies": { + "@parcel/diagnostic": "2.8.2", + "@parcel/fs": "2.8.2", + "@parcel/logger": "2.8.2", + "@parcel/types": "2.8.2", + "@parcel/utils": "2.8.2", + "@parcel/workers": "2.8.2", + "semver": "^5.7.1" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "peerDependencies": { + "@parcel/core": "^2.8.2" + } + }, + "node_modules/@parcel/optimizer-css/node_modules/@parcel/core/node_modules/@parcel/plugin": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/@parcel/plugin/-/plugin-2.8.2.tgz", + "integrity": "sha512-YG7TWfKsoNm72jbz3b3TLec0qJHVkuAWSzGzowdIhX37cP1kRfp6BU2VcH+qYPP/KYJLzhcZa9n3by147mGcxw==", + "peer": true, + "dependencies": { + "@parcel/types": "2.8.2" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/optimizer-css/node_modules/@parcel/core/node_modules/@parcel/types": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/@parcel/types/-/types-2.8.2.tgz", + "integrity": "sha512-HAYhokWxM10raIhqaYj9VR9eAvJ+xP2sNfQ1IcQybHpq3qblcBe/4jDeuUpwIyKeQ4gorp7xY+q8KDoR20j43w==", + "peer": true, + "dependencies": { + "@parcel/cache": "2.8.2", + "@parcel/diagnostic": "2.8.2", + "@parcel/fs": "2.8.2", + "@parcel/package-manager": "2.8.2", + "@parcel/source-map": "^2.1.1", + "@parcel/workers": "2.8.2", + "utility-types": "^3.10.0" + } + }, + "node_modules/@parcel/optimizer-css/node_modules/@parcel/core/node_modules/@parcel/utils": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/@parcel/utils/-/utils-2.8.2.tgz", + "integrity": "sha512-Ufax7wZxC9FNsUpR0EU7Z22LEY/q9jjsDTwswctCdfpWb7TE/NudOfM9myycfRvwBVEYN50lPbkt1QltEVnXQQ==", + "peer": true, + "dependencies": { + "@parcel/codeframe": "2.8.2", + "@parcel/diagnostic": "2.8.2", + "@parcel/hash": "2.8.2", + "@parcel/logger": "2.8.2", + "@parcel/markdown-ansi": "2.8.2", + "@parcel/source-map": "^2.1.1", + "chalk": "^4.1.0" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/optimizer-css/node_modules/@parcel/core/node_modules/@parcel/workers": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/@parcel/workers/-/workers-2.8.2.tgz", + "integrity": "sha512-Eg6CofIrJSNBa2fjXwvnzVLPKwR/6fkfQTFAm3Jl+4JYLVknBtTSFzQNp/Fa+HUEG889H9ucTk2CBi/fVPBAFw==", + "peer": true, + "dependencies": { + "@parcel/diagnostic": "2.8.2", + "@parcel/logger": "2.8.2", + "@parcel/types": "2.8.2", + "@parcel/utils": "2.8.2", + "chrome-trace-event": "^1.0.2", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "peerDependencies": { + "@parcel/core": "^2.8.2" + } + }, "node_modules/@parcel/optimizer-css/node_modules/@parcel/diagnostic": { "version": "2.8.0", "resolved": "https://registry.npmjs.org/@parcel/diagnostic/-/diagnostic-2.8.0.tgz", @@ -864,6 +1163,22 @@ "url": "https://opencollective.com/parcel" } }, + "node_modules/@parcel/optimizer-css/node_modules/@parcel/graph": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/@parcel/graph/-/graph-2.8.2.tgz", + "integrity": "sha512-SLEvBQBgfkXgU4EBu30+CNanpuKjcNuEv/x8SwobCF0i3Rk+QKbe7T36bNR7727mao++2Ha69q93Dd9dTPw0kQ==", + "peer": true, + "dependencies": { + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, "node_modules/@parcel/optimizer-css/node_modules/@parcel/hash": { "version": "2.8.0", "resolved": "https://registry.npmjs.org/@parcel/hash/-/hash-2.8.0.tgz", @@ -1769,8 +2084,7 @@ "node_modules/abortcontroller-polyfill": { "version": "1.7.3", "resolved": "https://registry.npmjs.org/abortcontroller-polyfill/-/abortcontroller-polyfill-1.7.3.tgz", - "integrity": "sha512-zetDJxd89y3X99Kvo4qFx8GKlt6GsvN3UcRZHwU6iFA/0KiOmhkTVhe8oRoTBiTVPZu09x3vCra47+w8Yz1+2Q==", - "dev": true + "integrity": "sha512-zetDJxd89y3X99Kvo4qFx8GKlt6GsvN3UcRZHwU6iFA/0KiOmhkTVhe8oRoTBiTVPZu09x3vCra47+w8Yz1+2Q==" }, "node_modules/acorn": { "version": "8.8.0", @@ -1853,7 +2167,6 @@ "version": "3.0.9", "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.9.tgz", "integrity": "sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==", - "dev": true, "dependencies": { "safe-buffer": "^5.0.1" } @@ -2023,7 +2336,6 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==", - "dev": true, "engines": { "node": ">=0.8" } @@ -2211,7 +2523,6 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-7.0.0.tgz", "integrity": "sha512-M3NhsLbV1i6HuGzBUH8vXrtxOk+tWmzWKDMbAVSUp3Zsjm7ywFeuwrUXhmhQyRK1q5B5GGy7hcXPbj3bnfZg2g==", - "dev": true, "engines": { "node": ">=6" } @@ -2219,8 +2530,7 @@ "node_modules/dotenv-expand": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz", - "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==", - "dev": true + "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==" }, "node_modules/electron-to-chromium": { "version": "1.4.251", @@ -3461,7 +3771,6 @@ "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, "funding": [ { "type": "github", @@ -3675,6 +3984,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/typescript": { + "version": "4.9.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz", + "integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, "node_modules/uc.micro": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", @@ -4275,6 +4596,196 @@ "chalk": "^4.1.0" } }, + "@parcel/core": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/@parcel/core/-/core-2.8.2.tgz", + "integrity": "sha512-ZGuq6p+Lzx6fgufaVsuOBwgpU3hgskTvIDIMdIDi9gOZyhGPK7U2srXdX+VYUL5ZSGbX04/P6QlB9FMAXK+nEg==", + "peer": true, + "requires": { + "@mischnic/json-sourcemap": "^0.1.0", + "@parcel/cache": "2.8.2", + "@parcel/diagnostic": "2.8.2", + "@parcel/events": "2.8.2", + "@parcel/fs": "2.8.2", + "@parcel/graph": "2.8.2", + "@parcel/hash": "2.8.2", + "@parcel/logger": "2.8.2", + "@parcel/package-manager": "2.8.2", + "@parcel/plugin": "2.8.2", + "@parcel/source-map": "^2.1.1", + "@parcel/types": "2.8.2", + "@parcel/utils": "2.8.2", + "@parcel/workers": "2.8.2", + "abortcontroller-polyfill": "^1.1.9", + "base-x": "^3.0.8", + "browserslist": "^4.6.6", + "clone": "^2.1.1", + "dotenv": "^7.0.0", + "dotenv-expand": "^5.1.0", + "json5": "^2.2.0", + "msgpackr": "^1.5.4", + "nullthrows": "^1.1.1", + "semver": "^5.7.1" + }, + "dependencies": { + "@parcel/cache": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/@parcel/cache/-/cache-2.8.2.tgz", + "integrity": "sha512-kiyoOgh1RXp5qp+wlb8Pi/Z7o9D82Oj5RlHnKSAauyR7jgnI8Vq8JTeBmlLqrf+kHxcDcp2p86hidSeANhlQNg==", + "peer": true, + "requires": { + "@parcel/fs": "2.8.2", + "@parcel/logger": "2.8.2", + "@parcel/utils": "2.8.2", + "lmdb": "2.5.2" + } + }, + "@parcel/codeframe": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/@parcel/codeframe/-/codeframe-2.8.2.tgz", + "integrity": "sha512-U2GT9gq1Zs3Gr83j8JIs10bLbGOHFl57Y8D57nrdR05F4iilV/UR6K7jkhdoiFc9WiHh3ewvrko5+pSdAVFPgQ==", + "peer": true, + "requires": { + "chalk": "^4.1.0" + } + }, + "@parcel/diagnostic": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/@parcel/diagnostic/-/diagnostic-2.8.2.tgz", + "integrity": "sha512-tGSMwM2rSYLjJW0fCd9gb3tNjfCX/83PZ10/5u2E33UZVkk8OIHsQmsrtq2H2g4oQL3rFxkfEx6nGPDGHwlx7A==", + "peer": true, + "requires": { + "@mischnic/json-sourcemap": "^0.1.0", + "nullthrows": "^1.1.1" + } + }, + "@parcel/events": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/@parcel/events/-/events-2.8.2.tgz", + "integrity": "sha512-o5etrsKm16y8iRPnjtEBNy4lD0WAigD66yt/RZl9Rx0vPVDly/63Rr9+BrXWVW7bJ7x0S0VVpWW4j3f/qZOsXg==", + "peer": true + }, + "@parcel/fs": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/@parcel/fs/-/fs-2.8.2.tgz", + "integrity": "sha512-aN8znbMndSqn1xwZEmMblzqmJsxcExv2jKLl/a9RUHAP7LaPYcPZIykDL3YwGCiKTCzjmRpXnNoyosjFFeBaHA==", + "peer": true, + "requires": { + "@parcel/fs-search": "2.8.2", + "@parcel/types": "2.8.2", + "@parcel/utils": "2.8.2", + "@parcel/watcher": "^2.0.7", + "@parcel/workers": "2.8.2" + } + }, + "@parcel/fs-search": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/@parcel/fs-search/-/fs-search-2.8.2.tgz", + "integrity": "sha512-ovQnupRm/MoE/tbgH0Ivknk0QYenXAewjcog+T5umDmUlTmnIRZjURrgDf5Xtw8T/CD5Xv+HmIXpJ9Ez/LzJpw==", + "peer": true, + "requires": { + "detect-libc": "^1.0.3" + } + }, + "@parcel/hash": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/@parcel/hash/-/hash-2.8.2.tgz", + "integrity": "sha512-NBnP8Hu0xvAqAfZXRaMM66i8nJyxpKS86BbhwkbgTGbwO1OY87GERliHeREJfcER0E0ZzwNow7MNR8ZDm6IvJQ==", + "peer": true, + "requires": { + "detect-libc": "^1.0.3", + "xxhash-wasm": "^0.4.2" + } + }, + "@parcel/logger": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/@parcel/logger/-/logger-2.8.2.tgz", + "integrity": "sha512-zlhK6QHxfFJMlVJxxcCw0xxBDrYPFPOhMxSD6p6b0z9Yct1l3NdpmfabgjKX8wnZmHokFsil6daleM+M80n2Ew==", + "peer": true, + "requires": { + "@parcel/diagnostic": "2.8.2", + "@parcel/events": "2.8.2" + } + }, + "@parcel/markdown-ansi": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/@parcel/markdown-ansi/-/markdown-ansi-2.8.2.tgz", + "integrity": "sha512-5y29TXgRgG0ybuXaDsDk4Aofg/nDUeAAyVl9/toYCDDhxpQV4yZt8WNPu4PaNYKGLuNgXwsmz+ryZQHGmfbAIQ==", + "peer": true, + "requires": { + "chalk": "^4.1.0" + } + }, + "@parcel/package-manager": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/@parcel/package-manager/-/package-manager-2.8.2.tgz", + "integrity": "sha512-hx4Imi0yhsSS0aNZkEANPYNNKqBuR63EUNWSxMyHh4ZOvbHoOXnMn1ySGdx6v0oi9HvKymNsLMQ1T5CuI4l4Bw==", + "peer": true, + "requires": { + "@parcel/diagnostic": "2.8.2", + "@parcel/fs": "2.8.2", + "@parcel/logger": "2.8.2", + "@parcel/types": "2.8.2", + "@parcel/utils": "2.8.2", + "@parcel/workers": "2.8.2", + "semver": "^5.7.1" + } + }, + "@parcel/plugin": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/@parcel/plugin/-/plugin-2.8.2.tgz", + "integrity": "sha512-YG7TWfKsoNm72jbz3b3TLec0qJHVkuAWSzGzowdIhX37cP1kRfp6BU2VcH+qYPP/KYJLzhcZa9n3by147mGcxw==", + "peer": true, + "requires": { + "@parcel/types": "2.8.2" + } + }, + "@parcel/types": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/@parcel/types/-/types-2.8.2.tgz", + "integrity": "sha512-HAYhokWxM10raIhqaYj9VR9eAvJ+xP2sNfQ1IcQybHpq3qblcBe/4jDeuUpwIyKeQ4gorp7xY+q8KDoR20j43w==", + "peer": true, + "requires": { + "@parcel/cache": "2.8.2", + "@parcel/diagnostic": "2.8.2", + "@parcel/fs": "2.8.2", + "@parcel/package-manager": "2.8.2", + "@parcel/source-map": "^2.1.1", + "@parcel/workers": "2.8.2", + "utility-types": "^3.10.0" + } + }, + "@parcel/utils": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/@parcel/utils/-/utils-2.8.2.tgz", + "integrity": "sha512-Ufax7wZxC9FNsUpR0EU7Z22LEY/q9jjsDTwswctCdfpWb7TE/NudOfM9myycfRvwBVEYN50lPbkt1QltEVnXQQ==", + "peer": true, + "requires": { + "@parcel/codeframe": "2.8.2", + "@parcel/diagnostic": "2.8.2", + "@parcel/hash": "2.8.2", + "@parcel/logger": "2.8.2", + "@parcel/markdown-ansi": "2.8.2", + "@parcel/source-map": "^2.1.1", + "chalk": "^4.1.0" + } + }, + "@parcel/workers": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/@parcel/workers/-/workers-2.8.2.tgz", + "integrity": "sha512-Eg6CofIrJSNBa2fjXwvnzVLPKwR/6fkfQTFAm3Jl+4JYLVknBtTSFzQNp/Fa+HUEG889H9ucTk2CBi/fVPBAFw==", + "peer": true, + "requires": { + "@parcel/diagnostic": "2.8.2", + "@parcel/logger": "2.8.2", + "@parcel/types": "2.8.2", + "@parcel/utils": "2.8.2", + "chrome-trace-event": "^1.0.2", + "nullthrows": "^1.1.1" + } + } + } + }, "@parcel/diagnostic": { "version": "2.8.0", "resolved": "https://registry.npmjs.org/@parcel/diagnostic/-/diagnostic-2.8.0.tgz", @@ -4309,6 +4820,15 @@ "detect-libc": "^1.0.3" } }, + "@parcel/graph": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/@parcel/graph/-/graph-2.8.2.tgz", + "integrity": "sha512-SLEvBQBgfkXgU4EBu30+CNanpuKjcNuEv/x8SwobCF0i3Rk+QKbe7T36bNR7727mao++2Ha69q93Dd9dTPw0kQ==", + "peer": true, + "requires": { + "nullthrows": "^1.1.1" + } + }, "@parcel/hash": { "version": "2.8.0", "resolved": "https://registry.npmjs.org/@parcel/hash/-/hash-2.8.0.tgz", @@ -4887,8 +5407,7 @@ "abortcontroller-polyfill": { "version": "1.7.3", "resolved": "https://registry.npmjs.org/abortcontroller-polyfill/-/abortcontroller-polyfill-1.7.3.tgz", - "integrity": "sha512-zetDJxd89y3X99Kvo4qFx8GKlt6GsvN3UcRZHwU6iFA/0KiOmhkTVhe8oRoTBiTVPZu09x3vCra47+w8Yz1+2Q==", - "dev": true + "integrity": "sha512-zetDJxd89y3X99Kvo4qFx8GKlt6GsvN3UcRZHwU6iFA/0KiOmhkTVhe8oRoTBiTVPZu09x3vCra47+w8Yz1+2Q==" }, "acorn": { "version": "8.8.0", @@ -4950,7 +5469,6 @@ "version": "3.0.9", "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.9.tgz", "integrity": "sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==", - "dev": true, "requires": { "safe-buffer": "^5.0.1" } @@ -5061,8 +5579,7 @@ "clone": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", - "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==", - "dev": true + "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==" }, "color-convert": { "version": "2.0.1", @@ -5197,14 +5714,12 @@ "dotenv": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-7.0.0.tgz", - "integrity": "sha512-M3NhsLbV1i6HuGzBUH8vXrtxOk+tWmzWKDMbAVSUp3Zsjm7ywFeuwrUXhmhQyRK1q5B5GGy7hcXPbj3bnfZg2g==", - "dev": true + "integrity": "sha512-M3NhsLbV1i6HuGzBUH8vXrtxOk+tWmzWKDMbAVSUp3Zsjm7ywFeuwrUXhmhQyRK1q5B5GGy7hcXPbj3bnfZg2g==" }, "dotenv-expand": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz", - "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==", - "dev": true + "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==" }, "electron-to-chromium": { "version": "1.4.251", @@ -5712,7 +6227,8 @@ "version": "8.6.6", "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-8.6.6.tgz", "integrity": "sha512-jRW30YGywD2ESXDc+l17AiritL0uVaSnWsb26f+68qaW9zgbIIr1f4v2Nsvc0+s0Z2N3uX6t/yAw7BwCQ1wMsA==", - "dev": true + "dev": true, + "requires": {} }, "marked": { "version": "4.2.5", @@ -6040,8 +6556,7 @@ "safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" }, "sass": { "version": "1.54.9", @@ -6185,6 +6700,11 @@ "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true }, + "typescript": { + "version": "4.9.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz", + "integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==" + }, "uc.micro": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", diff --git a/package.json b/package.json index 407c559..5df75e9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cg-select", - "version": "0.1.171", + "version": "0.2.1", "description": "Feature rich Select control for React/JS with multiselect, autocomplete and styling", "author": { "name": "CraftGroup", @@ -29,7 +29,8 @@ }, "dependencies": { "@parcel/optimizer-css": "^2.8.0", - "gh-pages": "^4.0.0" + "gh-pages": "^4.0.0", + "typescript": "^4.9.4" }, "keywords": [ "select", diff --git a/src/cg-select.js b/src/cg-select.js index 5a41e7c..96bf00c 100644 --- a/src/cg-select.js +++ b/src/cg-select.js @@ -92,6 +92,7 @@ export class DropDown { * selector: 'Уникальный селектор', selected: 'Выбранный элемент', placeholder: '...', + lable: '...' items: [string|number|object], darkTheme: true/false, searchMode: true/false, @@ -919,3 +920,4 @@ export class DropDown { } } } + diff --git a/src/cg-selectTS.ts b/src/cg-selectTS.ts new file mode 100644 index 0000000..cfcad63 --- /dev/null +++ b/src/cg-selectTS.ts @@ -0,0 +1,65 @@ +import { ISgSelect } from './interfaces/cg-select.interface'; +import { IItems } from './interfaces/items.interface'; +import './main.scss'; + +export class SGSelect implements ISgSelect { + selector: string; + selected?: string; + placeholder?: string; + items?: IItems[] | string[] | any; + darkTheme?: boolean; + searchMode?: boolean; + closeOnSelect?: boolean; + nativeSelectMode?: boolean; + listDisplayMode?: boolean; + language?: string; + lable?: string; + styles?: object; + event?: string; + url?: string; + multiselect?: boolean; + multiselectTag?: boolean; + + private element: Element | null; + private list: HTMLElement; + private options: object; + private caret: HTMLElement; + private category: string; + private selectedItems: object[] | object; + private itemsSelect: IItems[] | string[] | any; + private indexes: number[] = []; + + constructor(setting: ISgSelect) { + this.init(setting); + } + + private init(setting: ISgSelect): void { + const { items, multiselect, url, selector} = setting; + this.options = setting; + + const elem = document.querySelector(selector); + this.element = elem; + + this.element?.addEventListener('click', (e) => { + e.preventDefault(); + }); + + this.itemsSelect = []; + + if(multiselect === true){ + this.selectedItems = []; + } + + if (!items && url) { + this.renderUrl(); + return; + } + + items.forEach((dataItem, index) => { + this.itemsSelect.push() + }) + } + + private render() {} + private renderUrl() {} +} diff --git a/src/components/utilsTs.ts b/src/components/utilsTs.ts new file mode 100644 index 0000000..b879140 --- /dev/null +++ b/src/components/utilsTs.ts @@ -0,0 +1,48 @@ +import { IItems } from '../interfaces/items.interface'; + +interface IDataItem{ + category?: string; + categoryItems?: string; + ItemValue: IItems | string | number; +} + +/** + * Преобразование каждого елемента полученного из поля Items; + * @param {object | string} dataItem полученный елемент переданный при создании селекта может быть как object/string + * @param {number} index индекс этого элемента + * @returns {object} возвращает сформированный объект + */ + +export function getFormatItem(dataItem:IDataItem, index: number) { + const random = Math.random().toString(36).substring(2, 10); + let item: IItems; + +// if (checkItemStruct(dataItem)) { +// item = { +// id: dataItem.id, +// title: dataItem.title, +// value: index, +// }; +// } else { +// item = { +// id: random, +// title: dataItem, +// value: index, +// }; +// } + +// return item; +} + +/** + * Проверка содержит ли item указанные свойства, + * @param {object} item проверяемый на определенную структуру элемент + * @returns {boolean} возвращает true/false если item содержит указанные свойства + */ +export function checkItemStruct(item: object): boolean { + if (item && typeof item !== 'object') { + return false; + } + + return item.hasOwnProperty('id') && item.hasOwnProperty('title') && item.hasOwnProperty('value'); +} diff --git a/src/interfaces/cg-select.interface.ts b/src/interfaces/cg-select.interface.ts new file mode 100644 index 0000000..fd3190c --- /dev/null +++ b/src/interfaces/cg-select.interface.ts @@ -0,0 +1,20 @@ +import { IItems } from "./items.interface"; + +export interface ISgSelect { + selector: string; + selected?: string; + placeholder?: string; + items?: IItems[]| string[] | any; + darkTheme?: boolean; + searchMode?: boolean; + closeOnSelect?: boolean; + nativeSelectMode?: boolean; + listDisplayMode?: boolean; + language?: string; + lable?:string; + styles?: object; + event?: string; + url?: string; + multiselect?: boolean; + multiselectTag?: boolean; +} \ No newline at end of file diff --git a/src/interfaces/items.interface.ts b/src/interfaces/items.interface.ts new file mode 100644 index 0000000..c7bfa0d --- /dev/null +++ b/src/interfaces/items.interface.ts @@ -0,0 +1,5 @@ +export interface IItems{ + id: string; + title: string; + value: number | string +} \ No newline at end of file From 55c4bfaa7c56fbc37655825ab85c868b27b7c09c Mon Sep 17 00:00:00 2001 From: MaxOvs Date: Thu, 5 Jan 2023 19:56:07 +0300 Subject: [PATCH 02/21] Added methods in initSelected and methods for utils --- example/indexTs.ts | 1 - src/cg-selectTS.ts | 50 +++++++++++++-- src/components/utils/urils.interface.ts | 5 ++ src/components/utils/utilsTs.ts | 81 +++++++++++++++++++++++++ src/components/utilsTs.ts | 48 --------------- src/interfaces/items.interface.ts | 2 +- 6 files changed, 133 insertions(+), 54 deletions(-) create mode 100644 src/components/utils/urils.interface.ts create mode 100644 src/components/utils/utilsTs.ts delete mode 100644 src/components/utilsTs.ts diff --git a/example/indexTs.ts b/example/indexTs.ts index aebfdd1..73a18a7 100644 --- a/example/indexTs.ts +++ b/example/indexTs.ts @@ -3,7 +3,6 @@ import { SGSelect } from "../src/cg-selectTS"; const dropdn = new SGSelect({ selector: '.cg-dropdown_one', placeholder: 'Выберите авто', - // lable: 'EXAMPLE', items: [ 'BMW', { diff --git a/src/cg-selectTS.ts b/src/cg-selectTS.ts index cfcad63..8379ab2 100644 --- a/src/cg-selectTS.ts +++ b/src/cg-selectTS.ts @@ -1,3 +1,5 @@ +import { IDataItem } from './components/utils/urils.interface'; +import { createSelected, getFormatItem } from './components/utils/utilsTs'; import { ISgSelect } from './interfaces/cg-select.interface'; import { IItems } from './interfaces/items.interface'; import './main.scss'; @@ -22,7 +24,7 @@ export class SGSelect implements ISgSelect { private element: Element | null; private list: HTMLElement; - private options: object; + private options: ISgSelect; private caret: HTMLElement; private category: string; private selectedItems: object[] | object; @@ -31,17 +33,23 @@ export class SGSelect implements ISgSelect { constructor(setting: ISgSelect) { this.init(setting); + this.render(); } private init(setting: ISgSelect): void { const { items, multiselect, url, selector} = setting; + this.options = setting; + + const elem = document.querySelector(selector); this.element = elem; this.element?.addEventListener('click', (e) => { e.preventDefault(); + console.log('click'); + }); this.itemsSelect = []; @@ -55,11 +63,45 @@ export class SGSelect implements ISgSelect { return; } - items.forEach((dataItem, index) => { - this.itemsSelect.push() + items.forEach((dataItem:IDataItem, index:number) => { + this.itemsSelect.push(getFormatItem(dataItem, index)) }) } - private render() {} + private render() { + const { + styles, + multiselect, + searchMode, + multiselectTag, + darkTheme, + language, + nativeSelectMode, + listDisplayMode, + } = this.options; + + const random = Math.random().toString(36).substring(2, 10); + + this.initSelected() + + } + private renderUrl() {} + + + private initSelected(){ + const { styles, selected, placeholder, lable, language } = this.options; + + if (selected) { + createSelected(this.element, selected); + } else if (placeholder) { + createSelected(this.element, placeholder); + } else { + // if (language && language === 'ru') { + // createSelected(this.#element, ru.selectPlaceholder); + // } else { + // createSelected(this.#element, en.selectPlaceholder); + // } + } + } } diff --git a/src/components/utils/urils.interface.ts b/src/components/utils/urils.interface.ts new file mode 100644 index 0000000..c681930 --- /dev/null +++ b/src/components/utils/urils.interface.ts @@ -0,0 +1,5 @@ +export interface IDataItem{ + category?: string; + categoryItems?: string; + ItemValue: object | string | number; +} \ No newline at end of file diff --git a/src/components/utils/utilsTs.ts b/src/components/utils/utilsTs.ts new file mode 100644 index 0000000..3c32005 --- /dev/null +++ b/src/components/utils/utilsTs.ts @@ -0,0 +1,81 @@ +import { IItems } from '../../interfaces/items.interface'; +import { IDataItem } from './urils.interface'; + +/** + * Преобразование каждого елемента полученного из поля Items; + * @param {IDataItem} dataItem полученный елемент переданный при создании селекта может быть как object / string + * @param {number} index индекс этого элемента + * @returns {IDataItem | IItems} возвращает сформированный объект + */ + +export function getFormatItem(dataItem:IDataItem , index: number):IDataItem | IItems { + const random = Math.random().toString(36).substring(2, 10); + let item: IItems; + + if(checkItemStruct(dataItem)){ + return dataItem; + } else{ + item = { + id: random, + title: dataItem, + value: index + } + return item; + } +} + +/** + * Проверка содержит ли item указанные свойства, + * @param {object} item проверяемый на определенную структуру элемент + * @returns {boolean} возвращает true/false если item содержит указанные свойства + */ +export function checkItemStruct(item: object): boolean { + if (item && typeof item !== 'object') { + return false; + } + + return item.hasOwnProperty('id') && item.hasOwnProperty('title') && item.hasOwnProperty('value'); +} + +/** + * Создание кнопки выбора элементов + * @param {HTMLElement} element созданный экземпляр класса DropDown + * @param {string} content placeholer передаваемый из настроек селекта + * @param {object} styles не обязательный параметр. Объект в котором находяться настройки кастомизации частей селекта + */ +export function createSelected(element: Element|null, content?: string, styles?: object) { + + const select = document.createElement('div'); + const selected = document.createElement('p'); + const caret = document.createElement('div'); + + + select.classList.add('cg-select'); + selected.classList.add('selected'); + caret.classList.add('caret'); + + select.appendChild(selected); + select.appendChild(caret); + + if(content){ + const text = document.createTextNode(content); + selected.appendChild(text); + element?.appendChild(select) + } else if(styles){ + // customStyles(element, styles); + select.setAttribute('style', `${styles}`) + selected.setAttribute('style', `${styles}`) + caret.setAttribute('style', `${styles}`) + } + + // if (styles) { + // customStyles(element, styles); + + // element.innerHTML = ` + //
+ //

${content}

+ //
+ //
+ // `; + // } +} \ No newline at end of file diff --git a/src/components/utilsTs.ts b/src/components/utilsTs.ts deleted file mode 100644 index b879140..0000000 --- a/src/components/utilsTs.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { IItems } from '../interfaces/items.interface'; - -interface IDataItem{ - category?: string; - categoryItems?: string; - ItemValue: IItems | string | number; -} - -/** - * Преобразование каждого елемента полученного из поля Items; - * @param {object | string} dataItem полученный елемент переданный при создании селекта может быть как object/string - * @param {number} index индекс этого элемента - * @returns {object} возвращает сформированный объект - */ - -export function getFormatItem(dataItem:IDataItem, index: number) { - const random = Math.random().toString(36).substring(2, 10); - let item: IItems; - -// if (checkItemStruct(dataItem)) { -// item = { -// id: dataItem.id, -// title: dataItem.title, -// value: index, -// }; -// } else { -// item = { -// id: random, -// title: dataItem, -// value: index, -// }; -// } - -// return item; -} - -/** - * Проверка содержит ли item указанные свойства, - * @param {object} item проверяемый на определенную структуру элемент - * @returns {boolean} возвращает true/false если item содержит указанные свойства - */ -export function checkItemStruct(item: object): boolean { - if (item && typeof item !== 'object') { - return false; - } - - return item.hasOwnProperty('id') && item.hasOwnProperty('title') && item.hasOwnProperty('value'); -} diff --git a/src/interfaces/items.interface.ts b/src/interfaces/items.interface.ts index c7bfa0d..1e55bfd 100644 --- a/src/interfaces/items.interface.ts +++ b/src/interfaces/items.interface.ts @@ -1,5 +1,5 @@ export interface IItems{ id: string; - title: string; + title: string | number | object; value: number | string } \ No newline at end of file From 2f64f9f3a680bcd5f965101427d3d972ee147284 Mon Sep 17 00:00:00 2001 From: MaxOvs Date: Fri, 6 Jan 2023 13:40:18 +0300 Subject: [PATCH 03/21] Added methods in open and fix problems --- package-lock.json | 15 +- package.json | 1 + src/cg-selectTS.ts | 159 +++++++++++++++--- .../create-element/create-elementTs.ts | 25 +++ src/components/utils/urils.interface.ts | 4 +- src/components/utils/utilsTs.ts | 3 +- src/interfaces/items.interface.ts | 2 +- 7 files changed, 185 insertions(+), 24 deletions(-) create mode 100644 src/components/create-element/create-elementTs.ts diff --git a/package-lock.json b/package-lock.json index 65d6fdc..724119e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,15 +1,16 @@ { "name": "cg-select", - "version": "0.1.171", + "version": "0.2.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "cg-select", - "version": "0.1.171", + "version": "0.2.1", "license": "ISC", "dependencies": { "@parcel/optimizer-css": "^2.8.0", + "@types/prettier": "^2.7.2", "gh-pages": "^4.0.0", "typescript": "^4.9.4" }, @@ -2081,6 +2082,11 @@ "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", "dev": true }, + "node_modules/@types/prettier": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.2.tgz", + "integrity": "sha512-KufADq8uQqo1pYKVIYzfKbJfBAc0sOeXqGbFaSpv8MRmC/zXgowNZmFcbngndGk922QDmOASEXUZCaY48gs4cg==" + }, "node_modules/abortcontroller-polyfill": { "version": "1.7.3", "resolved": "https://registry.npmjs.org/abortcontroller-polyfill/-/abortcontroller-polyfill-1.7.3.tgz", @@ -5404,6 +5410,11 @@ "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", "dev": true }, + "@types/prettier": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.2.tgz", + "integrity": "sha512-KufADq8uQqo1pYKVIYzfKbJfBAc0sOeXqGbFaSpv8MRmC/zXgowNZmFcbngndGk922QDmOASEXUZCaY48gs4cg==" + }, "abortcontroller-polyfill": { "version": "1.7.3", "resolved": "https://registry.npmjs.org/abortcontroller-polyfill/-/abortcontroller-polyfill-1.7.3.tgz", diff --git a/package.json b/package.json index 5df75e9..cec7f93 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,7 @@ }, "dependencies": { "@parcel/optimizer-css": "^2.8.0", + "@types/prettier": "^2.7.2", "gh-pages": "^4.0.0", "typescript": "^4.9.4" }, diff --git a/src/cg-selectTS.ts b/src/cg-selectTS.ts index 8379ab2..175064e 100644 --- a/src/cg-selectTS.ts +++ b/src/cg-selectTS.ts @@ -1,3 +1,7 @@ +import { + createNativeSelect, + createNativeSelectOption, +} from './components/create-element/create-elementTs'; import { IDataItem } from './components/utils/urils.interface'; import { createSelected, getFormatItem } from './components/utils/utilsTs'; import { ISgSelect } from './interfaces/cg-select.interface'; @@ -23,9 +27,10 @@ export class SGSelect implements ISgSelect { multiselectTag?: boolean; private element: Element | null; - private list: HTMLElement; + private list: Element | null | undefined; private options: ISgSelect; - private caret: HTMLElement; + private randomId: string; + private caret: Element | null | undefined; private category: string; private selectedItems: object[] | object; private itemsSelect: IItems[] | string[] | any; @@ -36,39 +41,74 @@ export class SGSelect implements ISgSelect { this.render(); } + /** + * Приватный метод инициализации экземпляра класса DropDown + * @method #init + * @member + * @protected + * @param {ISgSelect} setting передаваемые настройки селекта + * @description Приватный метод. Общая инициализация селекта. Получение настоек и преобразвание элементов селекта. + * @example + * { + selector: '.cg-dropdown_one', + placeholder: 'Выберите авто', + items: [ + 'BMW', + { + id: '213sade', + title: 'Opel', + value: 1, + }, + 'Mersedes', + 'MAN', + 'max', + ], + darkTheme: true, + multiselect: true, + multiselectTag: true, + } + */ private init(setting: ISgSelect): void { - const { items, multiselect, url, selector} = setting; + const { items, multiselect, url, selector } = setting; this.options = setting; - - const elem = document.querySelector(selector); this.element = elem; this.element?.addEventListener('click', (e) => { e.preventDefault(); - console.log('click'); - + this.open(); }); this.itemsSelect = []; - - if(multiselect === true){ - this.selectedItems = []; + + if (multiselect === true) { + this.selectedItems = []; } if (!items && url) { - this.renderUrl(); - return; + this.renderUrl(); + return; } - items.forEach((dataItem:IDataItem, index:number) => { - this.itemsSelect.push(getFormatItem(dataItem, index)) - }) + items.forEach((dataItem: any, index: number) => { + let itemInputs: IDataItem = { + ItemValue: dataItem, + }; + + this.itemsSelect.push(getFormatItem(itemInputs.ItemValue, index)); + }); } - private render() { + /** + * Приватный метод рендера экземпляра класса DropDown + *@protected + * @method #render + * @param {string} select необязательный елемент. Передаеться в метод initSelected + * @description Рендер елементов в селекте. + */ + private render(select?: string): void { const { styles, multiselect, @@ -82,14 +122,76 @@ export class SGSelect implements ISgSelect { const random = Math.random().toString(36).substring(2, 10); - this.initSelected() + this.initSelected(); + const ulList = document.createElement('ul'); + const nativeSelect = createNativeSelect(); + + let inputSearch: string = ''; + let textNode: Text; + + this.randomId = random; + + ulList.classList.add('list'); + + this.element?.appendChild(ulList); + + this.itemsSelect.forEach((dataItem: IItems | any) => { + this.element?.appendChild(nativeSelect); + + const liItem = document.createElement('li'); + const nativeOption = createNativeSelectOption(); + const strongItem = document.createElement('strong'); + + liItem.classList.add('list__item'); + strongItem.classList.add('category'); + + if (multiselect && multiselect === true) { + const checkBox = document.createElement('input'); + checkBox.type = 'checkbox'; + checkBox.setAttribute('id', `chbox-${dataItem.id}`); + liItem.appendChild(checkBox); + + if (multiselectTag && multiselectTag == true) { + checkBox.classList.add('displayHide'); + } + + nativeSelect.setAttribute('multiple', 'multiple'); + } + + if (dataItem.title) { + nativeOption.text = dataItem.title; + nativeOption.value = dataItem.title; + textNode = document.createTextNode(dataItem.title); + + nativeSelect.appendChild(nativeOption); + liItem.appendChild(textNode); + ulList.appendChild(liItem); + } else { + // Для отрисовки категорий + textNode = document.createTextNode(dataItem); + strongItem.appendChild(textNode); + ulList.appendChild(strongItem); + } + }); + + this.list = this.element?.querySelector('.list'); + this.caret = this.element?.querySelector('.caret'); + + // this.#addOptionsBehaviour(); } private renderUrl() {} - - private initSelected(){ + /** + * Привaтный метод экземпляра класса DropDown + * + * @method #initSelected + * @param {string} select необязательный елемент. Используется в методе selectIndex + * @description Отрисовывает и стилизует селект + * @protected + */ + private initSelected(select?: string): void { const { styles, selected, placeholder, lable, language } = this.options; if (selected) { @@ -104,4 +206,23 @@ export class SGSelect implements ISgSelect { // } } } + + /** + * Приватный метод экземпляра класса DropDown + * @protected + * @param {boolean} oneClick необязательный параметр передаваемый из функции buttonControl + * @description Открывает список для выбора элемента + * @method #open + */ + private open(oneClick?: boolean): void { + if (oneClick === true) { + this.list?.classList.add('open'); + this.caret?.classList.add('caret_rotate'); + } else { + this.list?.classList.toggle('open'); + this.caret?.classList.toggle('caret_rotate'); + } + } + + private addOptionsBehaviour() {} } diff --git a/src/components/create-element/create-elementTs.ts b/src/components/create-element/create-elementTs.ts new file mode 100644 index 0000000..c5d4f7c --- /dev/null +++ b/src/components/create-element/create-elementTs.ts @@ -0,0 +1,25 @@ + +/** + * Метод который создает нативный селект + * @returns {HTMLSelectElement} Возвращает созданный нативный селект + */ + +export function createNativeSelect(): HTMLSelectElement { + const nativeSelect = document.createElement('select'); + + nativeSelect.setAttribute('name', 'dataSelect'); + nativeSelect.classList.add('nativeSelect'); + return nativeSelect; +} + +/** + * Метод который создает Options для нативного селекта + * @returns {HTMLOptionElement} Возвращает созданные Options нативного селекта + */ +export function createNativeSelectOption(): HTMLOptionElement { + const nativeOption = document.createElement('option'); + + nativeOption.classList.add('nativeSelect__nativeOption'); + return nativeOption; +} + \ No newline at end of file diff --git a/src/components/utils/urils.interface.ts b/src/components/utils/urils.interface.ts index c681930..b21d691 100644 --- a/src/components/utils/urils.interface.ts +++ b/src/components/utils/urils.interface.ts @@ -1,5 +1,7 @@ +import { IItems } from "../../interfaces/items.interface"; + export interface IDataItem{ category?: string; categoryItems?: string; - ItemValue: object | string | number; + ItemValue: string | IItems | number; } \ No newline at end of file diff --git a/src/components/utils/utilsTs.ts b/src/components/utils/utilsTs.ts index 3c32005..e63d5eb 100644 --- a/src/components/utils/utilsTs.ts +++ b/src/components/utils/utilsTs.ts @@ -8,7 +8,7 @@ import { IDataItem } from './urils.interface'; * @returns {IDataItem | IItems} возвращает сформированный объект */ -export function getFormatItem(dataItem:IDataItem , index: number):IDataItem | IItems { +export function getFormatItem(dataItem:any , index: number) : IItems { const random = Math.random().toString(36).substring(2, 10); let item: IItems; @@ -20,6 +20,7 @@ export function getFormatItem(dataItem:IDataItem , index: number):IDataItem | II title: dataItem, value: index } + return item; } } diff --git a/src/interfaces/items.interface.ts b/src/interfaces/items.interface.ts index 1e55bfd..c7bfa0d 100644 --- a/src/interfaces/items.interface.ts +++ b/src/interfaces/items.interface.ts @@ -1,5 +1,5 @@ export interface IItems{ id: string; - title: string | number | object; + title: string; value: number | string } \ No newline at end of file From f3f6d754dfe4635159b5f953f531fbd795731d55 Mon Sep 17 00:00:00 2001 From: MaxOvs Date: Fri, 6 Jan 2023 14:07:37 +0300 Subject: [PATCH 04/21] Finish working in basic functionality --- src/cg-selectTS.ts | 84 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 78 insertions(+), 6 deletions(-) diff --git a/src/cg-selectTS.ts b/src/cg-selectTS.ts index 175064e..fd02f20 100644 --- a/src/cg-selectTS.ts +++ b/src/cg-selectTS.ts @@ -39,11 +39,12 @@ export class SGSelect implements ISgSelect { constructor(setting: ISgSelect) { this.init(setting); this.render(); + this.closeSelectClick(); } /** * Приватный метод инициализации экземпляра класса DropDown - * @method #init + * @method init * @member * @protected * @param {ISgSelect} setting передаваемые настройки селекта @@ -104,7 +105,7 @@ export class SGSelect implements ISgSelect { /** * Приватный метод рендера экземпляра класса DropDown *@protected - * @method #render + * @method render * @param {string} select необязательный елемент. Передаеться в метод initSelected * @description Рендер елементов в селекте. */ @@ -178,7 +179,7 @@ export class SGSelect implements ISgSelect { this.list = this.element?.querySelector('.list'); this.caret = this.element?.querySelector('.caret'); - // this.#addOptionsBehaviour(); + this.addOptionsBehaviour(); } private renderUrl() {} @@ -186,7 +187,7 @@ export class SGSelect implements ISgSelect { /** * Привaтный метод экземпляра класса DropDown * - * @method #initSelected + * @method initSelected * @param {string} select необязательный елемент. Используется в методе selectIndex * @description Отрисовывает и стилизует селект * @protected @@ -212,7 +213,7 @@ export class SGSelect implements ISgSelect { * @protected * @param {boolean} oneClick необязательный параметр передаваемый из функции buttonControl * @description Открывает список для выбора элемента - * @method #open + * @method open */ private open(oneClick?: boolean): void { if (oneClick === true) { @@ -224,5 +225,76 @@ export class SGSelect implements ISgSelect { } } - private addOptionsBehaviour() {} + /** + * Приватный метод экземпляра класса DropDown + * @protected + * @description Закрывает список + * @method #close + */ + private close() { + this.list?.classList.remove('open'); + this.caret?.classList.remove('caret_rotate'); + } + + /** + * Приватный метод экземпляра класса DropDown + * @protected + * @description Закрывает список по клику вне элемента + * @method #closeSelectClick + */ + private closeSelectClick() { + const dropdown = document.querySelector(`${this.options.selector}`); + + document.addEventListener('click', (e) => { + const withinBoundaries = e.composedPath().includes(dropdown!); + if (!withinBoundaries) { + // if (this.btn) { + // return; + // } else { + // this.#close(); + // } + this.close(); + } + }); + } + + /** + * Приватный метод экземпляра класса DropDown + * @protected + * @description Метод реализовывающий выбор элементов в разных режимах. Обычный/Мультиселект/Мультиселект + Мультиселект Таг. + * @method addOptionsBehaviour + */ + private addOptionsBehaviour() { + const { + multiselect, + placeholder, + selected, + multiselectTag, + searchMode, + closeOnSelect, + darkTheme, + } = this.options; + + const options = this.element?.querySelectorAll('.list__item'); + const select = this.element?.querySelector('.selected'); + const nativeOption = this.element?.querySelectorAll('.nativeSelect__nativeOption'); + + const ulMultipul = document.createElement('ul'); + + if (multiselect && multiselect == true) { + ulMultipul.classList.add('multiselect-tag'); + select?.classList.add('overflow-hidden'); + } + + options?.forEach((option: Element, index: number) => { + option.addEventListener('click', (event) => { + const item = this.itemsSelect[index]; + const checkIndex = this.indexes.indexOf(index); + + select!.textContent = item.title; + this.selectedItems = item; + console.log(this.selectedItems); + }); + }); + } } From ef832c60aef0fed29c2c13744af49b275db0e8f6 Mon Sep 17 00:00:00 2001 From: MaxOvs Date: Fri, 6 Jan 2023 14:57:14 +0300 Subject: [PATCH 05/21] Fix naming --- example/indexTs.ts | 32 +++++++++++----------- src/cg-selectTS.ts | 12 ++++----- src/interfaces/cg-select.interface.ts | 38 +++++++++++++-------------- 3 files changed, 41 insertions(+), 41 deletions(-) diff --git a/example/indexTs.ts b/example/indexTs.ts index 73a18a7..22b9db4 100644 --- a/example/indexTs.ts +++ b/example/indexTs.ts @@ -1,17 +1,17 @@ -import { SGSelect } from "../src/cg-selectTS"; +import { CGSelect } from '../src/cg-selectTS'; -const dropdn = new SGSelect({ - selector: '.cg-dropdown_one', - placeholder: 'Выберите авто', - items: [ - 'BMW', - { - id: '213sade', - title: 'Opel', - value: 'ds', - }, - 'Mersedes', - 'MAN', - 'Ferari', - ] -}) \ No newline at end of file +const dropdn = new CGSelect({ + selector: '.cg-dropdown_one', + placeholder: 'Выберите авто', + items: [ + 'BMW', + { + id: '213sade', + title: 'Opel', + value: 'ds', + }, + 'Mersedes', + 'MAN', + 'Ferari', + ], +}); diff --git a/src/cg-selectTS.ts b/src/cg-selectTS.ts index fd02f20..f29a439 100644 --- a/src/cg-selectTS.ts +++ b/src/cg-selectTS.ts @@ -4,11 +4,11 @@ import { } from './components/create-element/create-elementTs'; import { IDataItem } from './components/utils/urils.interface'; import { createSelected, getFormatItem } from './components/utils/utilsTs'; -import { ISgSelect } from './interfaces/cg-select.interface'; +import { ICgSelect } from './interfaces/cg-select.interface'; import { IItems } from './interfaces/items.interface'; import './main.scss'; -export class SGSelect implements ISgSelect { +export class CGSelect implements ICgSelect { selector: string; selected?: string; placeholder?: string; @@ -28,7 +28,7 @@ export class SGSelect implements ISgSelect { private element: Element | null; private list: Element | null | undefined; - private options: ISgSelect; + private options: ICgSelect; private randomId: string; private caret: Element | null | undefined; private category: string; @@ -36,7 +36,7 @@ export class SGSelect implements ISgSelect { private itemsSelect: IItems[] | string[] | any; private indexes: number[] = []; - constructor(setting: ISgSelect) { + constructor(setting: ICgSelect) { this.init(setting); this.render(); this.closeSelectClick(); @@ -69,7 +69,7 @@ export class SGSelect implements ISgSelect { multiselectTag: true, } */ - private init(setting: ISgSelect): void { + private init(setting: ICgSelect): void { const { items, multiselect, url, selector } = setting; this.options = setting; @@ -240,7 +240,7 @@ export class SGSelect implements ISgSelect { * Приватный метод экземпляра класса DropDown * @protected * @description Закрывает список по клику вне элемента - * @method #closeSelectClick + * @method closeSelectClick */ private closeSelectClick() { const dropdown = document.querySelector(`${this.options.selector}`); diff --git a/src/interfaces/cg-select.interface.ts b/src/interfaces/cg-select.interface.ts index fd3190c..fe0d651 100644 --- a/src/interfaces/cg-select.interface.ts +++ b/src/interfaces/cg-select.interface.ts @@ -1,20 +1,20 @@ -import { IItems } from "./items.interface"; +import { IItems } from './items.interface'; -export interface ISgSelect { - selector: string; - selected?: string; - placeholder?: string; - items?: IItems[]| string[] | any; - darkTheme?: boolean; - searchMode?: boolean; - closeOnSelect?: boolean; - nativeSelectMode?: boolean; - listDisplayMode?: boolean; - language?: string; - lable?:string; - styles?: object; - event?: string; - url?: string; - multiselect?: boolean; - multiselectTag?: boolean; -} \ No newline at end of file +export interface ICgSelect { + selector: string; + selected?: string; + placeholder?: string; + items?: IItems[] | string[] | any; + darkTheme?: boolean; + searchMode?: boolean; + closeOnSelect?: boolean; + nativeSelectMode?: boolean; + listDisplayMode?: boolean; + language?: string; + lable?: string; + styles?: object; + event?: string; + url?: string; + multiselect?: boolean; + multiselectTag?: boolean; +} From 8eeabf44b2b6ffb9792621506cf380ff4bb95018 Mon Sep 17 00:00:00 2001 From: MaxOvs Date: Fri, 6 Jan 2023 21:14:16 +0300 Subject: [PATCH 06/21] Working in multiple mode --- example/indexTs.ts | 1 + src/cg-selectTS.ts | 100 +++++++++++++++--- .../create-element/create-elementTs.ts | 89 +++++++++++++--- src/components/utils/utilsTs.ts | 44 +++++--- 4 files changed, 193 insertions(+), 41 deletions(-) diff --git a/example/indexTs.ts b/example/indexTs.ts index 22b9db4..c038be2 100644 --- a/example/indexTs.ts +++ b/example/indexTs.ts @@ -14,4 +14,5 @@ const dropdn = new CGSelect({ 'MAN', 'Ferari', ], + multiselect: true, }); diff --git a/src/cg-selectTS.ts b/src/cg-selectTS.ts index f29a439..9f0bc99 100644 --- a/src/cg-selectTS.ts +++ b/src/cg-selectTS.ts @@ -3,7 +3,7 @@ import { createNativeSelectOption, } from './components/create-element/create-elementTs'; import { IDataItem } from './components/utils/urils.interface'; -import { createSelected, getFormatItem } from './components/utils/utilsTs'; +import { createSelected, getFormatItem, nativeOptionOrdinary } from './components/utils/utilsTs'; import { ICgSelect } from './interfaces/cg-select.interface'; import { IItems } from './interfaces/items.interface'; import './main.scss'; @@ -32,7 +32,7 @@ export class CGSelect implements ICgSelect { private randomId: string; private caret: Element | null | undefined; private category: string; - private selectedItems: object[] | object; + private selectedItems: string[] | string; private itemsSelect: IItems[] | string[] | any; private indexes: number[] = []; @@ -84,10 +84,6 @@ export class CGSelect implements ICgSelect { this.itemsSelect = []; - if (multiselect === true) { - this.selectedItems = []; - } - if (!items && url) { this.renderUrl(); return; @@ -147,13 +143,13 @@ export class CGSelect implements ICgSelect { liItem.classList.add('list__item'); strongItem.classList.add('category'); - if (multiselect && multiselect === true) { + if (multiselect) { const checkBox = document.createElement('input'); checkBox.type = 'checkbox'; checkBox.setAttribute('id', `chbox-${dataItem.id}`); liItem.appendChild(checkBox); - if (multiselectTag && multiselectTag == true) { + if (multiselectTag) { checkBox.classList.add('displayHide'); } @@ -276,24 +272,102 @@ export class CGSelect implements ICgSelect { } = this.options; const options = this.element?.querySelectorAll('.list__item'); - const select = this.element?.querySelector('.selected'); + const select: HTMLElement | null | undefined = this.element?.querySelector('.selected'); const nativeOption = this.element?.querySelectorAll('.nativeSelect__nativeOption'); const ulMultipul = document.createElement('ul'); - if (multiselect && multiselect == true) { + if (multiselect) { ulMultipul.classList.add('multiselect-tag'); select?.classList.add('overflow-hidden'); } options?.forEach((option: Element, index: number) => { option.addEventListener('click', (event) => { - const item = this.itemsSelect[index]; + const item: IItems = this.itemsSelect[index]; const checkIndex = this.indexes.indexOf(index); + if (closeOnSelect == false || multiselect) { + event.stopPropagation(); + event.preventDefault(); + } + select!.textContent = item.title; - this.selectedItems = item; - console.log(this.selectedItems); + this.selectedItems = item.title; + + nativeOptionOrdinary(nativeOption, item.title); + + options.forEach((option) => { + option.classList.remove('active'); + }); + option.classList.add('active'); + + // if (multiselect) { + // this.selectedItems = []; + // option.classList.toggle('active'); + // const checkBox: HTMLInputElement | null = option.querySelector('input[type="checkbox"]'); + + // if (checkBox) { + // if (!(event.target instanceof HTMLInputElement)) { + // checkBox.checked = !checkBox.checked; + // } + + // if (checkIndex === -1) { + // nativeOptionMultiple(nativeOption, item.title, true); + // this.indexes.push(index); + // select!.textContent = ''; + + // if (multiselectTag) { + // this.selectedItems.push(item); + // select!.appendChild(ulMultipul); + + // const data = { + // option: this.options, + // element: this.element, + // indexes: this.indexes, + // selectedItems: this.selectedItems, + // }; + + // ulMultipul.appendChild(createBreadcrumb(data, item.title, index, item.id)); + // } else { + // debugger; + // this.selectedItems.push(item.title); + // console.log(this.selectedItems); + + // select.innerText = this.selectedItems; + // } + // } else { + // if (multiselectTag) { + // const tagItem = document.getElementById(`tag-${index}-${item.id}`); + // ulMultipul.removeChild(tagItem); + // } + + // this.indexes.splice(checkIndex, 1); + // this.selectedItems.splice(checkIndex, 1); + // nativeOptionMultiple(nativeOption, item.title, false); + // } + + // if (!this.#selectedItems.length) { + // getSelectText(dataSelectText, select); + // } else { + // if (multiselectTag) { + // select.appendChild(ulMultipul); + // } else { + // select.innerText = this.#selectedItems; + // } + // } + // } + // } 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-elementTs.ts b/src/components/create-element/create-elementTs.ts index c5d4f7c..bbfccb0 100644 --- a/src/components/create-element/create-elementTs.ts +++ b/src/components/create-element/create-elementTs.ts @@ -1,15 +1,13 @@ - /** * Метод который создает нативный селект * @returns {HTMLSelectElement} Возвращает созданный нативный селект */ - export function createNativeSelect(): HTMLSelectElement { - const nativeSelect = document.createElement('select'); - - nativeSelect.setAttribute('name', 'dataSelect'); - nativeSelect.classList.add('nativeSelect'); - return nativeSelect; + const nativeSelect = document.createElement('select'); + + nativeSelect.setAttribute('name', 'dataSelect'); + nativeSelect.classList.add('nativeSelect'); + return nativeSelect; } /** @@ -17,9 +15,76 @@ export function createNativeSelect(): HTMLSelectElement { * @returns {HTMLOptionElement} Возвращает созданные Options нативного селекта */ export function createNativeSelectOption(): HTMLOptionElement { - const nativeOption = document.createElement('option'); - - nativeOption.classList.add('nativeSelect__nativeOption'); - return nativeOption; + const nativeOption = document.createElement('option'); + + nativeOption.classList.add('nativeSelect__nativeOption'); + return nativeOption; +} + +/** + * Метод который создает и отвечает за поведение chips + * @param {object} data объект в котором содержатся настройки и элементы селекта + * @param {string} title имя выбранного элемента для отрисовки chips + * @param {number} index индекс выбранного элемента для отрисовки chips + * @param {string} id уникальное id выбранного элемента + * @returns {HTMLElement} возвращает сформированный HTMLElement chips item + */ +export function createBreadcrumb(data: any, 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 liChip = document.createElement('li'); + const textNode = document.createTextNode(title); + const svgIcon = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); + const path1 = document.createElementNS('http://www.w3.org/2000/svg', 'path'); + const path2 = document.createElementNS('http://www.w3.org/2000/svg', 'path'); + + svgIcon.setAttribute('viewBox', '0 0 10 10'); + path1.setAttribute('d', 'M3,7 L7,3'); + path2.setAttribute('d', 'M3,3 L7,7'); + liChip.setAttribute('id', `tag-${index}-${id}`); + + svgIcon.classList.add('svg-icon'); + + svgIcon.appendChild(path1); + svgIcon.appendChild(path2); + liChip.appendChild(textNode); + liChip.appendChild(svgIcon); + + if (styles) { + const { chips } = styles; + // customStylesFormat(chips, liChip); + } + + svgIcon.addEventListener('click', (event) => { + event.preventDefault(); + event.stopPropagation(); + // nativeOptionMultiple(nativeOption, title, false); + + const deleteIcon = indexes.indexOf(index); + let checkBox = ''; + + indexes.splice(deleteIcon, 1); + selectedItems.splice(deleteIcon, 1); + + if (id) { + // checkBox = document.getElementById(`chbox-${id}`); + } else { + // checkBox = document.getElementById(`chbox-${index}`); + } + + // checkBox.checked = false; + // checkBox.parentElement.classList.remove('active'); + + if (!selectedItems.length) { + selected.innerText = placeholder; + } + + // liChip.parentElement.removeChild(liChip); + }); + + return liChip; } - \ No newline at end of file diff --git a/src/components/utils/utilsTs.ts b/src/components/utils/utilsTs.ts index e63d5eb..0da297f 100644 --- a/src/components/utils/utilsTs.ts +++ b/src/components/utils/utilsTs.ts @@ -8,18 +8,18 @@ import { IDataItem } from './urils.interface'; * @returns {IDataItem | IItems} возвращает сформированный объект */ -export function getFormatItem(dataItem:any , index: number) : IItems { +export function getFormatItem(dataItem: any, index: number): IItems { const random = Math.random().toString(36).substring(2, 10); let item: IItems; - if(checkItemStruct(dataItem)){ - return dataItem; - } else{ + if (checkItemStruct(dataItem)) { + return dataItem; + } else { item = { id: random, title: dataItem, - value: index - } + value: index, + }; return item; } @@ -44,13 +44,11 @@ export function checkItemStruct(item: object): boolean { * @param {string} content placeholer передаваемый из настроек селекта * @param {object} styles не обязательный параметр. Объект в котором находяться настройки кастомизации частей селекта */ -export function createSelected(element: Element|null, content?: string, styles?: object) { - +export function createSelected(element: Element | null, content?: string, styles?: object) { const select = document.createElement('div'); const selected = document.createElement('p'); const caret = document.createElement('div'); - select.classList.add('cg-select'); selected.classList.add('selected'); caret.classList.add('caret'); @@ -58,15 +56,15 @@ export function createSelected(element: Element|null, content?: string, styles?: select.appendChild(selected); select.appendChild(caret); - if(content){ + if (content) { const text = document.createTextNode(content); selected.appendChild(text); - element?.appendChild(select) - } else if(styles){ + element?.appendChild(select); + } else if (styles) { // customStyles(element, styles); - select.setAttribute('style', `${styles}`) - selected.setAttribute('style', `${styles}`) - caret.setAttribute('style', `${styles}`) + select.setAttribute('style', `${styles}`); + selected.setAttribute('style', `${styles}`); + caret.setAttribute('style', `${styles}`); } // if (styles) { @@ -79,4 +77,18 @@ export function createSelected(element: Element|null, content?: string, styles?: // // `; // } -} \ No newline at end of file +} + +/** + * Поведение нативного(одинарного) селекта при выборе кастомного + * @param {NodeList} element NodeList нативного селекта + * @param {any} item выбранный элемент в кастомном селекте + */ +export function nativeOptionOrdinary(element: NodeListOf | undefined, item: any) { + element!.forEach((option) => { + option.removeAttribute('selected'); + if (option.textContent === item) { + option.setAttribute('selected', 'selected'); + } + }); +} From 482bd59756de38177d645fd0a437dfeed6f1c80d Mon Sep 17 00:00:00 2001 From: MaxOvs Date: Mon, 9 Jan 2023 16:10:43 +0300 Subject: [PATCH 07/21] multiselect WORKING! And added new interface in create-element --- src/cg-selectTS.ts | 81 ++++++++++++++----- .../create-element.interface.ts | 8 ++ .../create-element/create-elementTs.ts | 17 ++-- src/components/utils/urils.interface.ts | 17 ++-- src/components/utils/utilsTs.ts | 51 +++++++++++- 5 files changed, 140 insertions(+), 34 deletions(-) create mode 100644 src/components/create-element/create-element.interface.ts 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; + } + }); +} From 2ed0e306e5b67338a7cf239ae3919c234309be81 Mon Sep 17 00:00:00 2001 From: MaxOvs Date: Mon, 9 Jan 2023 17:57:56 +0300 Subject: [PATCH 08/21] MultiTag in Working! Fixed bugs --- example/indexTs.ts | 1 + src/cg-selectTS.ts | 103 +++++++----------- .../create-element.interface.ts | 2 +- .../create-element/create-elementTs.ts | 29 ++--- 4 files changed, 57 insertions(+), 78 deletions(-) diff --git a/example/indexTs.ts b/example/indexTs.ts index c038be2..d96c107 100644 --- a/example/indexTs.ts +++ b/example/indexTs.ts @@ -15,4 +15,5 @@ const dropdn = new CGSelect({ 'Ferari', ], multiselect: true, + multiselectTag: true, }); diff --git a/src/cg-selectTS.ts b/src/cg-selectTS.ts index 837dd52..6e5ee40 100644 --- a/src/cg-selectTS.ts +++ b/src/cg-selectTS.ts @@ -1,8 +1,12 @@ +import { ICreateBreadCrumb } from './components/create-element/create-element.interface'; import { + CreateBreadCrumb, createNativeSelect, createNativeSelectOption, } from './components/create-element/create-elementTs'; + import { IDataItem, ITextSelect } from './components/utils/urils.interface'; + import { createSelected, getFormatItem, @@ -10,6 +14,7 @@ import { nativeOptionMultiple, nativeOptionOrdinary, } from './components/utils/utilsTs'; + import { ICgSelect } from './interfaces/cg-select.interface'; import { IItems } from './interfaces/items.interface'; import './main.scss'; @@ -320,22 +325,50 @@ export class CGSelect implements ICgSelect { nativeOptionMultiple(nativeOption, item.title, true); select!.textContent = ''; - if (Array.isArray(this.selectedItems)) { - this.selectedItems.push(item.title); - select!.innerText = this.selectedItems.join(','); + if (multiselectTag) { + if (Array.isArray(this.selectedItems)) { + const dataBreadCrumb: ICreateBreadCrumb = { + option: this.options, + element: this.element, + indexes: this.indexes, + selectedItems: this.selectedItems, + }; + + this.selectedItems.push(item.title); + select!.appendChild(ulMultipul); + ulMultipul.appendChild( + CreateBreadCrumb(dataBreadCrumb, item.title, index, item.id), + ); + } + } else { + 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 (multiselectTag) { + const tagItem = document.getElementById(`tag-${index}-${item.id}`); + ulMultipul.removeChild(tagItem!); + } if (Array.isArray(this.selectedItems)) { this.selectedItems.splice(checkIndex, 1); - select!.innerText = this.selectedItems.join(','); + this.indexes.splice(checkIndex, 1); + nativeOptionMultiple(nativeOption, item.title, false); } } - if (Array.isArray(this.selectedItems) && !this.selectedItems.length) { + if (!this.selectedItems.length) { getSelectText(placeholderTextSelect, select); + } else { + if (multiselectTag) { + select!.appendChild(ulMultipul); + } else { + if (Array.isArray(this.selectedItems)) { + select!.innerText = this.selectedItems.join(','); + } + } } } } else { @@ -349,62 +382,6 @@ export class CGSelect implements ICgSelect { }); option.classList.add('active'); } - - // if (multiselect) { - // this.selectedItems = []; - // option.classList.toggle('active'); - // const checkBox: HTMLInputElement | null = option.querySelector('input[type="checkbox"]'); - - // if (checkBox) { - // if (!(event.target instanceof HTMLInputElement)) { - // checkBox.checked = !checkBox.checked; - // } - - // if (checkIndex === -1) { - // nativeOptionMultiple(nativeOption, item.title, true); - // this.indexes.push(index); - // select!.textContent = ''; - - // if (multiselectTag) { - // this.selectedItems.push(item); - // select!.appendChild(ulMultipul); - - // const data = { - // option: this.options, - // element: this.element, - // indexes: this.indexes, - // selectedItems: this.selectedItems, - // }; - - // ulMultipul.appendChild(createBreadcrumb(data, item.title, index, item.id)); - // } else { - // debugger; - // this.selectedItems.push(item.title); - // console.log(this.selectedItems); - - // select.innerText = this.selectedItems; - // } - // } else { - // if (multiselectTag) { - // const tagItem = document.getElementById(`tag-${index}-${item.id}`); - // ulMultipul.removeChild(tagItem); - // } - - // this.indexes.splice(checkIndex, 1); - // this.selectedItems.splice(checkIndex, 1); - // nativeOptionMultiple(nativeOption, item.title, false); - // } - - // if (!this.#selectedItems.length) { - // getSelectText(dataSelectText, select); - // } else { - // if (multiselectTag) { - // select.appendChild(ulMultipul); - // } else { - // select.innerText = this.#selectedItems; - // } - // } - // } }); }); } diff --git a/src/components/create-element/create-element.interface.ts b/src/components/create-element/create-element.interface.ts index c3d42a9..31c3ada 100644 --- a/src/components/create-element/create-element.interface.ts +++ b/src/components/create-element/create-element.interface.ts @@ -1,6 +1,6 @@ import { ICgSelect } from '../../interfaces/cg-select.interface'; -export interface IcreateBreadCrumb { +export interface ICreateBreadCrumb { element: Element | null; option: ICgSelect; indexes: number[]; diff --git a/src/components/create-element/create-elementTs.ts b/src/components/create-element/create-elementTs.ts index 88cc128..49da6bf 100644 --- a/src/components/create-element/create-elementTs.ts +++ b/src/components/create-element/create-elementTs.ts @@ -1,4 +1,5 @@ -import { IcreateBreadCrumb } from './create-element.interface'; +import { nativeOptionMultiple } from '../utils/utilsTs'; +import { ICreateBreadCrumb } from './create-element.interface'; /** * Метод который создает нативный селект @@ -25,22 +26,22 @@ export function createNativeSelectOption(): HTMLOptionElement { /** * Метод который создает и отвечает за поведение chips - * @param {object} data объект в котором содержатся настройки и элементы селекта + * @param {ICreateBreadCrumb} data объект в котором содержатся настройки и элементы селекта * @param {string} title имя выбранного элемента для отрисовки chips * @param {number} index индекс выбранного элемента для отрисовки chips * @param {string} id уникальное id выбранного элемента * @returns {HTMLElement} возвращает сформированный HTMLElement chips item */ -export function createBreadcrumb( - data: IcreateBreadCrumb, +export function CreateBreadCrumb( + data: ICreateBreadCrumb, title: string, index: number, id: string, -) { +): HTMLLIElement { const { element, option, indexes, selectedItems } = data; const { placeholder, styles } = option; - const selected = element!.querySelector('.selected'); + const selected: HTMLElement | null | undefined = element?.querySelector('.selected'); const nativeOption = element!.querySelectorAll('.nativeSelect__nativeOption'); const liChip = document.createElement('li'); @@ -69,28 +70,28 @@ export function createBreadcrumb( svgIcon.addEventListener('click', (event) => { event.preventDefault(); event.stopPropagation(); - // nativeOptionMultiple(nativeOption, title, false); + nativeOptionMultiple(nativeOption, title, false); const deleteIcon = indexes.indexOf(index); - let checkBox = ''; + let checkBox: any; indexes.splice(deleteIcon, 1); selectedItems.splice(deleteIcon, 1); if (id) { - // checkBox = document.getElementById(`chbox-${id}`); + checkBox = document.getElementById(`chbox-${id}`); } else { - // checkBox = document.getElementById(`chbox-${index}`); + checkBox = document.getElementById(`chbox-${index}`); } - // checkBox.checked = false; - // checkBox.parentElement.classList.remove('active'); + checkBox.checked = false; + checkBox.parentElement.classList.remove('active'); if (!selectedItems.length) { - //selected?.textContent = placeholder; + selected!.innerText = placeholder!; } - // liChip.parentElement.removeChild(liChip); + liChip.parentElement!.removeChild(liChip); }); return liChip; From aab59fd24348229fdefe6141efaae48adac9f12b Mon Sep 17 00:00:00 2001 From: MaxOvs Date: Mon, 9 Jan 2023 18:01:31 +0300 Subject: [PATCH 09/21] Fixed naming --- src/cg-selectTS.ts | 10 +++++----- src/components/create-element/create-elementTs.ts | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/cg-selectTS.ts b/src/cg-selectTS.ts index 6e5ee40..4544967 100644 --- a/src/cg-selectTS.ts +++ b/src/cg-selectTS.ts @@ -1,11 +1,9 @@ -import { ICreateBreadCrumb } from './components/create-element/create-element.interface'; import { - CreateBreadCrumb, + createBreadCrumb, createNativeSelect, createNativeSelectOption, } from './components/create-element/create-elementTs'; - -import { IDataItem, ITextSelect } from './components/utils/urils.interface'; +import { ICreateBreadCrumb } from './components/create-element/create-element.interface'; import { createSelected, @@ -14,9 +12,11 @@ import { nativeOptionMultiple, nativeOptionOrdinary, } from './components/utils/utilsTs'; +import { IDataItem, ITextSelect } from './components/utils/urils.interface'; import { ICgSelect } from './interfaces/cg-select.interface'; import { IItems } from './interfaces/items.interface'; + import './main.scss'; export class CGSelect implements ICgSelect { @@ -337,7 +337,7 @@ export class CGSelect implements ICgSelect { this.selectedItems.push(item.title); select!.appendChild(ulMultipul); ulMultipul.appendChild( - CreateBreadCrumb(dataBreadCrumb, item.title, index, item.id), + createBreadCrumb(dataBreadCrumb, item.title, index, item.id), ); } } else { diff --git a/src/components/create-element/create-elementTs.ts b/src/components/create-element/create-elementTs.ts index 49da6bf..5c5278f 100644 --- a/src/components/create-element/create-elementTs.ts +++ b/src/components/create-element/create-elementTs.ts @@ -32,7 +32,7 @@ export function createNativeSelectOption(): HTMLOptionElement { * @param {string} id уникальное id выбранного элемента * @returns {HTMLElement} возвращает сформированный HTMLElement chips item */ -export function CreateBreadCrumb( +export function createBreadCrumb( data: ICreateBreadCrumb, title: string, index: number, From d4eb4c20d057586355a1eca4844b78ab99418484 Mon Sep 17 00:00:00 2001 From: MaxOvs Date: Tue, 10 Jan 2023 14:33:09 +0300 Subject: [PATCH 10/21] Fix utils and interfaces --- src/cg-selectTS.ts | 25 ++++++--- src/components/utils/urils.interface.ts | 6 ++- src/components/utils/utilsTs.ts | 67 ++++++++++++++++++++++++- 3 files changed, 88 insertions(+), 10 deletions(-) diff --git a/src/cg-selectTS.ts b/src/cg-selectTS.ts index 4544967..2a2722c 100644 --- a/src/cg-selectTS.ts +++ b/src/cg-selectTS.ts @@ -6,13 +6,14 @@ import { import { ICreateBreadCrumb } from './components/create-element/create-element.interface'; import { + clearSelect, createSelected, getFormatItem, getSelectText, nativeOptionMultiple, nativeOptionOrdinary, } from './components/utils/utilsTs'; -import { IDataItem, ITextSelect } from './components/utils/urils.interface'; +import { IDataItem, ISelectedItems } from './components/utils/urils.interface'; import { ICgSelect } from './interfaces/cg-select.interface'; import { IItems } from './interfaces/items.interface'; @@ -284,12 +285,9 @@ export class CGSelect implements ICgSelect { const options = this.element?.querySelectorAll('.list__item'); const select: HTMLElement | null | undefined = this.element?.querySelector('.selected'); - const nativeOption = this.element?.querySelectorAll('.nativeSelect__nativeOption'); + const nativeOption = this.element!.querySelectorAll('.nativeSelect__nativeOption'); - const placeholderTextSelect: ITextSelect = { - placeholder: placeholder, - selected: selected, - }; + let selectedItemsClear: ISelectedItems; const ulMultipul = document.createElement('ul'); @@ -301,6 +299,17 @@ export class CGSelect implements ICgSelect { options?.forEach((option: Element, index: number) => { option.addEventListener('click', (event) => { + if (Array.isArray(this.selectedItems)) { + selectedItemsClear = { + placeholder: placeholder!, + selected: selected!, + selectedItems: this.selectedItems, + indexes: this.indexes, + darkTheme: darkTheme, + multiselectTag: multiselectTag, + }; + } + const item: IItems = this.itemsSelect[index]; const checkIndex = this.indexes.indexOf(index); @@ -360,7 +369,7 @@ export class CGSelect implements ICgSelect { } if (!this.selectedItems.length) { - getSelectText(placeholderTextSelect, select); + getSelectText(selectedItemsClear, select); } else { if (multiselectTag) { select!.appendChild(ulMultipul); @@ -382,6 +391,8 @@ export class CGSelect implements ICgSelect { }); option.classList.add('active'); } + + clearSelect(select!, this.element!, selectedItemsClear); }); }); } diff --git a/src/components/utils/urils.interface.ts b/src/components/utils/urils.interface.ts index f0cfad8..62ea811 100644 --- a/src/components/utils/urils.interface.ts +++ b/src/components/utils/urils.interface.ts @@ -6,7 +6,11 @@ export interface IDataItem { ItemValue: string | IItems | number; } -export interface ITextSelect { +export interface ISelectedItems { placeholder?: string; selected?: string; + selectedItems?: string[]; + indexes?: number[]; + multiselectTag?: boolean; + darkTheme?: boolean; } diff --git a/src/components/utils/utilsTs.ts b/src/components/utils/utilsTs.ts index 814e9e9..eca9b81 100644 --- a/src/components/utils/utilsTs.ts +++ b/src/components/utils/utilsTs.ts @@ -1,6 +1,6 @@ import { ICgSelect } from '../../interfaces/cg-select.interface'; import { IItems } from '../../interfaces/items.interface'; -import { IDataItem, ITextSelect } from './urils.interface'; +import { IDataItem, ISelectedItems } from './urils.interface'; /** * Преобразование каждого елемента полученного из поля Items; @@ -33,7 +33,7 @@ export function getFormatItem(dataItem: any, index: number): IItems { * @returns {HTMLElement} возвращает сформированный елемент селекта */ export function getSelectText( - data: ITextSelect, + data: ISelectedItems, select: HTMLElement | null | undefined, ): HTMLElement { const { placeholder, selected } = data; @@ -102,6 +102,69 @@ export function createSelected(element: Element | null, content?: string, styles // } } +/** + * Создание кнопки отчиски селекта, при единичном выборе. + * @param {HTMLElement} select место в селекте которое будет переназначено на ''. + * @param {Element} element экземпляр класса DropDown. + * @param {ISelectedItems} dataSelectText текст который отрисовывается в селекте. + */ +export function clearSelect(select: HTMLElement, element: Element, dataSelectText: ISelectedItems) { + const { selectedItems, indexes, darkTheme, multiselectTag } = dataSelectText; + + const options = element.querySelectorAll('.list__item'); + const ulMultiSelect = element.querySelector('.multiselect-tag'); + const svgIcon = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); + const path1 = document.createElementNS('http://www.w3.org/2000/svg', 'path'); + const path2 = document.createElementNS('http://www.w3.org/2000/svg', 'path'); + const checkBox = element.querySelectorAll('li input'); + + svgIcon.setAttribute('viewBox', '0 0 10 10'); + path1.setAttribute('d', 'M2,8 L8,2'); + path2.setAttribute('d', 'M2,2 L8,8'); + svgIcon.appendChild(path1); + svgIcon.appendChild(path2); + + if (multiselectTag) { + return; + } + + if (darkTheme === true || !darkTheme) { + path1.classList.add('pathWhite'); + path2.classList.add('pathWhite'); + } + + if (darkTheme === false) { + path1.classList.add('pathBlack'); + path2.classList.add('pathBlack'); + } + + svgIcon.classList.add('svg-icon'); + svgIcon.classList.add('svg-clear'); + + select!.appendChild(svgIcon); + + svgIcon.addEventListener('click', () => { + select!.innerText = ''; + + if (Array.isArray(selectedItems)) { + selectedItems!.splice(0); + indexes!.splice(0); + } + + checkBox.forEach((item) => { + if (item instanceof HTMLInputElement) { + item.checked = false; + } + }); + + getSelectText(dataSelectText, select); + + options.forEach((option) => { + option.classList.remove('active'); + }); + }); +} + /** * Поведение нативного(одинарного) селекта при выборе кастомного * @param {NodeList} element NodeList нативного селекта From 5b7b9c041ed3c74572add77eba3e0838c26fa742 Mon Sep 17 00:00:00 2001 From: MaxOvs Date: Tue, 10 Jan 2023 18:12:38 +0300 Subject: [PATCH 11/21] Fixed styles(TODO: styles in search mode) --- example/indexTs.ts | 39 +++++- src/cg-select.js | 2 +- src/cg-selectTS.ts | 178 ++++++++++++++++++++++++-- src/components/utils/utilsTs.ts | 39 ++++++ src/interfaces/cg-select.interface.ts | 11 +- 5 files changed, 248 insertions(+), 21 deletions(-) diff --git a/example/indexTs.ts b/example/indexTs.ts index d96c107..88d4c99 100644 --- a/example/indexTs.ts +++ b/example/indexTs.ts @@ -4,16 +4,41 @@ const dropdn = new CGSelect({ selector: '.cg-dropdown_one', placeholder: 'Выберите авто', items: [ - 'BMW', { - id: '213sade', - title: 'Opel', - value: 'ds', + category: 'Russia', + categoryItems: [ + { + id: '28qwds', + title: 'Москва', + value: 0, + }, + , + 'Ростов-на-дону', + 'Саратов', + 'Волгоград', + 'Донецк', + ], + }, + { + category: 'USA', + categoryItems: ['Alabama', 'Texas', 'Colorado', 'Klirens', 'Los-Angeles'], + }, + { + category: 'France', + categoryItems: ['Paris'], }, - 'Mersedes', - 'MAN', - 'Ferari', ], + styles: { + head: { + width: '830px', + }, + list: { + width: '824px', + }, + placeholder: { + maxWidth: '500px ', + }, + }, multiselect: true, multiselectTag: true, }); diff --git a/src/cg-select.js b/src/cg-select.js index 96bf00c..3230143 100644 --- a/src/cg-select.js +++ b/src/cg-select.js @@ -548,7 +548,7 @@ export class DropDown { /** * Приватный метод рендера экземпляра класса DropDown - *@protected + * @protected * @method #renderUrl * @description Рендер елементов в селекте переданных с URL и их настойка */ diff --git a/src/cg-selectTS.ts b/src/cg-selectTS.ts index 2a2722c..51b230c 100644 --- a/src/cg-selectTS.ts +++ b/src/cg-selectTS.ts @@ -8,6 +8,8 @@ import { ICreateBreadCrumb } from './components/create-element/create-element.in import { clearSelect, createSelected, + customStyles, + customStylesFormat, getFormatItem, getSelectText, nativeOptionMultiple, @@ -15,7 +17,7 @@ import { } from './components/utils/utilsTs'; import { IDataItem, ISelectedItems } from './components/utils/urils.interface'; -import { ICgSelect } from './interfaces/cg-select.interface'; +import { ICgSelect, IStyle } from './interfaces/cg-select.interface'; import { IItems } from './interfaces/items.interface'; import './main.scss'; @@ -32,7 +34,7 @@ export class CGSelect implements ICgSelect { listDisplayMode?: boolean; language?: string; lable?: string; - styles?: object; + styles?: IStyle; event?: string; url?: string; multiselect?: boolean; @@ -104,15 +106,25 @@ export class CGSelect implements ICgSelect { items.forEach((dataItem: any, index: number) => { let itemInputs: IDataItem = { ItemValue: dataItem, + // category: dataItem.category, + // categoryItems: dataItem.categoryItems, }; - this.itemsSelect.push(getFormatItem(itemInputs.ItemValue, index)); + if (dataItem.category && dataItem.categoryItems) { + this.category = dataItem.category!; + this.itemsSelect.push(this.category); + dataItem.categoryItems.forEach((categoryItem, indexCategory) => { + this.itemsSelect.push(getFormatItem(categoryItem, indexCategory)); + }); + } else { + this.itemsSelect.push(getFormatItem(itemInputs.ItemValue, index)); + } }); } /** * Приватный метод рендера экземпляра класса DropDown - *@protected + * @protected * @method render * @param {string} select необязательный елемент. Передаеться в метод initSelected * @description Рендер елементов в селекте. @@ -131,7 +143,12 @@ export class CGSelect implements ICgSelect { const random = Math.random().toString(36).substring(2, 10); - this.initSelected(); + if (select || (select && styles)) { + this.initSelected(select); + customStyles(this.element!, styles); + } else { + this.initSelected(); + } const ulList = document.createElement('ul'); const nativeSelect = createNativeSelect(); @@ -143,6 +160,11 @@ export class CGSelect implements ICgSelect { ulList.classList.add('list'); + if (styles) { + const { list } = styles; + customStylesFormat(list!, ulList); + } + this.element?.appendChild(ulList); this.itemsSelect.forEach((dataItem: IItems | any) => { @@ -184,13 +206,98 @@ export class CGSelect implements ICgSelect { } }); + this.itemsSelect.filter((item, index) => { + if (typeof item !== 'object') { + this.itemsSelect.splice(index, 1); + } + return item; + }); + + if (darkTheme == false) { + this.checkTheme(); + } + + if (nativeSelectMode === true) { + // this.#selectMode(nativeSelectMode); + } + this.list = this.element?.querySelector('.list'); this.caret = this.element?.querySelector('.caret'); this.addOptionsBehaviour(); } - private renderUrl() {} + /** + * Приватный метод рендера экземпляра класса DropDown + * @protected + * @method renderUrl + * @description Рендер елементов в селекте переданных с URL и их настойка + */ + private async renderUrl() { + const { url, items, multiselect, multiselectTag } = this.options; + + if (items) { + return; + } + + if (!url) { + return; + } + + const response = await fetch(url); + const dataUrl = await response.json(); + + const nativeSelect = createNativeSelect(); + + dataUrl.forEach((dataItem: IItems, index: number) => { + const item = { + id: dataItem.id, + title: dataItem.title, + value: index, + }; + + const ulUrl = this.element!.querySelector('.list'); + + const nativeOption = createNativeSelectOption(); + const liUrl = document.createElement('li'); + const textUrl = document.createTextNode(item.title); + + if (multiselect) { + const checkBox = document.createElement('input'); + checkBox.type = 'checkbox'; + + if (multiselectTag) { + checkBox.classList.add('displayHide'); + } + + checkBox.setAttribute('id', `chbox-${item.id}`); + nativeSelect.setAttribute('multiple', 'multiple'); + + liUrl.appendChild(checkBox); + } + + liUrl.classList.add('list__item'); + nativeOption.value = item.title; + nativeOption.text = item.title; + + nativeSelect.appendChild(nativeOption); + liUrl.appendChild(textUrl); + ulUrl!.appendChild(liUrl); + + this.itemsSelect.push(item); + }); + + this.element!.appendChild(nativeSelect); + + this.itemsSelect.filter((item, index) => { + if (typeof item !== 'object') { + this.itemsSelect.splice(index, 1); + } + return item; + }); + + this.addOptionsBehaviour(); + } /** * Привaтный метод экземпляра класса DropDown @@ -208,11 +315,29 @@ export class CGSelect implements ICgSelect { } else if (placeholder) { createSelected(this.element, placeholder); } else { - // if (language && language === 'ru') { - // createSelected(this.#element, ru.selectPlaceholder); - // } else { - // createSelected(this.#element, en.selectPlaceholder); - // } + if (language && language === 'ru') { + // createSelected(this.#element, ru.selectPlaceholder); + } else { + // createSelected(this.#element, en.selectPlaceholder); + } + } + + if (select) { + createSelected(this.element, select, styles); + } + + if (lable) { + const lableItem = document.createElement('h1'); + const textLable = document.createTextNode(lable); + + lableItem.appendChild(textLable); + lableItem.classList.add('label'); + + this.element!.insertAdjacentElement('beforebegin', lableItem); + } + + if (styles) { + customStyles(this.element!, styles); } } @@ -237,7 +362,7 @@ export class CGSelect implements ICgSelect { * Приватный метод экземпляра класса DropDown * @protected * @description Закрывает список - * @method #close + * @method close */ private close(): void { this.list?.classList.remove('open'); @@ -396,4 +521,33 @@ export class CGSelect implements ICgSelect { }); }); } + + /** + * Приватный метод рендера экземпляра класса DropDown + * @protected + * @method #checkTheme + * @description Изменяет цветовую схему с темной на светлую. + */ + private checkTheme(): void { + const { darkTheme, searchMode } = this.options; + + const select = this.element!.querySelector('.cg-select'); + const caret = this.element!.querySelector('.caret'); + const list = this.element!.querySelector('ul.list'); + const search = this.element!.querySelector('.inputSearch'); + + if (darkTheme == false) { + select!.classList.add('selectWhite'); + caret!.classList.add('caretWhite'); + list!.classList.add('listWhite'); + + if (searchMode == true) { + search!.classList.add('inputWhite'); + } + } else if (darkTheme == true || !darkTheme) { + return; + } else { + throw new Error('Styles error or invalid value entered!'); + } + } } diff --git a/src/components/utils/utilsTs.ts b/src/components/utils/utilsTs.ts index eca9b81..4c82a65 100644 --- a/src/components/utils/utilsTs.ts +++ b/src/components/utils/utilsTs.ts @@ -204,3 +204,42 @@ export function nativeOptionMultiple( } }); } + +/** + * Поиск и стилизация елементов полученных из styles экземпляра DropDown + * @param {Element} element созданный экземпляр класса DropDown + * @param {object} styles объект в котором находяться настройки кастомизации частей селекта + */ +export function customStyles(element: Element, styles: any) { + if (!styles) { + return; + } + + const { head, caret, placeholder, lable } = styles; + + const cgSelect = element.querySelector('.cg-select'); + const caretSelect = element.querySelector('.caret'); + const placeholderSelect = element.querySelector('.selected'); + const lableItem = element.parentElement!.querySelector('h1.label'); + + customStylesFormat(head, cgSelect!); + customStylesFormat(caret, caretSelect!); + customStylesFormat(lable, lableItem!); + + if (placeholderSelect) { + customStylesFormat(placeholder, placeholderSelect); + } +} + +/** + * Универсальный метод для стилизации селекта + * @param {object} elemOption объект полученное из объекта styles у которого мы получаем ключ-значение стилей + * @param {HTMLElement} selector HTMLElement подвергающиеся кастомизации + */ +export function customStylesFormat(elemOption: object, selector: any) { + if (elemOption) { + Object.entries(elemOption).forEach(([key, value]) => { + selector.style[key] = value; + }); + } +} diff --git a/src/interfaces/cg-select.interface.ts b/src/interfaces/cg-select.interface.ts index fe0d651..b2cb7f6 100644 --- a/src/interfaces/cg-select.interface.ts +++ b/src/interfaces/cg-select.interface.ts @@ -12,9 +12,18 @@ export interface ICgSelect { listDisplayMode?: boolean; language?: string; lable?: string; - styles?: object; + styles?: IStyle; event?: string; url?: string; multiselect?: boolean; multiselectTag?: boolean; } + +export interface IStyle { + head?: object; + caret?: object; + placeholder?: object; + lable?: object; + list?: object; + search?: object; +} From 7b057ab4865e6331d9a9bce2646a005e72e79ef6 Mon Sep 17 00:00:00 2001 From: MaxOvs Date: Wed, 11 Jan 2023 17:45:29 +0300 Subject: [PATCH 12/21] Added initevent, displayMode etc. Fixed searchMode --- example/indexTs.ts | 5 + src/cg-selectTS.ts | 168 +++++++++++++++++- .../create-element/create-elementTs.ts | 26 +++ 3 files changed, 195 insertions(+), 4 deletions(-) diff --git a/example/indexTs.ts b/example/indexTs.ts index 88d4c99..5714a9f 100644 --- a/example/indexTs.ts +++ b/example/indexTs.ts @@ -39,6 +39,11 @@ const dropdn = new CGSelect({ maxWidth: '500px ', }, }, + // url + // listDisplayMode: true, + // searchMode: true, + // nativeSelectMode: true + // event: 'mouseenter', multiselect: true, multiselectTag: true, }); diff --git a/src/cg-selectTS.ts b/src/cg-selectTS.ts index 51b230c..69efdf8 100644 --- a/src/cg-selectTS.ts +++ b/src/cg-selectTS.ts @@ -1,5 +1,6 @@ import { createBreadCrumb, + createInputSearch, createNativeSelect, createNativeSelectOption, } from './components/create-element/create-elementTs'; @@ -19,6 +20,7 @@ import { IDataItem, ISelectedItems } from './components/utils/urils.interface'; import { ICgSelect, IStyle } from './interfaces/cg-select.interface'; import { IItems } from './interfaces/items.interface'; +import { ru, en } from './language/language'; import './main.scss'; @@ -54,6 +56,7 @@ export class CGSelect implements ICgSelect { this.init(setting); this.render(); this.closeSelectClick(); + this.initEvent(); } /** @@ -153,7 +156,7 @@ export class CGSelect implements ICgSelect { const ulList = document.createElement('ul'); const nativeSelect = createNativeSelect(); - let inputSearch: string = ''; + let inputSearch: HTMLInputElement; let textNode: Text; this.randomId = random; @@ -165,6 +168,18 @@ export class CGSelect implements ICgSelect { customStylesFormat(list!, ulList); } + if (searchMode) { + if (language === 'ru') { + inputSearch = createInputSearch(random, ru.placeholder); + } else { + inputSearch = createInputSearch(random, en.placeholder); + } + + const { search } = styles!; + customStylesFormat(search!, inputSearch); + ulList.appendChild(inputSearch); + } + this.element?.appendChild(ulList); this.itemsSelect.forEach((dataItem: IItems | any) => { @@ -213,16 +228,20 @@ export class CGSelect implements ICgSelect { return item; }); + this.list = this.element!.querySelector('.list'); + this.caret = this.element!.querySelector('.caret'); + if (darkTheme == false) { this.checkTheme(); } if (nativeSelectMode === true) { - // this.#selectMode(nativeSelectMode); + this.selectMode(nativeSelectMode); } - this.list = this.element?.querySelector('.list'); - this.caret = this.element?.querySelector('.caret'); + if (listDisplayMode) { + this.displayMode(listDisplayMode); + } this.addOptionsBehaviour(); } @@ -341,6 +360,30 @@ export class CGSelect implements ICgSelect { } } + /** + * Приватный метод экземпляра класса DropDown + * @protected + * @description Открывает и закрывает список по переданному эвенту + * @method initEvent + */ + private initEvent() { + const { event } = this.options; + if (!event) { + return; + } + + if (event) { + if (event === 'mouseenter') { + this.element!.addEventListener(event, () => { + this.open(); + }); + this.element!.addEventListener('mouseleave', () => { + this.close(); + }); + } + } + } + /** * Приватный метод экземпляра класса DropDown * @protected @@ -422,6 +465,10 @@ export class CGSelect implements ICgSelect { select?.classList.add('overflow-hidden'); } + if (searchMode) { + this.searchModeSelect(this.randomId); + } + options?.forEach((option: Element, index: number) => { option.addEventListener('click', (event) => { if (Array.isArray(this.selectedItems)) { @@ -550,4 +597,117 @@ export class CGSelect implements ICgSelect { throw new Error('Styles error or invalid value entered!'); } } + + /** + * Приватный метод экземпляра класса DropDown + * @protected + * @param {boolean} nativeSelectMode параметр отвечающий за добавления нативного селекта. + * @description Изменяет отображение селекта на мобильных устройствах + * @method selectMode + */ + private selectMode(nativeSelectMode: boolean) { + let win = window.outerWidth; + + if (nativeSelectMode === true) { + const select = this.element!.querySelector('.cg-select'); + const list = this.element!.querySelector('.list'); + const nativeSelect = this.element!.querySelector('.nativeSelect'); + + if (win < 576) { + select!.classList.add('displayHide'); + list!.classList.add('displayHide'); + nativeSelect!.classList.add('nativeSelectActive'); + } else if (win > 576) { + select!.classList.remove('displayHide'); + list!.classList.remove('displayHide'); + nativeSelect!.classList.remove('nativeSelectActive'); + nativeSelect!.classList.add('displayHide'); + } + } else { + return; + } + } + + /** + * Приватный метод экземпляра класса DropDown + * @protected + * @param {boolean} listDisplayMode параметр отвечающий за отображение выбора в виде модального окна. + * @description Изменяет отображение листа с выбором в виде модального окна. + * @method displayMode + */ + private displayMode(listDisplayMode: boolean): void { + if (listDisplayMode) { + const modal = document.createElement('div'); + const body = document.querySelector('body'); + const list = this.list!; + + modal.appendChild(list); + this.element!.appendChild(modal); + + this.element!.addEventListener('click', () => { + modal.classList.toggle('modal'); + list.classList.toggle('listModal'); + body!.classList.toggle('overflowHide'); + }); + } else { + return; + } + } + + /** + * Метод который реализует поиск элементов в селекте + * @protected + * @param {string} random уникальное значение для input элемента. + * @method searchMode + */ + private searchModeSelect(random: string) { + const { language } = this.options; + + const input = this.element!.querySelector(`#searchSelect-${random}`) as HTMLInputElement; + const searchSelect = this.element!.querySelectorAll('.list__item'); + const result = document.createElement('p'); + + let textNode: Text; + if (language && language === 'ru') { + textNode = document.createTextNode(`${ru.textInListSearch}`); + } else { + textNode = document.createTextNode(`${en.textInListSearch}`); + } + + result.appendChild(textNode); + result.classList.add('displayHide'); + result.classList.add('noRezult'); + input!.parentElement!.appendChild(result); + + input!.addEventListener('click', (e) => { + e.stopPropagation(); + }); + + if (input instanceof HTMLInputElement) { + input!.oninput = function () { + let valueSearch: string = input.value.trim().toLowerCase(); + let anyMatch = false; + + if (valueSearch != '') { + searchSelect.forEach((elem) => { + let isMatching = new RegExp(valueSearch, 'gi').test(elem.textContent!); + anyMatch = anyMatch || isMatching; + + if (elem.textContent!.toLowerCase().search(valueSearch) == -1) { + elem.classList.add('displayHide'); + } else { + elem.classList.remove('displayHide'); + } + }); + + result.classList.toggle('displayHide', anyMatch); + } else { + searchSelect.forEach((elem) => { + elem.classList.remove('displayHide'); + result.classList.add('displayHide'); + }); + } + }; + } + } } diff --git a/src/components/create-element/create-elementTs.ts b/src/components/create-element/create-elementTs.ts index 5c5278f..83786c2 100644 --- a/src/components/create-element/create-elementTs.ts +++ b/src/components/create-element/create-elementTs.ts @@ -96,3 +96,29 @@ export function createBreadCrumb( return liChip; } + +/** + * Метод который создает поиск элементов в селекте + * @param {string} random уникальное значение для input элемента. + * @param {string} lenguage текст на определенном языке переданный из файла language.js + * @returns {HTMLInputElement} Возвращает сформированный input елемент. + */ +export function createInputSearch(random: string, lenguage: string): HTMLInputElement { + const inputSearch = document.createElement('input'); + + inputSearch.type = 'text'; + inputSearch.classList.add('inputSearch'); + inputSearch.setAttribute('id', `searchSelect-${random}`); + + if (lenguage) { + inputSearch.setAttribute('placeholder', `${lenguage}`); + } else { + inputSearch.setAttribute('placeholder', 'Search...'); + } + + inputSearch.addEventListener('click', (e) => { + e.preventDefault(); + }); + + return inputSearch; +} From f72084e44e8492741f4e08aaa0242e3c6c802627 Mon Sep 17 00:00:00 2001 From: MaxOvs Date: Wed, 11 Jan 2023 18:41:33 +0300 Subject: [PATCH 13/21] Added public methods and fixed bugs --- src/cg-selectTS.ts | 109 ++++++++++++++++++++------- src/interfaces/language.interface.ts | 5 ++ src/language/languageTS.ts | 13 ++++ 3 files changed, 100 insertions(+), 27 deletions(-) create mode 100644 src/interfaces/language.interface.ts create mode 100644 src/language/languageTS.ts diff --git a/src/cg-selectTS.ts b/src/cg-selectTS.ts index 69efdf8..4738298 100644 --- a/src/cg-selectTS.ts +++ b/src/cg-selectTS.ts @@ -20,7 +20,8 @@ import { IDataItem, ISelectedItems } from './components/utils/urils.interface'; import { ICgSelect, IStyle } from './interfaces/cg-select.interface'; import { IItems } from './interfaces/items.interface'; -import { ru, en } from './language/language'; +import { ru, en } from './language/languageTS'; +import { ILanguage } from './interfaces/language.interface'; import './main.scss'; @@ -628,32 +629,6 @@ export class CGSelect implements ICgSelect { } } - /** - * Приватный метод экземпляра класса DropDown - * @protected - * @param {boolean} listDisplayMode параметр отвечающий за отображение выбора в виде модального окна. - * @description Изменяет отображение листа с выбором в виде модального окна. - * @method displayMode - */ - private displayMode(listDisplayMode: boolean): void { - if (listDisplayMode) { - const modal = document.createElement('div'); - const body = document.querySelector('body'); - const list = this.list!; - - modal.appendChild(list); - this.element!.appendChild(modal); - - this.element!.addEventListener('click', () => { - modal.classList.toggle('modal'); - list.classList.toggle('listModal'); - body!.classList.toggle('overflowHide'); - }); - } else { - return; - } - } - /** * Метод который реализует поиск элементов в селекте * @protected @@ -710,4 +685,84 @@ export class CGSelect implements ICgSelect { }; } } + + /** + * Приватный метод экземпляра класса DropDown + * @protected + * @param {boolean} listDisplayMode параметр отвечающий за отображение выбора в виде модального окна. + * @description Изменяет отображение листа с выбором в виде модального окна. + * @method displayMode + */ + private displayMode(listDisplayMode: boolean): void { + if (listDisplayMode) { + const modal = document.createElement('div'); + const body = document.querySelector('body'); + const list = this.list!; + + modal.appendChild(list); + this.element!.appendChild(modal); + + this.element!.addEventListener('click', () => { + modal.classList.toggle('modal'); + list.classList.toggle('listModal'); + body!.classList.toggle('overflowHide'); + }); + } else { + return; + } + } + + // Public methods + /** + * Метод экземпляра класса DropDown + * @param {object} language объект в котором находятся поля для подключения языка имеет два обязательных поля placeholder, textInListSearch + * @description метод позволяющий заменить плейсхолдер в поиске и текст который выводится если нет результата + * @method addLanguage + */ + public addLanguage(language: ILanguage) { + const { placeholder, textInListSearch, selectPlaceholder } = language; + const { searchMode } = this.options; + + const select = this.element!.querySelector('.selected'); + const textNodeSelect = document.createTextNode(selectPlaceholder); + select!.appendChild(textNodeSelect); + + if (searchMode) { + const search = this.element!.querySelector('.inputSearch'); + const textNoRezult = this.element!.querySelector('.noRezult'); + const textNode = document.createTextNode(textInListSearch); + + search!.setAttribute('placeholder', placeholder); + search!.setAttribute('placeholder', placeholder); + + textNoRezult!.textContent = ''; + textNoRezult!.appendChild(textNode); + } + } + + /** + * Метод экземпляра класса DropDown + * @param {HTMLInputElement} button - HTML кнопка + * @param {string} method - метод открытия open/close + * @description Метод позволяющий открывать/закрывать селект с помощью кнопок + * @method buttonControl + */ + public buttonControl(button, method: string) { + const { listDisplayMode } = this.options; + + if (listDisplayMode === true) { + return; + } + + // this.btn = button; + button.addEventListener('click', () => { + if (method.toLowerCase() === 'open') { + this.open(true); + } else if (method.toLowerCase() === 'close') { + this.close(); + } else { + return; + } + }); + } } diff --git a/src/interfaces/language.interface.ts b/src/interfaces/language.interface.ts new file mode 100644 index 0000000..ffaaf2a --- /dev/null +++ b/src/interfaces/language.interface.ts @@ -0,0 +1,5 @@ +export interface ILanguage { + placeholder: string; + selectPlaceholder: string; + textInListSearch: string; +} diff --git a/src/language/languageTS.ts b/src/language/languageTS.ts new file mode 100644 index 0000000..41212b9 --- /dev/null +++ b/src/language/languageTS.ts @@ -0,0 +1,13 @@ +import { ILanguage } from '../interfaces/language.interface'; + +export const ru: ILanguage = { + selectPlaceholder: 'Выберите элемент...', + placeholder: 'Поиск...', + textInListSearch: 'Совпадений нет...', +}; + +export const en: ILanguage = { + selectPlaceholder: 'Select element...', + placeholder: 'Search...', + textInListSearch: 'No matches...', +}; From 994a1e972d7f074c131ea312ce7649e7c80db4fa Mon Sep 17 00:00:00 2001 From: MaxOvs Date: Thu, 12 Jan 2023 16:23:49 +0300 Subject: [PATCH 14/21] Fixed variables in main class --- example/indexTs.ts | 1 + src/cg-selectTS.ts | 226 +++++++++++++++++--------------- src/components/utils/utilsTs.ts | 2 +- 3 files changed, 122 insertions(+), 107 deletions(-) diff --git a/example/indexTs.ts b/example/indexTs.ts index 5714a9f..ce8f715 100644 --- a/example/indexTs.ts +++ b/example/indexTs.ts @@ -44,6 +44,7 @@ const dropdn = new CGSelect({ // searchMode: true, // nativeSelectMode: true // event: 'mouseenter', + // buttonControl multiselect: true, multiselectTag: true, }); diff --git a/src/cg-selectTS.ts b/src/cg-selectTS.ts index 4738298..d25dd38 100644 --- a/src/cg-selectTS.ts +++ b/src/cg-selectTS.ts @@ -26,6 +26,7 @@ import { ILanguage } from './interfaces/language.interface'; import './main.scss'; export class CGSelect implements ICgSelect { + // Настройки селекта selector: string; selected?: string; placeholder?: string; @@ -43,6 +44,7 @@ export class CGSelect implements ICgSelect { multiselect?: boolean; multiselectTag?: boolean; + // Переменные и комплектующие селекта private element: Element | null; private list: Element | null | undefined; private options: ICgSelect; @@ -50,8 +52,8 @@ export class CGSelect implements ICgSelect { private caret: Element | null | undefined; private category: string; private selectedItems: string[] | string; - private itemsSelect: IItems[] | string[] | any; private indexes: number[] = []; + private btnCntr: Element | null; constructor(setting: ICgSelect) { this.init(setting); @@ -88,11 +90,43 @@ export class CGSelect implements ICgSelect { } */ private init(setting: ICgSelect): void { - const { items, multiselect, url, selector } = setting; + const { + items, + multiselect, + multiselectTag, + url, + selector, + listDisplayMode, + nativeSelectMode, + searchMode, + darkTheme, + language, + styles, + lable, + event, + selected, + placeholder, + } = setting; this.options = setting; - const elem = document.querySelector(selector); + this.multiselect = multiselect; + this.multiselectTag = multiselectTag; + this.url = url; + this.selector = selector; + this.items = items; + this.searchMode = searchMode; + this.darkTheme = darkTheme; + this.language = language; + this.nativeSelectMode = nativeSelectMode; + this.listDisplayMode = listDisplayMode; + this.styles = styles; + this.lable = lable; + this.event = event; + this.selected = selected; + this.placeholder = placeholder; + + const elem = document.querySelector(this.selector); this.element = elem; this.element?.addEventListener('click', (e) => { @@ -100,9 +134,9 @@ export class CGSelect implements ICgSelect { this.open(); }); - this.itemsSelect = []; + this.items = []; - if (!items && url) { + if (!this.items && this.url) { this.renderUrl(); return; } @@ -116,12 +150,12 @@ export class CGSelect implements ICgSelect { if (dataItem.category && dataItem.categoryItems) { this.category = dataItem.category!; - this.itemsSelect.push(this.category); - dataItem.categoryItems.forEach((categoryItem, indexCategory) => { - this.itemsSelect.push(getFormatItem(categoryItem, indexCategory)); + this.items.push(this.category); + dataItem.categoryItems.forEach((categoryItem, indexCategory: number) => { + this.items.push(getFormatItem(categoryItem, indexCategory)); }); } else { - this.itemsSelect.push(getFormatItem(itemInputs.ItemValue, index)); + this.items.push(getFormatItem(itemInputs.ItemValue, index)); } }); } @@ -134,16 +168,7 @@ export class CGSelect implements ICgSelect { * @description Рендер елементов в селекте. */ private render(select?: string): void { - const { - styles, - multiselect, - searchMode, - multiselectTag, - darkTheme, - language, - nativeSelectMode, - listDisplayMode, - } = this.options; + const { styles } = this.options; const random = Math.random().toString(36).substring(2, 10); @@ -169,8 +194,8 @@ export class CGSelect implements ICgSelect { customStylesFormat(list!, ulList); } - if (searchMode) { - if (language === 'ru') { + if (this.searchMode) { + if (this.language === 'ru') { inputSearch = createInputSearch(random, ru.placeholder); } else { inputSearch = createInputSearch(random, en.placeholder); @@ -183,7 +208,7 @@ export class CGSelect implements ICgSelect { this.element?.appendChild(ulList); - this.itemsSelect.forEach((dataItem: IItems | any) => { + this.items.forEach((dataItem: IItems | any) => { this.element?.appendChild(nativeSelect); const liItem = document.createElement('li'); @@ -193,13 +218,13 @@ export class CGSelect implements ICgSelect { liItem.classList.add('list__item'); strongItem.classList.add('category'); - if (multiselect) { + if (this.multiselect) { const checkBox = document.createElement('input'); checkBox.type = 'checkbox'; checkBox.setAttribute('id', `chbox-${dataItem.id}`); liItem.appendChild(checkBox); - if (multiselectTag) { + if (this.multiselectTag) { checkBox.classList.add('displayHide'); } @@ -222,9 +247,9 @@ export class CGSelect implements ICgSelect { } }); - this.itemsSelect.filter((item, index) => { + this.items.filter((item, index) => { if (typeof item !== 'object') { - this.itemsSelect.splice(index, 1); + this.items.splice(index, 1); } return item; }); @@ -232,16 +257,16 @@ export class CGSelect implements ICgSelect { this.list = this.element!.querySelector('.list'); this.caret = this.element!.querySelector('.caret'); - if (darkTheme == false) { + if (this.darkTheme == false) { this.checkTheme(); } - if (nativeSelectMode === true) { - this.selectMode(nativeSelectMode); + if (this.nativeSelectMode === true) { + this.selectMode(this.nativeSelectMode); } - if (listDisplayMode) { - this.displayMode(listDisplayMode); + if (this.listDisplayMode) { + this.displayMode(this.listDisplayMode); } this.addOptionsBehaviour(); @@ -254,17 +279,11 @@ export class CGSelect implements ICgSelect { * @description Рендер елементов в селекте переданных с URL и их настойка */ private async renderUrl() { - const { url, items, multiselect, multiselectTag } = this.options; - - if (items) { + if (this.items || !this.url) { return; } - if (!url) { - return; - } - - const response = await fetch(url); + const response = await fetch(this.url); const dataUrl = await response.json(); const nativeSelect = createNativeSelect(); @@ -282,11 +301,11 @@ export class CGSelect implements ICgSelect { const liUrl = document.createElement('li'); const textUrl = document.createTextNode(item.title); - if (multiselect) { + if (this.multiselect) { const checkBox = document.createElement('input'); checkBox.type = 'checkbox'; - if (multiselectTag) { + if (this.multiselectTag) { checkBox.classList.add('displayHide'); } @@ -304,14 +323,14 @@ export class CGSelect implements ICgSelect { liUrl.appendChild(textUrl); ulUrl!.appendChild(liUrl); - this.itemsSelect.push(item); + this.items.push(item); }); this.element!.appendChild(nativeSelect); - this.itemsSelect.filter((item, index) => { + this.items.filter((item, index) => { if (typeof item !== 'object') { - this.itemsSelect.splice(index, 1); + this.items.splice(index, 1); } return item; }); @@ -328,17 +347,17 @@ export class CGSelect implements ICgSelect { * @protected */ private initSelected(select?: string): void { - const { styles, selected, placeholder, lable, language } = this.options; + const { styles } = this.options; - if (selected) { - createSelected(this.element, selected); - } else if (placeholder) { - createSelected(this.element, placeholder); + if (this.selected) { + createSelected(this.element, this.selected); + } else if (this.placeholder) { + createSelected(this.element, this.placeholder); } else { - if (language && language === 'ru') { - // createSelected(this.#element, ru.selectPlaceholder); + if (this.language && this.language === 'ru') { + createSelected(this.element, ru.selectPlaceholder); } else { - // createSelected(this.#element, en.selectPlaceholder); + createSelected(this.element, en.selectPlaceholder); } } @@ -346,9 +365,9 @@ export class CGSelect implements ICgSelect { createSelected(this.element, select, styles); } - if (lable) { + if (this.lable) { const lableItem = document.createElement('h1'); - const textLable = document.createTextNode(lable); + const textLable = document.createTextNode(this.lable); lableItem.appendChild(textLable); lableItem.classList.add('label'); @@ -368,14 +387,13 @@ export class CGSelect implements ICgSelect { * @method initEvent */ private initEvent() { - const { event } = this.options; - if (!event) { + if (!this.event) { return; } - if (event) { - if (event === 'mouseenter') { - this.element!.addEventListener(event, () => { + if (this.event) { + if (this.event === 'mouseenter') { + this.element!.addEventListener(this.event, () => { this.open(); }); this.element!.addEventListener('mouseleave', () => { @@ -394,11 +412,11 @@ export class CGSelect implements ICgSelect { */ private open(oneClick?: boolean): void { if (oneClick === true) { - this.list?.classList.add('open'); - this.caret?.classList.add('caret_rotate'); + this.list!.classList.add('open'); + this.caret!.classList.add('caret_rotate'); } else { - this.list?.classList.toggle('open'); - this.caret?.classList.toggle('caret_rotate'); + this.list!.classList.toggle('open'); + this.caret!.classList.toggle('caret_rotate'); } } @@ -425,12 +443,11 @@ export class CGSelect implements ICgSelect { document.addEventListener('click', (e) => { const withinBoundaries = e.composedPath().includes(dropdown!); if (!withinBoundaries) { - // if (this.btn) { - // return; - // } else { - // this.#close(); - // } - this.close(); + if (this.btnCntr) { + return; + } else { + this.close(); + } } }); } @@ -442,16 +459,6 @@ export class CGSelect implements ICgSelect { * @method addOptionsBehaviour */ private addOptionsBehaviour() { - const { - multiselect, - placeholder, - selected, - multiselectTag, - searchMode, - closeOnSelect, - darkTheme, - } = this.options; - const options = this.element?.querySelectorAll('.list__item'); const select: HTMLElement | null | undefined = this.element?.querySelector('.selected'); const nativeOption = this.element!.querySelectorAll('.nativeSelect__nativeOption'); @@ -460,13 +467,13 @@ export class CGSelect implements ICgSelect { const ulMultipul = document.createElement('ul'); - if (multiselect) { + if (this.multiselect) { this.selectedItems = []; ulMultipul.classList.add('multiselect-tag'); select?.classList.add('overflow-hidden'); } - if (searchMode) { + if (this.searchMode) { this.searchModeSelect(this.randomId); } @@ -474,25 +481,25 @@ export class CGSelect implements ICgSelect { option.addEventListener('click', (event) => { if (Array.isArray(this.selectedItems)) { selectedItemsClear = { - placeholder: placeholder!, - selected: selected!, + placeholder: this.placeholder!, + selected: this.selected!, selectedItems: this.selectedItems, indexes: this.indexes, - darkTheme: darkTheme, - multiselectTag: multiselectTag, + darkTheme: this.darkTheme, + multiselectTag: this.multiselectTag, }; } - const item: IItems = this.itemsSelect[index]; + const item: IItems = this.items[index]; const checkIndex = this.indexes.indexOf(index); - if (closeOnSelect == false || multiselect) { + if (this.closeOnSelect == false || this.multiselect) { event.stopPropagation(); event.preventDefault(); } - if (multiselect) { + if (this.multiselect) { option.classList.toggle('active'); const checkBox: HTMLInputElement | null = option.querySelector('input[type="checkbox"]'); @@ -507,7 +514,7 @@ export class CGSelect implements ICgSelect { nativeOptionMultiple(nativeOption, item.title, true); select!.textContent = ''; - if (multiselectTag) { + if (this.multiselectTag) { if (Array.isArray(this.selectedItems)) { const dataBreadCrumb: ICreateBreadCrumb = { option: this.options, @@ -529,7 +536,7 @@ export class CGSelect implements ICgSelect { } } } else { - if (multiselectTag) { + if (this.multiselectTag) { const tagItem = document.getElementById(`tag-${index}-${item.id}`); ulMultipul.removeChild(tagItem!); } @@ -544,7 +551,7 @@ export class CGSelect implements ICgSelect { if (!this.selectedItems.length) { getSelectText(selectedItemsClear, select); } else { - if (multiselectTag) { + if (this.multiselectTag) { select!.appendChild(ulMultipul); } else { if (Array.isArray(this.selectedItems)) { @@ -577,22 +584,20 @@ export class CGSelect implements ICgSelect { * @description Изменяет цветовую схему с темной на светлую. */ private checkTheme(): void { - const { darkTheme, searchMode } = this.options; - const select = this.element!.querySelector('.cg-select'); const caret = this.element!.querySelector('.caret'); const list = this.element!.querySelector('ul.list'); const search = this.element!.querySelector('.inputSearch'); - if (darkTheme == false) { + if (this.darkTheme == false) { select!.classList.add('selectWhite'); caret!.classList.add('caretWhite'); list!.classList.add('listWhite'); - if (searchMode == true) { + if (this.searchMode == true) { search!.classList.add('inputWhite'); } - } else if (darkTheme == true || !darkTheme) { + } else if (this.darkTheme == true) { return; } else { throw new Error('Styles error or invalid value entered!'); @@ -636,14 +641,12 @@ export class CGSelect implements ICgSelect { * @method searchMode */ private searchModeSelect(random: string) { - const { language } = this.options; - const input = this.element!.querySelector(`#searchSelect-${random}`) as HTMLInputElement; const searchSelect = this.element!.querySelectorAll('.list__item'); const result = document.createElement('p'); let textNode: Text; - if (language && language === 'ru') { + if (this.language && this.language === 'ru') { textNode = document.createTextNode(`${ru.textInListSearch}`); } else { textNode = document.createTextNode(`${en.textInListSearch}`); @@ -713,6 +716,20 @@ export class CGSelect implements ICgSelect { } // Public methods + /** + * Метод экземпляра класса DropDown + * @param {number} numberItem номер возвращаемого элемента + * @returns {HTMLElement} возвращает ссылку на выбранный HTML элемент + * @method getElement + */ + public getElement(numberItem: number) { + if (numberItem > this.items.length) { + return; + } + + return this.items[numberItem]; + } + /** * Метод экземпляра класса DropDown * @param {object} language объект в котором находятся поля для подключения языка имеет два обязательных поля placeholder, textInListSearch @@ -721,13 +738,12 @@ export class CGSelect implements ICgSelect { */ public addLanguage(language: ILanguage) { const { placeholder, textInListSearch, selectPlaceholder } = language; - const { searchMode } = this.options; const select = this.element!.querySelector('.selected'); const textNodeSelect = document.createTextNode(selectPlaceholder); select!.appendChild(textNodeSelect); - if (searchMode) { + if (this.searchMode) { const search = this.element!.querySelector('.inputSearch'); const textNoRezult = this.element!.querySelector('.noRezult'); const textNode = document.createTextNode(textInListSearch); @@ -747,14 +763,12 @@ export class CGSelect implements ICgSelect { * @description Метод позволяющий открывать/закрывать селект с помощью кнопок * @method buttonControl */ - public buttonControl(button, method: string) { - const { listDisplayMode } = this.options; - - if (listDisplayMode === true) { + public buttonControl(button: Element, method: string) { + if (this.listDisplayMode) { return; } - // this.btn = button; + this.btnCntr = button!; button.addEventListener('click', () => { if (method.toLowerCase() === 'open') { this.open(true); diff --git a/src/components/utils/utilsTs.ts b/src/components/utils/utilsTs.ts index 4c82a65..720ae3b 100644 --- a/src/components/utils/utilsTs.ts +++ b/src/components/utils/utilsTs.ts @@ -84,7 +84,7 @@ export function createSelected(element: Element | null, content?: string, styles selected.appendChild(text); element?.appendChild(select); } else if (styles) { - // customStyles(element, styles); + customStyles(element!, styles); select.setAttribute('style', `${styles}`); selected.setAttribute('style', `${styles}`); caret.setAttribute('style', `${styles}`); From 1830ae23ada17c704e5d1af1124de811285534fd Mon Sep 17 00:00:00 2001 From: MaxOvs Date: Thu, 12 Jan 2023 19:02:00 +0300 Subject: [PATCH 15/21] Fixed public methods --- src/cg-selectTS.ts | 93 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/src/cg-selectTS.ts b/src/cg-selectTS.ts index d25dd38..a29265f 100644 --- a/src/cg-selectTS.ts +++ b/src/cg-selectTS.ts @@ -779,4 +779,97 @@ export class CGSelect implements ICgSelect { } }); } + + /** + * Метод экземпляра класса DropDown + * @param {boolean} value - Передаваемый параметр для добавления атрибута disabled; + * @description Метод позволяющий переключать состояние селекта disabled, + * @method disabled + */ + public disabled(value: boolean) { + const select = this.element!.querySelector('.cg-select'); + const nativeSelect = this.element!.querySelector('.nativeSelect'); + + if (value === true) { + this.element!.setAttribute('disabled', 'true'); + nativeSelect!.setAttribute('disabled', 'true'); + select!.classList.add('disabled'); + } else { + this.element!.removeAttribute('disabled'); + nativeSelect!.removeAttribute('disabled'); + select!.classList.remove('disabled'); + } + } + + /** + * Метод экземпляра класса DropDown + * @param {string | object} item добавляемый елемент + * @description добавляет переданный элемент в конец списка и перерисовывает список. Не может использоваться при передачи элементов с категорями + * @method addItem + */ + public addItem(item: IItems | string | number) { + if (this.category) { + console.log('can`t add item to category'); + return; + } + + if (!item) { + return false; + } + + const index = this.items.length; + + this.items.push(getFormatItem(item, index)); + this.render(); + } + + /** + * Метод экземпляра класса DropDown + * @param {number} index индекс удаляемого элемента + * @description удаляет елемент по индексу из списка и перерисовывает его. Не может использоваться при передачи элементов с категорями. + * @method deleteItem + */ + public deleteItem(index: number) { + if (this.category) { + console.log('can`t add item to category'); + return; + } + + const item = this.items[index]; + + this.items.splice(index, 1); + this.render(); + } + + /** + * Метод экземпляра класса DropDown + * @description удаляет все елементы из списка и перерисовывает его. + * @method deleteItemAll + */ + public deleteItemAll() { + this.items.splice(0, this.items.length); + this.render(); + } + + /** + * Метод экземпляра класса DropDown + * @param {number} index индекс выбранного элемента + * @description выбирает элемент который будет изначально отрисовываться в селекте + * @method selectIndex + */ + public selectIndex(index: number) { + if (this.category) { + console.log('can`t add item to category'); + return; + } + + const options = this.element!.querySelectorAll('.list__item') as NodeListOf; + + if (index > options!.length) { + return; + } + + const select: string = options[index].innerText; + this.render(select); + } } From 4d10721b7bc207fe59e3fdd0ce6efbf5b401395e Mon Sep 17 00:00:00 2001 From: MaxOvs Date: Fri, 13 Jan 2023 15:26:35 +0300 Subject: [PATCH 16/21] Added description in interfaces and etc --- example/indexTs.ts | 28 +- index.ts | 3 + package-lock.json | 133 ++- package.json | 3 +- src/cg-selectTS.js | 839 ++++++++++++++++++ src/cg-selectTS.ts | 142 ++- .../create-element.interface.js | 2 + .../create-element.interface.ts | 16 + .../create-element/create-elementTs.js | 103 +++ src/components/utils/urils.interface.js | 2 + src/components/utils/urils.interface.ts | 39 +- src/components/utils/utilsTs.js | 210 +++++ src/components/utils/utilsTs.ts | 41 +- src/interfaces/cg-select.interface.js | 2 + src/interfaces/cg-select.interface.ts | 96 ++ src/interfaces/items.interface.js | 2 + src/interfaces/items.interface.ts | 22 +- src/interfaces/language.interface.js | 2 + src/interfaces/language.interface.ts | 12 + src/language/languageTS.js | 13 + tsconfig.json | 102 +++ 21 files changed, 1728 insertions(+), 84 deletions(-) create mode 100644 index.ts create mode 100644 src/cg-selectTS.js create mode 100644 src/components/create-element/create-element.interface.js create mode 100644 src/components/create-element/create-elementTs.js create mode 100644 src/components/utils/urils.interface.js create mode 100644 src/components/utils/utilsTs.js create mode 100644 src/interfaces/cg-select.interface.js create mode 100644 src/interfaces/items.interface.js create mode 100644 src/interfaces/language.interface.js create mode 100644 src/language/languageTS.js create mode 100644 tsconfig.json diff --git a/example/indexTs.ts b/example/indexTs.ts index ce8f715..dfa4a3a 100644 --- a/example/indexTs.ts +++ b/example/indexTs.ts @@ -4,29 +4,15 @@ const dropdn = new CGSelect({ selector: '.cg-dropdown_one', placeholder: 'Выберите авто', items: [ + 'BMW', { - category: 'Russia', - categoryItems: [ - { - id: '28qwds', - title: 'Москва', - value: 0, - }, - , - 'Ростов-на-дону', - 'Саратов', - 'Волгоград', - 'Донецк', - ], - }, - { - category: 'USA', - categoryItems: ['Alabama', 'Texas', 'Colorado', 'Klirens', 'Los-Angeles'], - }, - { - category: 'France', - categoryItems: ['Paris'], + id: '213sade', + title: 'Opel', + value: 1, }, + 'Mersedes', + 'MAN', + 'max', ], styles: { head: { diff --git a/index.ts b/index.ts new file mode 100644 index 0000000..37a4489 --- /dev/null +++ b/index.ts @@ -0,0 +1,3 @@ +import { CGSelect } from './src/cg-selectTS'; + +export default CGSelect; diff --git a/package-lock.json b/package-lock.json index 724119e..e532c4b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,6 +12,7 @@ "@parcel/optimizer-css": "^2.8.0", "@types/prettier": "^2.7.2", "gh-pages": "^4.0.0", + "typedoc": "^0.23.24", "typescript": "^4.9.4" }, "devDependencies": { @@ -3016,6 +3017,11 @@ "node": ">=6" } }, + "node_modules/jsonc-parser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", + "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==" + }, "node_modules/jsonfile": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", @@ -3267,6 +3273,11 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, + "node_modules/lunr": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", + "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==" + }, "node_modules/make-dir": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", @@ -3328,7 +3339,6 @@ "version": "4.2.5", "resolved": "https://registry.npmjs.org/marked/-/marked-4.2.5.tgz", "integrity": "sha512-jPueVhumq7idETHkb203WDD4fMA3yV9emQ5vLwop58lu8bTclMghBWcYAavlDqIEMaisADinV1TooIFCfqOsYQ==", - "dev": true, "bin": { "marked": "bin/marked.js" }, @@ -3817,6 +3827,16 @@ "semver": "bin/semver" } }, + "node_modules/shiki": { + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.12.1.tgz", + "integrity": "sha512-aieaV1m349rZINEBkjxh2QbBvFFQOlgqYTNtCal82hHj4dDZ76oMlQIX+C7ryerBTDiga3e5NfH6smjdJ02BbQ==", + "dependencies": { + "jsonc-parser": "^3.2.0", + "vscode-oniguruma": "^1.7.0", + "vscode-textmate": "^8.0.0" + } + }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -3990,6 +4010,45 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/typedoc": { + "version": "0.23.24", + "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.23.24.tgz", + "integrity": "sha512-bfmy8lNQh+WrPYcJbtjQ6JEEsVl/ce1ZIXyXhyW+a1vFrjO39t6J8sL/d6FfAGrJTc7McCXgk9AanYBSNvLdIA==", + "dependencies": { + "lunr": "^2.3.9", + "marked": "^4.2.5", + "minimatch": "^5.1.2", + "shiki": "^0.12.1" + }, + "bin": { + "typedoc": "bin/typedoc" + }, + "engines": { + "node": ">= 14.14" + }, + "peerDependencies": { + "typescript": "4.6.x || 4.7.x || 4.8.x || 4.9.x" + } + }, + "node_modules/typedoc/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/typedoc/node_modules/minimatch": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.2.tgz", + "integrity": "sha512-bNH9mmM9qsJ2X4r2Nat1B//1dJVcn3+iBLa3IgqJ7EbGaDNepL9QSHOxN4ng33s52VMMhhIfgCYDk3C4ZmlDAg==", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/typescript": { "version": "4.9.4", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz", @@ -4061,6 +4120,16 @@ "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", "dev": true }, + "node_modules/vscode-oniguruma": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.7.0.tgz", + "integrity": "sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA==" + }, + "node_modules/vscode-textmate": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-8.0.0.tgz", + "integrity": "sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==" + }, "node_modules/weak-lru-cache": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/weak-lru-cache/-/weak-lru-cache-1.2.2.tgz", @@ -6064,6 +6133,11 @@ "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==" }, + "jsonc-parser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", + "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==" + }, "jsonfile": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", @@ -6198,6 +6272,11 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, + "lunr": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", + "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==" + }, "make-dir": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", @@ -6244,8 +6323,7 @@ "marked": { "version": "4.2.5", "resolved": "https://registry.npmjs.org/marked/-/marked-4.2.5.tgz", - "integrity": "sha512-jPueVhumq7idETHkb203WDD4fMA3yV9emQ5vLwop58lu8bTclMghBWcYAavlDqIEMaisADinV1TooIFCfqOsYQ==", - "dev": true + "integrity": "sha512-jPueVhumq7idETHkb203WDD4fMA3yV9emQ5vLwop58lu8bTclMghBWcYAavlDqIEMaisADinV1TooIFCfqOsYQ==" }, "mdn-data": { "version": "2.0.14", @@ -6585,6 +6663,16 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" }, + "shiki": { + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.12.1.tgz", + "integrity": "sha512-aieaV1m349rZINEBkjxh2QbBvFFQOlgqYTNtCal82hHj4dDZ76oMlQIX+C7ryerBTDiga3e5NfH6smjdJ02BbQ==", + "requires": { + "jsonc-parser": "^3.2.0", + "vscode-oniguruma": "^1.7.0", + "vscode-textmate": "^8.0.0" + } + }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -6711,6 +6799,35 @@ "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true }, + "typedoc": { + "version": "0.23.24", + "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.23.24.tgz", + "integrity": "sha512-bfmy8lNQh+WrPYcJbtjQ6JEEsVl/ce1ZIXyXhyW+a1vFrjO39t6J8sL/d6FfAGrJTc7McCXgk9AanYBSNvLdIA==", + "requires": { + "lunr": "^2.3.9", + "marked": "^4.2.5", + "minimatch": "^5.1.2", + "shiki": "^0.12.1" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "requires": { + "balanced-match": "^1.0.0" + } + }, + "minimatch": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.2.tgz", + "integrity": "sha512-bNH9mmM9qsJ2X4r2Nat1B//1dJVcn3+iBLa3IgqJ7EbGaDNepL9QSHOxN4ng33s52VMMhhIfgCYDk3C4ZmlDAg==", + "requires": { + "brace-expansion": "^2.0.1" + } + } + } + }, "typescript": { "version": "4.9.4", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz", @@ -6753,6 +6870,16 @@ "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", "dev": true }, + "vscode-oniguruma": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.7.0.tgz", + "integrity": "sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA==" + }, + "vscode-textmate": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-8.0.0.tgz", + "integrity": "sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==" + }, "weak-lru-cache": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/weak-lru-cache/-/weak-lru-cache-1.2.2.tgz", diff --git a/package.json b/package.json index cec7f93..9b9c8b7 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "homepage": "https://cg-select.itguild.info", "scripts": { "start": "parcel example/index.html -p 4500 --open ", - "build": "parcel build index.js", + "build": "parcel build index.ts", "deploy": "gh-pages -d dist", "predeploy": "npm run build" }, @@ -31,6 +31,7 @@ "@parcel/optimizer-css": "^2.8.0", "@types/prettier": "^2.7.2", "gh-pages": "^4.0.0", + "typedoc": "^0.23.24", "typescript": "^4.9.4" }, "keywords": [ diff --git a/src/cg-selectTS.js b/src/cg-selectTS.js new file mode 100644 index 0000000..d98807b --- /dev/null +++ b/src/cg-selectTS.js @@ -0,0 +1,839 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +exports.__esModule = true; +exports.CGSelect = void 0; +var create_elementTs_1 = require("./components/create-element/create-elementTs"); +var utilsTs_1 = require("./components/utils/utilsTs"); +var languageTS_1 = require("./language/languageTS"); +require("./main.scss"); +/** + * @class Описание класса ICgSelect + * @description Этот класс реализовывает функционал кастомного селекта, с возможностями кастомизации. + * @author Овсяников Максим + */ +var CGSelect = /** @class */ (function () { + /** + * @param {ICgSelect} setting Объект принимающий настройки селекта + * @constructor Конструктор класса DropDown + * @description Конструктор принимает объект и рендерит селект. + * @example + * options = { + * selector: 'Уникальный селектор', + selected: 'Выбранный элемент', + placeholder: '...', + lable: '...' + items: [string|number|object], + darkTheme: true/false, + searchMode: true/false, + closeOnSelect: true/false, + nativeSelectMode: true/false, + listDisplayMode: true/false, + language: 'ru/en', + styles: { + head: { + background: '...', + }, + list: {...}, + chips: {...}, + caret: {...}, + placeholder: {...}, + lable: {..}, + }, + event: '...', + url: 'http/...', + multiselect: true/false, + multiselectTag: true/false, + * } + */ + function CGSelect(setting) { + /** + * Массив индексов выбранных элементов + * @type {number[]} + */ + this.indexes = []; + this.init(setting); + this.render(); + this.closeSelectClick(); + this.initEvent(); + } + Object.defineProperty(CGSelect.prototype, "value", { + //Getters + /** + * Метод экземпляра класса DropDown + * @returns {string[] | string} Возвращает выбранные элемент(ы) в виде массива/элемента/null + * @description Геттер возвращающий выбранные элемент(ы) селекта + */ + get: function () { + var _a; + return (_a = this.selectedItems) !== null && _a !== void 0 ? _a : null; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(CGSelect.prototype, "indexesOf", { + /** + * Метод экземпляра класса DropDown + * @returns {number | number[]}Возвращает индексы выбранных элемента(ов) в виде массива/пустой массив + * @description Геттер возвращающий индексы выбранных элемента(ов) селекта + */ + get: function () { + var _a; + return (_a = this.indexes) !== null && _a !== void 0 ? _a : []; + }, + enumerable: false, + configurable: true + }); + /** + * Приватный метод инициализации экземпляра класса DropDown + * @method init + * @member + * @protected + * @param {ISgSelect} setting передаваемые настройки селекта + * @description Приватный метод. Общая инициализация селекта. Получение настоек и преобразвание элементов селекта. + * @example + * { + selector: '.cg-dropdown_one', + placeholder: 'Выберите авто', + items: [ + 'BMW', + { + id: '213sade', + title: 'Opel', + value: 1, + }, + 'Mersedes', + 'MAN', + 'max', + ], + darkTheme: true, + multiselect: true, + multiselectTag: true, + } + */ + CGSelect.prototype.init = function (setting) { + var _this = this; + var _a; + var items = setting.items, multiselect = setting.multiselect, multiselectTag = setting.multiselectTag, url = setting.url, selector = setting.selector, listDisplayMode = setting.listDisplayMode, nativeSelectMode = setting.nativeSelectMode, searchMode = setting.searchMode, darkTheme = setting.darkTheme, language = setting.language, styles = setting.styles, lable = setting.lable, event = setting.event, selected = setting.selected, placeholder = setting.placeholder; + this.options = setting; + this.multiselect = multiselect; + this.multiselectTag = multiselectTag; + this.url = url; + this.selector = selector; + this.items = items; + this.searchMode = searchMode; + this.darkTheme = darkTheme; + this.language = language; + this.nativeSelectMode = nativeSelectMode; + this.listDisplayMode = listDisplayMode; + this.styles = styles; + this.lable = lable; + this.event = event; + this.selected = selected; + this.placeholder = placeholder; + var elem = document.querySelector(this.selector); + this.element = elem; + (_a = this.element) === null || _a === void 0 ? void 0 : _a.addEventListener('click', function (e) { + e.preventDefault(); + _this.open(); + }); + this.items = []; + if (!this.items && this.url) { + this.renderUrl(); + return; + } + utilsTs_1.createSelected; + items.forEach(function (dataItem, index) { + var itemInputs = { + ItemValue: dataItem, + category: dataItem.category, + categoryItems: dataItem.categoryItems + }; + if (itemInputs.category && itemInputs.categoryItems) { + _this.category = itemInputs.category; + _this.items.push(_this.category); + itemInputs.categoryItems.forEach(function (categoryItem, indexCategory) { + _this.items.push((0, utilsTs_1.getFormatItem)(categoryItem, indexCategory)); + }); + } + else { + _this.items.push((0, utilsTs_1.getFormatItem)(itemInputs.ItemValue, index)); + } + }); + }; + /** + * Приватный метод рендера экземпляра класса DropDown + * @protected + * @method render + * @param {string} select необязательный елемент. Передаеться в метод initSelected + * @description Рендер елементов в селекте. + */ + CGSelect.prototype.render = function (select) { + var _this = this; + var _a, _b; + var random = Math.random().toString(36).substring(2, 10); + if (select || (select && this.styles)) { + this.initSelected(select); + (0, utilsTs_1.customStyles)(this.element, this.styles); + } + else { + this.initSelected(); + } + var ulList = document.createElement('ul'); + var nativeSelect = (0, create_elementTs_1.createNativeSelect)(); + var inputSearch; + var textNode; + this.randomId = random; + ulList.classList.add('list'); + if (this.styles) { + (0, utilsTs_1.customStylesFormat)(this.styles.list, ulList); + } + if (this.searchMode) { + if (this.language === 'ru') { + inputSearch = (0, create_elementTs_1.createInputSearch)(random, languageTS_1.ru.placeholder); + } + else { + inputSearch = (0, create_elementTs_1.createInputSearch)(random, languageTS_1.en.placeholder); + } + (0, utilsTs_1.customStylesFormat)((_a = this.styles) === null || _a === void 0 ? void 0 : _a.search, inputSearch); + ulList.appendChild(inputSearch); + } + (_b = this.element) === null || _b === void 0 ? void 0 : _b.appendChild(ulList); + this.items.forEach(function (dataItem) { + var _a; + (_a = _this.element) === null || _a === void 0 ? void 0 : _a.appendChild(nativeSelect); + var liItem = document.createElement('li'); + var nativeOption = (0, create_elementTs_1.createNativeSelectOption)(); + var strongItem = document.createElement('strong'); + liItem.classList.add('list__item'); + strongItem.classList.add('category'); + if (_this.multiselect) { + var checkBox = document.createElement('input'); + checkBox.type = 'checkbox'; + checkBox.setAttribute('id', "chbox-".concat(dataItem.id)); + liItem.appendChild(checkBox); + if (_this.multiselectTag) { + checkBox.classList.add('displayHide'); + } + nativeSelect.setAttribute('multiple', 'multiple'); + } + if (dataItem.title) { + nativeOption.text = dataItem.title; + nativeOption.value = dataItem.title; + textNode = document.createTextNode(dataItem.title); + nativeSelect.appendChild(nativeOption); + liItem.appendChild(textNode); + ulList.appendChild(liItem); + } + else { + // Для отрисовки категорий + textNode = document.createTextNode(dataItem); + strongItem.appendChild(textNode); + ulList.appendChild(strongItem); + } + }); + this.items.filter(function (item, index) { + if (typeof item !== 'object') { + _this.items.splice(index, 1); + } + return item; + }); + this.list = this.element.querySelector('.list'); + this.caret = this.element.querySelector('.caret'); + if (this.darkTheme == false) { + this.checkTheme(); + } + if (this.nativeSelectMode === true) { + this.selectMode(this.nativeSelectMode); + } + if (this.listDisplayMode) { + this.displayMode(this.listDisplayMode); + } + this.addOptionsBehaviour(); + }; + /** + * Приватный метод рендера экземпляра класса DropDown + * @protected + * @method renderUrl + * @description Рендер елементов в селекте переданных с URL и их настойка + */ + CGSelect.prototype.renderUrl = function () { + return __awaiter(this, void 0, void 0, function () { + var response, dataUrl, nativeSelect; + var _this = this; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + if (this.items || !this.url) { + return [2 /*return*/]; + } + return [4 /*yield*/, fetch(this.url)]; + case 1: + response = _a.sent(); + return [4 /*yield*/, response.json()]; + case 2: + dataUrl = _a.sent(); + nativeSelect = (0, create_elementTs_1.createNativeSelect)(); + dataUrl.forEach(function (dataItem, index) { + var item = { + id: dataItem.id, + title: dataItem.title, + value: index + }; + var ulUrl = _this.element.querySelector('.list'); + var nativeOption = (0, create_elementTs_1.createNativeSelectOption)(); + var liUrl = document.createElement('li'); + var textUrl = document.createTextNode(item.title); + if (_this.multiselect) { + var checkBox = document.createElement('input'); + checkBox.type = 'checkbox'; + if (_this.multiselectTag) { + checkBox.classList.add('displayHide'); + } + checkBox.setAttribute('id', "chbox-".concat(item.id)); + nativeSelect.setAttribute('multiple', 'multiple'); + liUrl.appendChild(checkBox); + } + liUrl.classList.add('list__item'); + nativeOption.value = item.title; + nativeOption.text = item.title; + nativeSelect.appendChild(nativeOption); + liUrl.appendChild(textUrl); + ulUrl.appendChild(liUrl); + _this.items.push(item); + }); + this.element.appendChild(nativeSelect); + this.items.filter(function (item, index) { + if (typeof item !== 'object') { + _this.items.splice(index, 1); + } + return item; + }); + this.addOptionsBehaviour(); + return [2 /*return*/]; + } + }); + }); + }; + /** + * Привaтный метод экземпляра класса DropDown + * @method initSelected + * @param {string} select необязательный елемент. Используется в методе selectIndex + * @description Отрисовывает и стилизует селект + * @protected + */ + CGSelect.prototype.initSelected = function (select) { + if (this.selected) { + (0, utilsTs_1.createSelected)(this.element, this.selected); + } + else if (this.placeholder) { + (0, utilsTs_1.createSelected)(this.element, this.placeholder); + } + else { + if (this.language && this.language === 'ru') { + (0, utilsTs_1.createSelected)(this.element, languageTS_1.ru.selectPlaceholder); + } + else { + (0, utilsTs_1.createSelected)(this.element, languageTS_1.en.selectPlaceholder); + } + } + if (select) { + (0, utilsTs_1.createSelected)(this.element, select, this.styles); + } + if (this.lable) { + var lableItem = document.createElement('h1'); + var textLable = document.createTextNode(this.lable); + lableItem.appendChild(textLable); + lableItem.classList.add('label'); + this.element.insertAdjacentElement('beforebegin', lableItem); + } + if (this.styles) { + (0, utilsTs_1.customStyles)(this.element, this.styles); + } + }; + /** + * Приватный метод экземпляра класса DropDown + * @protected + * @description Открывает и закрывает список по переданному эвенту + * @method initEvent + */ + CGSelect.prototype.initEvent = function () { + var _this = this; + if (!this.event) { + return; + } + if (this.event) { + if (this.event === 'mouseenter') { + this.element.addEventListener(this.event, function () { + _this.open(); + }); + this.element.addEventListener('mouseleave', function () { + _this.close(); + }); + } + } + }; + /** + * Приватный метод экземпляра класса DropDown + * @protected + * @param {boolean} oneClick необязательный параметр передаваемый из функции buttonControl + * @description Открывает список для выбора элемента + * @method open + */ + CGSelect.prototype.open = function (oneClick) { + if (oneClick === true) { + this.list.classList.add('open'); + this.caret.classList.add('caret_rotate'); + } + else { + this.list.classList.toggle('open'); + this.caret.classList.toggle('caret_rotate'); + } + }; + /** + * Приватный метод экземпляра класса DropDown + * @protected + * @description Закрывает список + * @method close + */ + CGSelect.prototype.close = function () { + var _a, _b; + (_a = this.list) === null || _a === void 0 ? void 0 : _a.classList.remove('open'); + (_b = this.caret) === null || _b === void 0 ? void 0 : _b.classList.remove('caret_rotate'); + }; + /** + * Приватный метод экземпляра класса DropDown + * @protected + * @description Закрывает список по клику вне элемента + * @method closeSelectClick + */ + CGSelect.prototype.closeSelectClick = function () { + var _this = this; + var dropdown = document.querySelector("".concat(this.options.selector)); + document.addEventListener('click', function (e) { + var withinBoundaries = e.composedPath().includes(dropdown); + if (!withinBoundaries) { + if (_this.btnCntr) { + return; + } + else { + _this.close(); + } + } + }); + }; + /** + * Приватный метод экземпляра класса DropDown + * @protected + * @description Метод реализовывающий выбор элементов в разных режимах. Обычный/Мультиселект/Мультиселект + Мультиселект Таг. + * @method addOptionsBehaviour + */ + CGSelect.prototype.addOptionsBehaviour = function () { + var _this = this; + var _a, _b; + var options = (_a = this.element) === null || _a === void 0 ? void 0 : _a.querySelectorAll('.list__item'); + var select = (_b = this.element) === null || _b === void 0 ? void 0 : _b.querySelector('.selected'); + var nativeOption = this.element.querySelectorAll('.nativeSelect__nativeOption'); + var selectedItemsClear; + var ulMultipul = document.createElement('ul'); + if (this.multiselect) { + this.selectedItems = []; + ulMultipul.classList.add('multiselect-tag'); + select === null || select === void 0 ? void 0 : select.classList.add('overflow-hidden'); + } + if (this.searchMode) { + this.searchModeSelect(this.randomId); + } + options === null || options === void 0 ? void 0 : options.forEach(function (option, index) { + option.addEventListener('click', function (event) { + if (Array.isArray(_this.selectedItems)) { + selectedItemsClear = { + placeholder: _this.placeholder, + selected: _this.selected, + selectedItems: _this.selectedItems, + indexes: _this.indexes, + darkTheme: _this.darkTheme, + multiselectTag: _this.multiselectTag + }; + } + var item = _this.items[index]; + var checkIndex = _this.indexes.indexOf(index); + if (_this.closeOnSelect == false || _this.multiselect) { + event.stopPropagation(); + event.preventDefault(); + } + if (_this.multiselect) { + option.classList.toggle('active'); + var checkBox = option.querySelector('input[type="checkbox"]'); + if (checkBox) { + if (!(event.target instanceof HTMLInputElement)) { + checkBox.checked = !checkBox.checked; + } + if (checkIndex == -1) { + _this.indexes.push(index); + (0, utilsTs_1.nativeOptionMultiple)(nativeOption, item.title, true); + select.textContent = ''; + if (_this.multiselectTag) { + if (Array.isArray(_this.selectedItems)) { + var dataBreadCrumb = { + option: _this.options, + element: _this.element, + indexes: _this.indexes, + selectedItems: _this.selectedItems + }; + _this.selectedItems.push(item.title); + select.appendChild(ulMultipul); + ulMultipul.appendChild((0, create_elementTs_1.createBreadCrumb)(dataBreadCrumb, item.title, index, item.id)); + } + } + else { + if (Array.isArray(_this.selectedItems)) { + _this.selectedItems.push(item.title); + select.innerText = _this.selectedItems.join(','); + } + } + } + else { + if (_this.multiselectTag) { + var tagItem = document.getElementById("tag-".concat(index, "-").concat(item.id)); + ulMultipul.removeChild(tagItem); + } + if (Array.isArray(_this.selectedItems)) { + _this.selectedItems.splice(checkIndex, 1); + _this.indexes.splice(checkIndex, 1); + (0, utilsTs_1.nativeOptionMultiple)(nativeOption, item.title, false); + } + } + if (!_this.selectedItems.length) { + (0, utilsTs_1.getSelectText)(selectedItemsClear, select); + } + else { + if (_this.multiselectTag) { + select.appendChild(ulMultipul); + } + else { + if (Array.isArray(_this.selectedItems)) { + select.innerText = _this.selectedItems.join(','); + } + } + } + } + } + else { + select.textContent = item.title; + _this.selectedItems = item.title; + (0, utilsTs_1.nativeOptionOrdinary)(nativeOption, item.title); + options.forEach(function (option) { + option.classList.remove('active'); + }); + option.classList.add('active'); + } + (0, utilsTs_1.clearSelect)(select, _this.element, selectedItemsClear); + }); + }); + }; + /** + * Приватный метод рендера экземпляра класса DropDown + * @protected + * @method #checkTheme + * @description Изменяет цветовую схему с темной на светлую. + */ + CGSelect.prototype.checkTheme = function () { + var select = this.element.querySelector('.cg-select'); + var caret = this.element.querySelector('.caret'); + var list = this.element.querySelector('ul.list'); + var search = this.element.querySelector('.inputSearch'); + if (this.darkTheme == false) { + select.classList.add('selectWhite'); + caret.classList.add('caretWhite'); + list.classList.add('listWhite'); + if (this.searchMode == true) { + search.classList.add('inputWhite'); + } + } + else if (this.darkTheme == true) { + return; + } + else { + throw new Error('Styles error or invalid value entered!'); + } + }; + /** + * Приватный метод экземпляра класса DropDown + * @protected + * @param {boolean} nativeSelectMode параметр отвечающий за добавления нативного селекта. + * @description Изменяет отображение селекта на мобильных устройствах + * @method selectMode + */ + CGSelect.prototype.selectMode = function (nativeSelectMode) { + var win = window.outerWidth; + if (nativeSelectMode === true) { + var select = this.element.querySelector('.cg-select'); + var list = this.element.querySelector('.list'); + var nativeSelect = this.element.querySelector('.nativeSelect'); + if (win < 576) { + select.classList.add('displayHide'); + list.classList.add('displayHide'); + nativeSelect.classList.add('nativeSelectActive'); + } + else if (win > 576) { + select.classList.remove('displayHide'); + list.classList.remove('displayHide'); + nativeSelect.classList.remove('nativeSelectActive'); + nativeSelect.classList.add('displayHide'); + } + } + else { + return; + } + }; + /** + * Метод который реализует поиск элементов в селекте + * @protected + * @param {string} random уникальное значение для input элемента. + * @method searchMode + */ + CGSelect.prototype.searchModeSelect = function (random) { + var input = this.element.querySelector("#searchSelect-".concat(random)); + var searchSelect = this.element.querySelectorAll('.list__item'); + var result = document.createElement('p'); + var textNode; + if (this.language && this.language === 'ru') { + textNode = document.createTextNode("".concat(languageTS_1.ru.textInListSearch)); + } + else { + textNode = document.createTextNode("".concat(languageTS_1.en.textInListSearch)); + } + result.appendChild(textNode); + result.classList.add('displayHide'); + result.classList.add('noRezult'); + input.parentElement.appendChild(result); + input.addEventListener('click', function (e) { + e.stopPropagation(); + }); + if (input instanceof HTMLInputElement) { + input.oninput = function () { + var valueSearch = input.value.trim().toLowerCase(); + var anyMatch = false; + if (valueSearch != '') { + searchSelect.forEach(function (elem) { + var isMatching = new RegExp(valueSearch, 'gi').test(elem.textContent); + anyMatch = anyMatch || isMatching; + if (elem.textContent.toLowerCase().search(valueSearch) == -1) { + elem.classList.add('displayHide'); + } + else { + elem.classList.remove('displayHide'); + } + }); + result.classList.toggle('displayHide', anyMatch); + } + else { + searchSelect.forEach(function (elem) { + elem.classList.remove('displayHide'); + result.classList.add('displayHide'); + }); + } + }; + } + }; + /** + * Приватный метод экземпляра класса DropDown + * @protected + * @param {boolean} listDisplayMode параметр отвечающий за отображение выбора в виде модального окна. + * @description Изменяет отображение листа с выбором в виде модального окна. + * @method displayMode + */ + CGSelect.prototype.displayMode = function (listDisplayMode) { + if (listDisplayMode) { + var modal_1 = document.createElement('div'); + var body_1 = document.querySelector('body'); + var list_1 = this.list; + modal_1.appendChild(list_1); + this.element.appendChild(modal_1); + this.element.addEventListener('click', function () { + modal_1.classList.toggle('modal'); + list_1.classList.toggle('listModal'); + body_1.classList.toggle('overflowHide'); + }); + } + else { + return; + } + }; + // Public methods + /** + * Метод экземпляра класса DropDown + * @param {number} numberItem номер возвращаемого элемента + * @returns {HTMLElement} возвращает ссылку на выбранный HTML элемент + * @method getElement + */ + CGSelect.prototype.getElement = function (numberItem) { + if (numberItem > this.items.length) { + return; + } + return this.items[numberItem]; + }; + /** + * Метод экземпляра класса DropDown + * @param {object} language объект в котором находятся поля для подключения языка имеет два обязательных поля placeholder, textInListSearch + * @description метод позволяющий заменить плейсхолдер в поиске и текст который выводится если нет результата + * @method addLanguage + */ + CGSelect.prototype.addLanguage = function (language) { + var placeholder = language.placeholder, textInListSearch = language.textInListSearch, selectPlaceholder = language.selectPlaceholder; + var select = this.element.querySelector('.selected'); + var textNodeSelect = document.createTextNode(selectPlaceholder); + select.appendChild(textNodeSelect); + if (this.searchMode) { + var search = this.element.querySelector('.inputSearch'); + var textNoRezult = this.element.querySelector('.noRezult'); + var textNode = document.createTextNode(textInListSearch); + search.setAttribute('placeholder', placeholder); + search.setAttribute('placeholder', placeholder); + textNoRezult.textContent = ''; + textNoRezult.appendChild(textNode); + } + }; + /** + * Метод экземпляра класса DropDown + * @param {HTMLInputElement} button - HTML кнопка + * @param {string} method - метод открытия open/close + * @description Метод позволяющий открывать/закрывать селект с помощью кнопок + * @method buttonControl + */ + CGSelect.prototype.buttonControl = function (button, method) { + var _this = this; + if (this.listDisplayMode) { + return; + } + this.btnCntr = button; + button.addEventListener('click', function () { + if (method.toLowerCase() === 'open') { + _this.open(true); + } + else if (method.toLowerCase() === 'close') { + _this.close(); + } + else { + return; + } + }); + }; + /** + * Метод экземпляра класса DropDown + * @param {boolean} value - Передаваемый параметр для добавления атрибута disabled; + * @description Метод позволяющий переключать состояние селекта disabled, + * @method disabled + */ + CGSelect.prototype.disabled = function (value) { + var select = this.element.querySelector('.cg-select'); + var nativeSelect = this.element.querySelector('.nativeSelect'); + if (value === true) { + this.element.setAttribute('disabled', 'true'); + nativeSelect.setAttribute('disabled', 'true'); + select.classList.add('disabled'); + } + else { + this.element.removeAttribute('disabled'); + nativeSelect.removeAttribute('disabled'); + select.classList.remove('disabled'); + } + }; + /** + * Метод экземпляра класса DropDown + * @param {string | object} item добавляемый елемент + * @description добавляет переданный элемент в конец списка и перерисовывает список. Не может использоваться при передачи элементов с категорями + * @method addItem + */ + CGSelect.prototype.addItem = function (item) { + if (this.category) { + console.log('can`t add item to category'); + return; + } + if (!item) { + return false; + } + var index = this.items.length; + this.items.push((0, utilsTs_1.getFormatItem)(item, index)); + this.render(); + }; + /** + * Метод экземпляра класса DropDown + * @param {number} index индекс удаляемого элемента + * @description удаляет елемент по индексу из списка и перерисовывает его. Не может использоваться при передачи элементов с категорями. + * @method deleteItem + */ + CGSelect.prototype.deleteItem = function (index) { + if (this.category) { + console.log('can`t add item to category'); + return; + } + var item = this.items[index]; + this.items.splice(index, 1); + this.render(); + }; + /** + * Метод экземпляра класса DropDown + * @description удаляет все елементы из списка и перерисовывает его. + * @method deleteItemAll + */ + CGSelect.prototype.deleteItemAll = function () { + this.items.splice(0, this.items.length); + this.render(); + }; + /** + * Метод экземпляра класса DropDown + * @param {number} index индекс выбранного элемента + * @description выбирает элемент который будет изначально отрисовываться в селекте + * @method selectIndex + */ + CGSelect.prototype.selectIndex = function (index) { + if (this.category) { + console.log('can`t add item to category'); + return; + } + var options = this.element.querySelectorAll('.list__item'); + if (index > options.length) { + return; + } + var select = options[index].innerText; + this.render(select); + }; + return CGSelect; +}()); +exports.CGSelect = CGSelect; diff --git a/src/cg-selectTS.ts b/src/cg-selectTS.ts index a29265f..faa5e46 100644 --- a/src/cg-selectTS.ts +++ b/src/cg-selectTS.ts @@ -25,8 +25,14 @@ import { ILanguage } from './interfaces/language.interface'; import './main.scss'; +/** + * @class Описание класса ICgSelect + * @description Этот класс реализовывает функционал кастомного селекта, с возможностями кастомизации. + * @author Овсяников Максим + */ export class CGSelect implements ICgSelect { // Настройки селекта + selector: string; selected?: string; placeholder?: string; @@ -45,16 +51,86 @@ export class CGSelect implements ICgSelect { multiselectTag?: boolean; // Переменные и комплектующие селекта + + /** + * Созданный HTML елемент + * @type {Element | null} + */ private element: Element | null; + /** + * Созданный список(ul), с классом list + * @type {Element | null | undefined} + */ private list: Element | null | undefined; + /** + * Настройки селекта передаваемые при создании экземпляра класса + * @type {ICgSelect} + */ private options: ICgSelect; + /** + * Уникальный Id для елементов + * @type {string} + */ private randomId: string; + /** + * Переменная для управления каретки + * @type {Element | null | undefined} + */ private caret: Element | null | undefined; + /** + * Переданные категории + * @type {string} + */ private category: string; + /** + * Выбранный или массив выбранных элементов из списка + * @type {string[] | string} + */ private selectedItems: string[] | string; + /** + * Массив индексов выбранных элементов + * @type {number[]} + */ private indexes: number[] = []; + /** + * Кнопка, для управления селектом + * @type {Element | null} + */ private btnCntr: Element | null; + /** + * @param {ICgSelect} setting Объект принимающий настройки селекта + * @constructor Конструктор класса DropDown + * @description Конструктор принимает объект и рендерит селект. + * @example + * options = { + * selector: 'Уникальный селектор', + selected: 'Выбранный элемент', + placeholder: '...', + lable: '...' + items: [string|number|object], + darkTheme: true/false, + searchMode: true/false, + closeOnSelect: true/false, + nativeSelectMode: true/false, + listDisplayMode: true/false, + language: 'ru/en', + styles: { + head: { + background: '...', + }, + list: {...}, + chips: {...}, + caret: {...}, + placeholder: {...}, + lable: {..}, + }, + event: '...', + url: 'http/...', + multiselect: true/false, + multiselectTag: true/false, + * } + */ constructor(setting: ICgSelect) { this.init(setting); this.render(); @@ -62,6 +138,25 @@ export class CGSelect implements ICgSelect { this.initEvent(); } + //Getters + /** + * Метод экземпляра класса DropDown + * @returns {string[] | string} Возвращает выбранные элемент(ы) в виде массива/элемента/null + * @description Геттер возвращающий выбранные элемент(ы) селекта + */ + get value(): string | string[] { + return this.selectedItems ?? null; + } + + /** + * Метод экземпляра класса DropDown + * @returns {number | number[]}Возвращает индексы выбранных элемента(ов) в виде массива/пустой массив + * @description Геттер возвращающий индексы выбранных элемента(ов) селекта + */ + get indexesOf(): number | number[] { + return this.indexes ?? []; + } + /** * Приватный метод инициализации экземпляра класса DropDown * @method init @@ -140,18 +235,19 @@ export class CGSelect implements ICgSelect { this.renderUrl(); return; } + createSelected; items.forEach((dataItem: any, index: number) => { let itemInputs: IDataItem = { ItemValue: dataItem, - // category: dataItem.category, - // categoryItems: dataItem.categoryItems, + category: dataItem.category, + categoryItems: dataItem.categoryItems, }; - if (dataItem.category && dataItem.categoryItems) { - this.category = dataItem.category!; + if (itemInputs.category && itemInputs.categoryItems) { + this.category = itemInputs.category!; this.items.push(this.category); - dataItem.categoryItems.forEach((categoryItem, indexCategory: number) => { + itemInputs.categoryItems.forEach((categoryItem, indexCategory: number) => { this.items.push(getFormatItem(categoryItem, indexCategory)); }); } else { @@ -168,13 +264,11 @@ export class CGSelect implements ICgSelect { * @description Рендер елементов в селекте. */ private render(select?: string): void { - const { styles } = this.options; - const random = Math.random().toString(36).substring(2, 10); - if (select || (select && styles)) { + if (select || (select && this.styles)) { this.initSelected(select); - customStyles(this.element!, styles); + customStyles(this.element!, this.styles!); } else { this.initSelected(); } @@ -189,9 +283,8 @@ export class CGSelect implements ICgSelect { ulList.classList.add('list'); - if (styles) { - const { list } = styles; - customStylesFormat(list!, ulList); + if (this.styles) { + customStylesFormat(this.styles.list!, ulList); } if (this.searchMode) { @@ -201,8 +294,7 @@ export class CGSelect implements ICgSelect { inputSearch = createInputSearch(random, en.placeholder); } - const { search } = styles!; - customStylesFormat(search!, inputSearch); + customStylesFormat(this.styles?.search!, inputSearch); ulList.appendChild(inputSearch); } @@ -247,10 +339,11 @@ export class CGSelect implements ICgSelect { } }); - this.items.filter((item, index) => { + this.items.filter((item: IItems | any, index: number) => { if (typeof item !== 'object') { this.items.splice(index, 1); } + return item; }); @@ -340,29 +433,26 @@ export class CGSelect implements ICgSelect { /** * Привaтный метод экземпляра класса DropDown - * * @method initSelected * @param {string} select необязательный елемент. Используется в методе selectIndex * @description Отрисовывает и стилизует селект * @protected */ private initSelected(select?: string): void { - const { styles } = this.options; - if (this.selected) { - createSelected(this.element, this.selected); + createSelected(this.element!, this.selected); } else if (this.placeholder) { - createSelected(this.element, this.placeholder); + createSelected(this.element!, this.placeholder); } else { if (this.language && this.language === 'ru') { - createSelected(this.element, ru.selectPlaceholder); + createSelected(this.element!, ru.selectPlaceholder); } else { - createSelected(this.element, en.selectPlaceholder); + createSelected(this.element!, en.selectPlaceholder); } } if (select) { - createSelected(this.element, select, styles); + createSelected(this.element!, select, this.styles); } if (this.lable) { @@ -375,8 +465,8 @@ export class CGSelect implements ICgSelect { this.element!.insertAdjacentElement('beforebegin', lableItem); } - if (styles) { - customStyles(this.element!, styles); + if (this.styles) { + customStyles(this.element!, this.styles); } } @@ -722,7 +812,7 @@ export class CGSelect implements ICgSelect { * @returns {HTMLElement} возвращает ссылку на выбранный HTML элемент * @method getElement */ - public getElement(numberItem: number) { + public getElement(numberItem: number): IItems[] | string[] | any { if (numberItem > this.items.length) { return; } diff --git a/src/components/create-element/create-element.interface.js b/src/components/create-element/create-element.interface.js new file mode 100644 index 0000000..0e34578 --- /dev/null +++ b/src/components/create-element/create-element.interface.js @@ -0,0 +1,2 @@ +"use strict"; +exports.__esModule = true; diff --git a/src/components/create-element/create-element.interface.ts b/src/components/create-element/create-element.interface.ts index 31c3ada..b0acac0 100644 --- a/src/components/create-element/create-element.interface.ts +++ b/src/components/create-element/create-element.interface.ts @@ -1,8 +1,24 @@ import { ICgSelect } from '../../interfaces/cg-select.interface'; export interface ICreateBreadCrumb { + /** + * Определенный экземпляр класса. + * @type {Element | null} + */ element: Element | null; + /** + * Настройки селекта. + * @type {ICgSelect} + */ option: ICgSelect; + /** + * Массив индексов выбранных элементов. + * @type {number[]} + */ indexes: number[]; + /** + * Массив с выбранными элементами. + * @type {string[]} + */ selectedItems: string[]; } diff --git a/src/components/create-element/create-elementTs.js b/src/components/create-element/create-elementTs.js new file mode 100644 index 0000000..bd8f9b0 --- /dev/null +++ b/src/components/create-element/create-elementTs.js @@ -0,0 +1,103 @@ +"use strict"; +exports.__esModule = true; +exports.createInputSearch = exports.createBreadCrumb = exports.createNativeSelectOption = exports.createNativeSelect = void 0; +var utilsTs_1 = require("../utils/utilsTs"); +/** + * Метод который создает нативный селект + * @returns {HTMLSelectElement} Возвращает созданный нативный селект + */ +function createNativeSelect() { + var nativeSelect = document.createElement('select'); + nativeSelect.setAttribute('name', 'dataSelect'); + nativeSelect.classList.add('nativeSelect'); + return nativeSelect; +} +exports.createNativeSelect = createNativeSelect; +/** + * Метод который создает Options для нативного селекта + * @returns {HTMLOptionElement} Возвращает созданные Options нативного селекта + */ +function createNativeSelectOption() { + var nativeOption = document.createElement('option'); + nativeOption.classList.add('nativeSelect__nativeOption'); + return nativeOption; +} +exports.createNativeSelectOption = createNativeSelectOption; +/** + * Метод который создает и отвечает за поведение chips + * @param {ICreateBreadCrumb} data объект в котором содержатся настройки и элементы селекта + * @param {string} title имя выбранного элемента для отрисовки chips + * @param {number} index индекс выбранного элемента для отрисовки chips + * @param {string} id уникальное id выбранного элемента + * @returns {HTMLElement} возвращает сформированный HTMLElement chips item + */ +function createBreadCrumb(data, title, index, id) { + var element = data.element, option = data.option, indexes = data.indexes, selectedItems = data.selectedItems; + var placeholder = option.placeholder, styles = option.styles; + var selected = element === null || element === void 0 ? void 0 : element.querySelector('.selected'); + var nativeOption = element.querySelectorAll('.nativeSelect__nativeOption'); + var liChip = document.createElement('li'); + var textNode = document.createTextNode(title); + var svgIcon = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); + var path1 = document.createElementNS('http://www.w3.org/2000/svg', 'path'); + var path2 = document.createElementNS('http://www.w3.org/2000/svg', 'path'); + svgIcon.setAttribute('viewBox', '0 0 10 10'); + path1.setAttribute('d', 'M3,7 L7,3'); + path2.setAttribute('d', 'M3,3 L7,7'); + liChip.setAttribute('id', "tag-".concat(index, "-").concat(id)); + svgIcon.classList.add('svg-icon'); + svgIcon.appendChild(path1); + svgIcon.appendChild(path2); + liChip.appendChild(textNode); + liChip.appendChild(svgIcon); + if (styles) { + // const { chips } = styles; + // customStylesFormat(chips, liChip); + } + svgIcon.addEventListener('click', function (event) { + event.preventDefault(); + event.stopPropagation(); + (0, utilsTs_1.nativeOptionMultiple)(nativeOption, title, false); + var deleteIcon = indexes.indexOf(index); + var checkBox; + indexes.splice(deleteIcon, 1); + selectedItems.splice(deleteIcon, 1); + if (id) { + checkBox = document.getElementById("chbox-".concat(id)); + } + else { + checkBox = document.getElementById("chbox-".concat(index)); + } + checkBox.checked = false; + checkBox.parentElement.classList.remove('active'); + if (!selectedItems.length) { + selected.innerText = placeholder; + } + liChip.parentElement.removeChild(liChip); + }); + return liChip; +} +exports.createBreadCrumb = createBreadCrumb; +/** + * Метод который создает поиск элементов в селекте + * @param {string} random уникальное значение для input элемента. + * @param {string} lenguage текст на определенном языке переданный из файла language.js + * @returns {HTMLInputElement} Возвращает сформированный input елемент. + */ +function createInputSearch(random, lenguage) { + var inputSearch = document.createElement('input'); + inputSearch.type = 'text'; + inputSearch.classList.add('inputSearch'); + inputSearch.setAttribute('id', "searchSelect-".concat(random)); + if (lenguage) { + inputSearch.setAttribute('placeholder', "".concat(lenguage)); + } + else { + inputSearch.setAttribute('placeholder', 'Search...'); + } + inputSearch.addEventListener('click', function (e) { + e.preventDefault(); + }); + return inputSearch; +} +exports.createInputSearch = createInputSearch; diff --git a/src/components/utils/urils.interface.js b/src/components/utils/urils.interface.js new file mode 100644 index 0000000..0e34578 --- /dev/null +++ b/src/components/utils/urils.interface.js @@ -0,0 +1,2 @@ +"use strict"; +exports.__esModule = true; diff --git a/src/components/utils/urils.interface.ts b/src/components/utils/urils.interface.ts index 62ea811..a949fd0 100644 --- a/src/components/utils/urils.interface.ts +++ b/src/components/utils/urils.interface.ts @@ -1,16 +1,53 @@ import { IItems } from '../../interfaces/items.interface'; export interface IDataItem { + /** + * Необязательный параметр. Категория группы элементов. + * @type {string} + */ category?: string; - categoryItems?: string; + /** + * Необязательный параметр. Массив с элементами. + * @type {IItems[] | string[] | any} + */ + categoryItems?: IItems[] | string[] | any; + /** + * Значение переданного элемента. + * @type {string | IItems | number} + */ ItemValue: string | IItems | number; } export interface ISelectedItems { + /** + * Placeholder необязательный параметр, в который передается текст плейсхолдера селекта. + * @type {string} + */ placeholder?: string; + /** + * Необязательный параметр, в который передается элемент который будет выбран изначально в селекте. + * @type {string} + */ selected?: string; + /** + * Массив выбранных элементов из списка + * @type {string[]} + */ selectedItems?: string[]; + /** + * Массив индексов выбранных элементов + * @type {number[]} + */ indexes?: number[]; + /** + * Необязательный параметр, который отвечает за поведения селекта, + * для него, ***работает только в месте с подключением multiselect. + * @type {boolean} + */ multiselectTag?: boolean; + /** + * Необязательный параметр, который отвечает за включение светлой/темной темы по умолчанию, стоит темная тема. + * @type {boolean} + */ darkTheme?: boolean; } diff --git a/src/components/utils/utilsTs.js b/src/components/utils/utilsTs.js new file mode 100644 index 0000000..3181b8d --- /dev/null +++ b/src/components/utils/utilsTs.js @@ -0,0 +1,210 @@ +"use strict"; +/** + * Utils module + * @module Utils + */ +exports.__esModule = true; +exports.customStylesFormat = exports.customStyles = exports.nativeOptionMultiple = exports.nativeOptionOrdinary = exports.clearSelect = exports.createSelected = exports.checkItemStruct = exports.getSelectText = exports.getFormatItem = void 0; +/** + * Преобразование каждого елемента полученного из поля Items; + * @param {any} dataItem полученный елемент переданный при создании селекта может быть как object / string + * @param {number} index индекс этого элемента + * @returns {IItems} возвращает сформированный объект + */ +function getFormatItem(dataItem, index) { + var random = Math.random().toString(36).substring(2, 10); + var item; + if (checkItemStruct(dataItem)) { + return dataItem; + } + else { + item = { + id: random, + title: dataItem, + value: index + }; + return item; + } +} +exports.getFormatItem = getFormatItem; +/** + * Вставка изначального текста селекта(до выбора) + * @param {ITextSelect} data объект в котором находяться title селекта + * @param {HTMLElement | null | undefined} select елемент селекта, куда будет вставляться title + * @returns {HTMLElement} возвращает сформированный елемент селекта + */ +function getSelectText(data, select) { + var placeholder = data.placeholder, selected = data.selected; + if (placeholder) { + select.innerText = placeholder; + } + else if (selected) { + select.innerText = selected; + } + else { + select.innerText = 'Select...'; + } + return select; +} +exports.getSelectText = getSelectText; +/** + * Проверка содержит ли item указанные свойства, + * @param {object} item проверяемый на определенную структуру элемент + * @returns {boolean} возвращает true/false если item содержит указанные свойства + */ +function checkItemStruct(item) { + if (item && typeof item !== 'object') { + return false; + } + return item.hasOwnProperty('id') && item.hasOwnProperty('title') && item.hasOwnProperty('value'); +} +exports.checkItemStruct = checkItemStruct; +/** + * Создание кнопки выбора элементов + * @param {HTMLElement} element созданный экземпляр класса DropDown + * @param {string} content placeholer передаваемый из настроек селекта + * @param {object} styles не обязательный параметр. Объект в котором находяться настройки кастомизации частей селекта + */ +function createSelected(element, content, styles) { + var select = document.createElement('div'); + var selected = document.createElement('p'); + var caret = document.createElement('div'); + select.classList.add('cg-select'); + selected.classList.add('selected'); + caret.classList.add('caret'); + select.appendChild(selected); + select.appendChild(caret); + if (content) { + var text = document.createTextNode(content); + selected.appendChild(text); + element === null || element === void 0 ? void 0 : element.appendChild(select); + } + else if (styles) { + customStyles(element, styles); + select.setAttribute('style', "".concat(styles)); + selected.setAttribute('style', "".concat(styles)); + caret.setAttribute('style', "".concat(styles)); + } +} +exports.createSelected = createSelected; +/** + * Создание кнопки отчиски селекта, при единичном выборе. + * @param {HTMLElement} select место в селекте которое будет переназначено на ''. + * @param {Element} element экземпляр класса DropDown. + * @param {ISelectedItems} dataSelectText текст который отрисовывается в селекте. + */ +function clearSelect(select, element, dataSelectText) { + var selectedItems = dataSelectText.selectedItems, indexes = dataSelectText.indexes, darkTheme = dataSelectText.darkTheme, multiselectTag = dataSelectText.multiselectTag; + var options = element.querySelectorAll('.list__item'); + var ulMultiSelect = element.querySelector('.multiselect-tag'); + var svgIcon = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); + var path1 = document.createElementNS('http://www.w3.org/2000/svg', 'path'); + var path2 = document.createElementNS('http://www.w3.org/2000/svg', 'path'); + var checkBox = element.querySelectorAll('li input'); + svgIcon.setAttribute('viewBox', '0 0 10 10'); + path1.setAttribute('d', 'M2,8 L8,2'); + path2.setAttribute('d', 'M2,2 L8,8'); + svgIcon.appendChild(path1); + svgIcon.appendChild(path2); + if (multiselectTag) { + return; + } + if (darkTheme === true || !darkTheme) { + path1.classList.add('pathWhite'); + path2.classList.add('pathWhite'); + } + if (darkTheme === false) { + path1.classList.add('pathBlack'); + path2.classList.add('pathBlack'); + } + svgIcon.classList.add('svg-icon'); + svgIcon.classList.add('svg-clear'); + select.appendChild(svgIcon); + svgIcon.addEventListener('click', function () { + select.innerText = ''; + if (Array.isArray(selectedItems)) { + selectedItems.splice(0); + indexes.splice(0); + } + checkBox.forEach(function (item) { + if (item instanceof HTMLInputElement) { + item.checked = false; + } + }); + getSelectText(dataSelectText, select); + options.forEach(function (option) { + option.classList.remove('active'); + }); + }); +} +exports.clearSelect = clearSelect; +/** + * Поведение нативного(одинарного) селекта при выборе кастомного + * @param {NodeList} element NodeList нативного селекта + * @param {any} item выбранный элемент в кастомном селекте + */ +function nativeOptionOrdinary(element, item) { + element.forEach(function (option) { + option.removeAttribute('selected'); + if (option.textContent === item) { + option.setAttribute('selected', 'selected'); + } + }); +} +exports.nativeOptionOrdinary = nativeOptionOrdinary; +/** + * Поведение нативного(Multiple) селекта при выборе в кастомном + * @param {NodeListOf | undefined} element NodeList нативного селекта + * @param {string} item выбранный элемент в кастомном селекте + * @param {boolean} condition специальный флаг при котором добавляются/убераются атрибуты у нативного селекта + */ +function nativeOptionMultiple(element, item, condition) { + element.forEach(function (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; + } + }); +} +exports.nativeOptionMultiple = nativeOptionMultiple; +/** + * Поиск и стилизация елементов полученных из styles экземпляра DropDown + * @param {Element} element созданный экземпляр класса DropDown + * @param {object} styles объект в котором находяться настройки кастомизации частей селекта + */ +function customStyles(element, styles) { + var cgSelect = element.querySelector('.cg-select'); + var caretSelect = element.querySelector('.caret'); + var placeholderSelect = element.querySelector('.selected'); + var lableItem = element.parentElement.querySelector('h1.label'); + customStylesFormat(styles.head, cgSelect); + customStylesFormat(styles.caret, caretSelect); + customStylesFormat(styles.lable, lableItem); + if (placeholderSelect) { + customStylesFormat(styles.placeholder, placeholderSelect); + } +} +exports.customStyles = customStyles; +/** + * Универсальный метод для стилизации селекта + * @param {object} elemOption объект полученное из объекта styles у которого мы получаем ключ-значение стилей + * @param {HTMLElement} selector HTMLElement подвергающиеся кастомизации + */ +function customStylesFormat(elemOption, selector) { + if (elemOption) { + Object.entries(elemOption).forEach(function (_a) { + var key = _a[0], value = _a[1]; + selector.style[key] = value; + }); + } +} +exports.customStylesFormat = customStylesFormat; diff --git a/src/components/utils/utilsTs.ts b/src/components/utils/utilsTs.ts index 720ae3b..c6cf502 100644 --- a/src/components/utils/utilsTs.ts +++ b/src/components/utils/utilsTs.ts @@ -1,14 +1,18 @@ -import { ICgSelect } from '../../interfaces/cg-select.interface'; +/** + * Utils module + * @module Utils + */ + +import { IStyle } from '../../interfaces/cg-select.interface'; import { IItems } from '../../interfaces/items.interface'; import { IDataItem, ISelectedItems } from './urils.interface'; /** * Преобразование каждого елемента полученного из поля Items; - * @param {IDataItem} dataItem полученный елемент переданный при создании селекта может быть как object / string + * @param {any} dataItem полученный елемент переданный при создании селекта может быть как object / string * @param {number} index индекс этого элемента - * @returns {IDataItem | IItems} возвращает сформированный объект + * @returns {IItems} возвращает сформированный объект */ - export function getFormatItem(dataItem: any, index: number): IItems { const random = Math.random().toString(36).substring(2, 10); let item: IItems; @@ -67,7 +71,7 @@ export function checkItemStruct(item: object): boolean { * @param {string} content placeholer передаваемый из настроек селекта * @param {object} styles не обязательный параметр. Объект в котором находяться настройки кастомизации частей селекта */ -export function createSelected(element: Element | null, content?: string, styles?: object) { +export function createSelected(element: Element, content?: string, styles?: IStyle) { const select = document.createElement('div'); const selected = document.createElement('p'); const caret = document.createElement('div'); @@ -89,17 +93,6 @@ export function createSelected(element: Element | null, content?: string, styles selected.setAttribute('style', `${styles}`); caret.setAttribute('style', `${styles}`); } - - // if (styles) { - // customStyles(element, styles); - - // element.innerHTML = ` - //
- //

${content}

- //
- //
- // `; - // } } /** @@ -210,24 +203,18 @@ export function nativeOptionMultiple( * @param {Element} element созданный экземпляр класса DropDown * @param {object} styles объект в котором находяться настройки кастомизации частей селекта */ -export function customStyles(element: Element, styles: any) { - if (!styles) { - return; - } - - const { head, caret, placeholder, lable } = styles; - +export function customStyles(element: Element, styles: IStyle) { const cgSelect = element.querySelector('.cg-select'); const caretSelect = element.querySelector('.caret'); const placeholderSelect = element.querySelector('.selected'); const lableItem = element.parentElement!.querySelector('h1.label'); - customStylesFormat(head, cgSelect!); - customStylesFormat(caret, caretSelect!); - customStylesFormat(lable, lableItem!); + customStylesFormat(styles.head!, cgSelect!); + customStylesFormat(styles.caret!, caretSelect!); + customStylesFormat(styles.lable!, lableItem!); if (placeholderSelect) { - customStylesFormat(placeholder, placeholderSelect); + customStylesFormat(styles.placeholder!, placeholderSelect); } } diff --git a/src/interfaces/cg-select.interface.js b/src/interfaces/cg-select.interface.js new file mode 100644 index 0000000..0e34578 --- /dev/null +++ b/src/interfaces/cg-select.interface.js @@ -0,0 +1,2 @@ +"use strict"; +exports.__esModule = true; diff --git a/src/interfaces/cg-select.interface.ts b/src/interfaces/cg-select.interface.ts index b2cb7f6..8da039c 100644 --- a/src/interfaces/cg-select.interface.ts +++ b/src/interfaces/cg-select.interface.ts @@ -1,29 +1,125 @@ import { IItems } from './items.interface'; export interface ICgSelect { + /** + * Уникальный селектор - *обязательный параметр(индефикатор), который задаеться при создании селекта. + * @type {string} + */ selector: string; + /** + * Необязательный параметр, в который передается элемент который будет выбран изначально в селекте. + * @type {string} + */ selected?: string; + /** + * Placeholder необязательный параметр, в который передается текст плейсхолдера селекта. + * @type {string} + */ placeholder?: string; + /** + * *Обязательный параметр(эсли не указан другой способ получения данных (url)), это массив элементов, + * которые будут отображаться в селекте при выборе. + * @type {IItems[] | string[] | any} + */ items?: IItems[] | string[] | any; + /** + * Необязательный параметр, который отвечает за включение светлой/темной темы по умолчанию, стоит темная тема(darkTheme == true) + * @type {boolean} + */ darkTheme?: boolean; + /** + * Необязательный параметр, который добавляет живой поиск по элеметам селекта. + * @type {boolean} + */ searchMode?: boolean; + /** + * Необязательный параметр, который отвечает за поведения селекта при открытии, если closeOnSelect: false, + * тогда при выборе елемента в селекте закрытия не происходит, + * и можно выбрать другой элемент по умолчанию, closeOnSelect:true. + * @type {boolean} + */ closeOnSelect?: boolean; + /** + * Необязательный параметр, который отвечает за поведения селекта при открытии на мобильных усторйствах. + * @type {boolean} + */ nativeSelectMode?: boolean; + /** + * Необязательный параметр, который отвечает за поведения селекта при открытии. + * @type {boolean} + */ listDisplayMode?: boolean; + /** + * Необязательный параметр, отвечающий за локализацию некоторых текстовых элементов. + * @type {string} + */ language?: string; + /** + * Необязательный параметр,который добавляет lable перед селектом. + * @type {string} + */ lable?: string; + /** + * Необязательный параметр, который отвечает за кастомизацию элементов селекта, + * в него передаются обьекты с CSS свойствами для кастомизируемых элементов. + * @type {IStyle} + */ styles?: IStyle; + /** + * Необязательный параметр, который отвечает за поведения селекта, передавая в этот параметр, евент по типу 'mouseenter', + * селект будет открываться при наведении. + * @type {string} + */ event?: string; + /** + * Обязательный параметр(эсли не указан другой способ получения данных (items)), + * данные которые приходят с бекэнда в формате {id:"", title: "", value: ""}. + * @type {string} + */ url?: string; + /** + * Необязательный параметр, который отвечает за поведения селекта, добавляет возможность выбирать несколько элементов. + * Выбранные элементы отрисовываются как обычный текст, через запятую. + * @type {boolean} + */ multiselect?: boolean; + /** + * Необязательный параметр, который отвечает за поведения селекта, + * для него, ***работает только в месте с подключением multiselect. + * @type {boolean} + */ multiselectTag?: boolean; } export interface IStyle { + /** + * Кастомизация кнопки селекта. + * @type {object} + */ head?: object; + /** + * Кастомизация каретки. + * @type {object} + */ caret?: object; + /** + * Кастомизация placeholder. + * @type {object} + */ placeholder?: object; + /** + * Кастомизация lable селекта. + * @type {object} + */ lable?: object; + /** + * Кастомизация листа с выбором элементов. + * @type {object} + */ list?: object; + /** + * Кастомизация поиска. + * @type {object} + */ search?: object; } diff --git a/src/interfaces/items.interface.js b/src/interfaces/items.interface.js new file mode 100644 index 0000000..0e34578 --- /dev/null +++ b/src/interfaces/items.interface.js @@ -0,0 +1,2 @@ +"use strict"; +exports.__esModule = true; diff --git a/src/interfaces/items.interface.ts b/src/interfaces/items.interface.ts index c7bfa0d..b827cfd 100644 --- a/src/interfaces/items.interface.ts +++ b/src/interfaces/items.interface.ts @@ -1,5 +1,17 @@ -export interface IItems{ - id: string; - title: string; - value: number | string -} \ No newline at end of file +export interface IItems { + /** + * Уникальное ID элемента + * @type {string} + */ + id: string; + /** + * Текстовое значение элемента + * @type {string} + */ + title: string; + /** + * Порядковый номер, или другая информация + * @type {number | string} + */ + value: number | string; +} diff --git a/src/interfaces/language.interface.js b/src/interfaces/language.interface.js new file mode 100644 index 0000000..0e34578 --- /dev/null +++ b/src/interfaces/language.interface.js @@ -0,0 +1,2 @@ +"use strict"; +exports.__esModule = true; diff --git a/src/interfaces/language.interface.ts b/src/interfaces/language.interface.ts index ffaaf2a..c2665f7 100644 --- a/src/interfaces/language.interface.ts +++ b/src/interfaces/language.interface.ts @@ -1,5 +1,17 @@ export interface ILanguage { + /** + * Текст в поиске. + * @type {string} + */ placeholder: string; + /** + * Дефолтный Текст Селекта если не указан placeholder или выбранный элемент + * @type {string} + */ selectPlaceholder: string; + /** + * Текст если совпадений нет. + * @type {string} + */ textInListSearch: string; } diff --git a/src/language/languageTS.js b/src/language/languageTS.js new file mode 100644 index 0000000..1e4e0ca --- /dev/null +++ b/src/language/languageTS.js @@ -0,0 +1,13 @@ +"use strict"; +exports.__esModule = true; +exports.en = exports.ru = void 0; +exports.ru = { + selectPlaceholder: 'Выберите элемент...', + placeholder: 'Поиск...', + textInListSearch: 'Совпадений нет...' +}; +exports.en = { + selectPlaceholder: 'Select element...', + placeholder: 'Search...', + textInListSearch: 'No matches...' +}; diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..2e03881 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,102 @@ +{ + "compilerOptions": { + + /* Projects */ + // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ + // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ + // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ + // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ + // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ + // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ + + /* Language and Environment */ + "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ + // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ + // "jsx": "preserve", /* Specify what JSX code is generated. */ + // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ + // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ + // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ + // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ + // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ + // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ + // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ + // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ + // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ + + /* Modules */ + "module": "commonjs", /* Specify what module code is generated. */ + // "rootDir": "./", /* Specify the root folder within your source files. */ + // "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ + // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ + // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ + // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ + // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ + // "types": [], /* Specify type package names to be included without being referenced in a source file. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ + // "resolveJsonModule": true, /* Enable importing .json files. */ + // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ + + /* JavaScript Support */ + // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ + // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ + // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ + + /* Emit */ + // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ + // "declarationMap": true, /* Create sourcemaps for d.ts files. */ + // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ + // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ + // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ + // "outDir": "./", /* Specify an output folder for all emitted files. */ + // "removeComments": true, /* Disable emitting comments. */ + // "noEmit": true, /* Disable emitting files from a compilation. */ + // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ + // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ + // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ + // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ + // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ + // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ + // "newLine": "crlf", /* Set the newline character for emitting files. */ + // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ + // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ + // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ + // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ + // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ + // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ + + /* Interop Constraints */ + // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ + // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ + "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ + // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ + "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ + + /* Type Checking */ + "strict": true, /* Enable all strict type-checking options. */ + // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ + // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ + // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ + // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ + // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ + // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ + // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ + // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ + // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ + // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ + // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ + // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ + // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ + // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ + // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ + // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ + // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ + + /* Completeness */ + // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */ + } +} From ae258e68f4659232acaa62a6db814180f361630c Mon Sep 17 00:00:00 2001 From: MaxOvs Date: Fri, 13 Jan 2023 15:40:11 +0300 Subject: [PATCH 17/21] Fixed files --- package.json | 2 +- src/cg-selectTS.js | 839 ------------------ src/cg-selectTS.ts | 29 +- .../create-element.interface.js | 2 - .../create-element/create-elementTs.js | 103 --- src/components/utils/urils.interface.js | 2 - src/components/utils/urils.interface.ts | 2 +- src/components/utils/utilsTs.js | 210 ----- src/interfaces/cg-select.interface.js | 2 - src/interfaces/cg-select.interface.ts | 2 +- src/interfaces/items.interface.js | 2 - src/interfaces/language.interface.js | 2 - src/language/languageTS.js | 13 - tsconfig.json | 2 +- 14 files changed, 19 insertions(+), 1193 deletions(-) delete mode 100644 src/cg-selectTS.js delete mode 100644 src/components/create-element/create-element.interface.js delete mode 100644 src/components/create-element/create-elementTs.js delete mode 100644 src/components/utils/urils.interface.js delete mode 100644 src/components/utils/utilsTs.js delete mode 100644 src/interfaces/cg-select.interface.js delete mode 100644 src/interfaces/items.interface.js delete mode 100644 src/interfaces/language.interface.js delete mode 100644 src/language/languageTS.js diff --git a/package.json b/package.json index 9b9c8b7..10a7f63 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "homepage": "https://cg-select.itguild.info", "scripts": { "start": "parcel example/index.html -p 4500 --open ", - "build": "parcel build index.ts", + "build": "parcel build index.js", "deploy": "gh-pages -d dist", "predeploy": "npm run build" }, diff --git a/src/cg-selectTS.js b/src/cg-selectTS.js deleted file mode 100644 index d98807b..0000000 --- a/src/cg-selectTS.js +++ /dev/null @@ -1,839 +0,0 @@ -"use strict"; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -var __generator = (this && this.__generator) || function (thisArg, body) { - var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; - return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; - function verb(n) { return function (v) { return step([n, v]); }; } - function step(op) { - if (f) throw new TypeError("Generator is already executing."); - while (g && (g = 0, op[0] && (_ = 0)), _) try { - if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; - if (y = 0, t) op = [op[0] & 2, t.value]; - switch (op[0]) { - case 0: case 1: t = op; break; - case 4: _.label++; return { value: op[1], done: false }; - case 5: _.label++; y = op[1]; op = [0]; continue; - case 7: op = _.ops.pop(); _.trys.pop(); continue; - default: - if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } - if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } - if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } - if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } - if (t[2]) _.ops.pop(); - _.trys.pop(); continue; - } - op = body.call(thisArg, _); - } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } - if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; - } -}; -exports.__esModule = true; -exports.CGSelect = void 0; -var create_elementTs_1 = require("./components/create-element/create-elementTs"); -var utilsTs_1 = require("./components/utils/utilsTs"); -var languageTS_1 = require("./language/languageTS"); -require("./main.scss"); -/** - * @class Описание класса ICgSelect - * @description Этот класс реализовывает функционал кастомного селекта, с возможностями кастомизации. - * @author Овсяников Максим - */ -var CGSelect = /** @class */ (function () { - /** - * @param {ICgSelect} setting Объект принимающий настройки селекта - * @constructor Конструктор класса DropDown - * @description Конструктор принимает объект и рендерит селект. - * @example - * options = { - * selector: 'Уникальный селектор', - selected: 'Выбранный элемент', - placeholder: '...', - lable: '...' - items: [string|number|object], - darkTheme: true/false, - searchMode: true/false, - closeOnSelect: true/false, - nativeSelectMode: true/false, - listDisplayMode: true/false, - language: 'ru/en', - styles: { - head: { - background: '...', - }, - list: {...}, - chips: {...}, - caret: {...}, - placeholder: {...}, - lable: {..}, - }, - event: '...', - url: 'http/...', - multiselect: true/false, - multiselectTag: true/false, - * } - */ - function CGSelect(setting) { - /** - * Массив индексов выбранных элементов - * @type {number[]} - */ - this.indexes = []; - this.init(setting); - this.render(); - this.closeSelectClick(); - this.initEvent(); - } - Object.defineProperty(CGSelect.prototype, "value", { - //Getters - /** - * Метод экземпляра класса DropDown - * @returns {string[] | string} Возвращает выбранные элемент(ы) в виде массива/элемента/null - * @description Геттер возвращающий выбранные элемент(ы) селекта - */ - get: function () { - var _a; - return (_a = this.selectedItems) !== null && _a !== void 0 ? _a : null; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(CGSelect.prototype, "indexesOf", { - /** - * Метод экземпляра класса DropDown - * @returns {number | number[]}Возвращает индексы выбранных элемента(ов) в виде массива/пустой массив - * @description Геттер возвращающий индексы выбранных элемента(ов) селекта - */ - get: function () { - var _a; - return (_a = this.indexes) !== null && _a !== void 0 ? _a : []; - }, - enumerable: false, - configurable: true - }); - /** - * Приватный метод инициализации экземпляра класса DropDown - * @method init - * @member - * @protected - * @param {ISgSelect} setting передаваемые настройки селекта - * @description Приватный метод. Общая инициализация селекта. Получение настоек и преобразвание элементов селекта. - * @example - * { - selector: '.cg-dropdown_one', - placeholder: 'Выберите авто', - items: [ - 'BMW', - { - id: '213sade', - title: 'Opel', - value: 1, - }, - 'Mersedes', - 'MAN', - 'max', - ], - darkTheme: true, - multiselect: true, - multiselectTag: true, - } - */ - CGSelect.prototype.init = function (setting) { - var _this = this; - var _a; - var items = setting.items, multiselect = setting.multiselect, multiselectTag = setting.multiselectTag, url = setting.url, selector = setting.selector, listDisplayMode = setting.listDisplayMode, nativeSelectMode = setting.nativeSelectMode, searchMode = setting.searchMode, darkTheme = setting.darkTheme, language = setting.language, styles = setting.styles, lable = setting.lable, event = setting.event, selected = setting.selected, placeholder = setting.placeholder; - this.options = setting; - this.multiselect = multiselect; - this.multiselectTag = multiselectTag; - this.url = url; - this.selector = selector; - this.items = items; - this.searchMode = searchMode; - this.darkTheme = darkTheme; - this.language = language; - this.nativeSelectMode = nativeSelectMode; - this.listDisplayMode = listDisplayMode; - this.styles = styles; - this.lable = lable; - this.event = event; - this.selected = selected; - this.placeholder = placeholder; - var elem = document.querySelector(this.selector); - this.element = elem; - (_a = this.element) === null || _a === void 0 ? void 0 : _a.addEventListener('click', function (e) { - e.preventDefault(); - _this.open(); - }); - this.items = []; - if (!this.items && this.url) { - this.renderUrl(); - return; - } - utilsTs_1.createSelected; - items.forEach(function (dataItem, index) { - var itemInputs = { - ItemValue: dataItem, - category: dataItem.category, - categoryItems: dataItem.categoryItems - }; - if (itemInputs.category && itemInputs.categoryItems) { - _this.category = itemInputs.category; - _this.items.push(_this.category); - itemInputs.categoryItems.forEach(function (categoryItem, indexCategory) { - _this.items.push((0, utilsTs_1.getFormatItem)(categoryItem, indexCategory)); - }); - } - else { - _this.items.push((0, utilsTs_1.getFormatItem)(itemInputs.ItemValue, index)); - } - }); - }; - /** - * Приватный метод рендера экземпляра класса DropDown - * @protected - * @method render - * @param {string} select необязательный елемент. Передаеться в метод initSelected - * @description Рендер елементов в селекте. - */ - CGSelect.prototype.render = function (select) { - var _this = this; - var _a, _b; - var random = Math.random().toString(36).substring(2, 10); - if (select || (select && this.styles)) { - this.initSelected(select); - (0, utilsTs_1.customStyles)(this.element, this.styles); - } - else { - this.initSelected(); - } - var ulList = document.createElement('ul'); - var nativeSelect = (0, create_elementTs_1.createNativeSelect)(); - var inputSearch; - var textNode; - this.randomId = random; - ulList.classList.add('list'); - if (this.styles) { - (0, utilsTs_1.customStylesFormat)(this.styles.list, ulList); - } - if (this.searchMode) { - if (this.language === 'ru') { - inputSearch = (0, create_elementTs_1.createInputSearch)(random, languageTS_1.ru.placeholder); - } - else { - inputSearch = (0, create_elementTs_1.createInputSearch)(random, languageTS_1.en.placeholder); - } - (0, utilsTs_1.customStylesFormat)((_a = this.styles) === null || _a === void 0 ? void 0 : _a.search, inputSearch); - ulList.appendChild(inputSearch); - } - (_b = this.element) === null || _b === void 0 ? void 0 : _b.appendChild(ulList); - this.items.forEach(function (dataItem) { - var _a; - (_a = _this.element) === null || _a === void 0 ? void 0 : _a.appendChild(nativeSelect); - var liItem = document.createElement('li'); - var nativeOption = (0, create_elementTs_1.createNativeSelectOption)(); - var strongItem = document.createElement('strong'); - liItem.classList.add('list__item'); - strongItem.classList.add('category'); - if (_this.multiselect) { - var checkBox = document.createElement('input'); - checkBox.type = 'checkbox'; - checkBox.setAttribute('id', "chbox-".concat(dataItem.id)); - liItem.appendChild(checkBox); - if (_this.multiselectTag) { - checkBox.classList.add('displayHide'); - } - nativeSelect.setAttribute('multiple', 'multiple'); - } - if (dataItem.title) { - nativeOption.text = dataItem.title; - nativeOption.value = dataItem.title; - textNode = document.createTextNode(dataItem.title); - nativeSelect.appendChild(nativeOption); - liItem.appendChild(textNode); - ulList.appendChild(liItem); - } - else { - // Для отрисовки категорий - textNode = document.createTextNode(dataItem); - strongItem.appendChild(textNode); - ulList.appendChild(strongItem); - } - }); - this.items.filter(function (item, index) { - if (typeof item !== 'object') { - _this.items.splice(index, 1); - } - return item; - }); - this.list = this.element.querySelector('.list'); - this.caret = this.element.querySelector('.caret'); - if (this.darkTheme == false) { - this.checkTheme(); - } - if (this.nativeSelectMode === true) { - this.selectMode(this.nativeSelectMode); - } - if (this.listDisplayMode) { - this.displayMode(this.listDisplayMode); - } - this.addOptionsBehaviour(); - }; - /** - * Приватный метод рендера экземпляра класса DropDown - * @protected - * @method renderUrl - * @description Рендер елементов в селекте переданных с URL и их настойка - */ - CGSelect.prototype.renderUrl = function () { - return __awaiter(this, void 0, void 0, function () { - var response, dataUrl, nativeSelect; - var _this = this; - return __generator(this, function (_a) { - switch (_a.label) { - case 0: - if (this.items || !this.url) { - return [2 /*return*/]; - } - return [4 /*yield*/, fetch(this.url)]; - case 1: - response = _a.sent(); - return [4 /*yield*/, response.json()]; - case 2: - dataUrl = _a.sent(); - nativeSelect = (0, create_elementTs_1.createNativeSelect)(); - dataUrl.forEach(function (dataItem, index) { - var item = { - id: dataItem.id, - title: dataItem.title, - value: index - }; - var ulUrl = _this.element.querySelector('.list'); - var nativeOption = (0, create_elementTs_1.createNativeSelectOption)(); - var liUrl = document.createElement('li'); - var textUrl = document.createTextNode(item.title); - if (_this.multiselect) { - var checkBox = document.createElement('input'); - checkBox.type = 'checkbox'; - if (_this.multiselectTag) { - checkBox.classList.add('displayHide'); - } - checkBox.setAttribute('id', "chbox-".concat(item.id)); - nativeSelect.setAttribute('multiple', 'multiple'); - liUrl.appendChild(checkBox); - } - liUrl.classList.add('list__item'); - nativeOption.value = item.title; - nativeOption.text = item.title; - nativeSelect.appendChild(nativeOption); - liUrl.appendChild(textUrl); - ulUrl.appendChild(liUrl); - _this.items.push(item); - }); - this.element.appendChild(nativeSelect); - this.items.filter(function (item, index) { - if (typeof item !== 'object') { - _this.items.splice(index, 1); - } - return item; - }); - this.addOptionsBehaviour(); - return [2 /*return*/]; - } - }); - }); - }; - /** - * Привaтный метод экземпляра класса DropDown - * @method initSelected - * @param {string} select необязательный елемент. Используется в методе selectIndex - * @description Отрисовывает и стилизует селект - * @protected - */ - CGSelect.prototype.initSelected = function (select) { - if (this.selected) { - (0, utilsTs_1.createSelected)(this.element, this.selected); - } - else if (this.placeholder) { - (0, utilsTs_1.createSelected)(this.element, this.placeholder); - } - else { - if (this.language && this.language === 'ru') { - (0, utilsTs_1.createSelected)(this.element, languageTS_1.ru.selectPlaceholder); - } - else { - (0, utilsTs_1.createSelected)(this.element, languageTS_1.en.selectPlaceholder); - } - } - if (select) { - (0, utilsTs_1.createSelected)(this.element, select, this.styles); - } - if (this.lable) { - var lableItem = document.createElement('h1'); - var textLable = document.createTextNode(this.lable); - lableItem.appendChild(textLable); - lableItem.classList.add('label'); - this.element.insertAdjacentElement('beforebegin', lableItem); - } - if (this.styles) { - (0, utilsTs_1.customStyles)(this.element, this.styles); - } - }; - /** - * Приватный метод экземпляра класса DropDown - * @protected - * @description Открывает и закрывает список по переданному эвенту - * @method initEvent - */ - CGSelect.prototype.initEvent = function () { - var _this = this; - if (!this.event) { - return; - } - if (this.event) { - if (this.event === 'mouseenter') { - this.element.addEventListener(this.event, function () { - _this.open(); - }); - this.element.addEventListener('mouseleave', function () { - _this.close(); - }); - } - } - }; - /** - * Приватный метод экземпляра класса DropDown - * @protected - * @param {boolean} oneClick необязательный параметр передаваемый из функции buttonControl - * @description Открывает список для выбора элемента - * @method open - */ - CGSelect.prototype.open = function (oneClick) { - if (oneClick === true) { - this.list.classList.add('open'); - this.caret.classList.add('caret_rotate'); - } - else { - this.list.classList.toggle('open'); - this.caret.classList.toggle('caret_rotate'); - } - }; - /** - * Приватный метод экземпляра класса DropDown - * @protected - * @description Закрывает список - * @method close - */ - CGSelect.prototype.close = function () { - var _a, _b; - (_a = this.list) === null || _a === void 0 ? void 0 : _a.classList.remove('open'); - (_b = this.caret) === null || _b === void 0 ? void 0 : _b.classList.remove('caret_rotate'); - }; - /** - * Приватный метод экземпляра класса DropDown - * @protected - * @description Закрывает список по клику вне элемента - * @method closeSelectClick - */ - CGSelect.prototype.closeSelectClick = function () { - var _this = this; - var dropdown = document.querySelector("".concat(this.options.selector)); - document.addEventListener('click', function (e) { - var withinBoundaries = e.composedPath().includes(dropdown); - if (!withinBoundaries) { - if (_this.btnCntr) { - return; - } - else { - _this.close(); - } - } - }); - }; - /** - * Приватный метод экземпляра класса DropDown - * @protected - * @description Метод реализовывающий выбор элементов в разных режимах. Обычный/Мультиселект/Мультиселект + Мультиселект Таг. - * @method addOptionsBehaviour - */ - CGSelect.prototype.addOptionsBehaviour = function () { - var _this = this; - var _a, _b; - var options = (_a = this.element) === null || _a === void 0 ? void 0 : _a.querySelectorAll('.list__item'); - var select = (_b = this.element) === null || _b === void 0 ? void 0 : _b.querySelector('.selected'); - var nativeOption = this.element.querySelectorAll('.nativeSelect__nativeOption'); - var selectedItemsClear; - var ulMultipul = document.createElement('ul'); - if (this.multiselect) { - this.selectedItems = []; - ulMultipul.classList.add('multiselect-tag'); - select === null || select === void 0 ? void 0 : select.classList.add('overflow-hidden'); - } - if (this.searchMode) { - this.searchModeSelect(this.randomId); - } - options === null || options === void 0 ? void 0 : options.forEach(function (option, index) { - option.addEventListener('click', function (event) { - if (Array.isArray(_this.selectedItems)) { - selectedItemsClear = { - placeholder: _this.placeholder, - selected: _this.selected, - selectedItems: _this.selectedItems, - indexes: _this.indexes, - darkTheme: _this.darkTheme, - multiselectTag: _this.multiselectTag - }; - } - var item = _this.items[index]; - var checkIndex = _this.indexes.indexOf(index); - if (_this.closeOnSelect == false || _this.multiselect) { - event.stopPropagation(); - event.preventDefault(); - } - if (_this.multiselect) { - option.classList.toggle('active'); - var checkBox = option.querySelector('input[type="checkbox"]'); - if (checkBox) { - if (!(event.target instanceof HTMLInputElement)) { - checkBox.checked = !checkBox.checked; - } - if (checkIndex == -1) { - _this.indexes.push(index); - (0, utilsTs_1.nativeOptionMultiple)(nativeOption, item.title, true); - select.textContent = ''; - if (_this.multiselectTag) { - if (Array.isArray(_this.selectedItems)) { - var dataBreadCrumb = { - option: _this.options, - element: _this.element, - indexes: _this.indexes, - selectedItems: _this.selectedItems - }; - _this.selectedItems.push(item.title); - select.appendChild(ulMultipul); - ulMultipul.appendChild((0, create_elementTs_1.createBreadCrumb)(dataBreadCrumb, item.title, index, item.id)); - } - } - else { - if (Array.isArray(_this.selectedItems)) { - _this.selectedItems.push(item.title); - select.innerText = _this.selectedItems.join(','); - } - } - } - else { - if (_this.multiselectTag) { - var tagItem = document.getElementById("tag-".concat(index, "-").concat(item.id)); - ulMultipul.removeChild(tagItem); - } - if (Array.isArray(_this.selectedItems)) { - _this.selectedItems.splice(checkIndex, 1); - _this.indexes.splice(checkIndex, 1); - (0, utilsTs_1.nativeOptionMultiple)(nativeOption, item.title, false); - } - } - if (!_this.selectedItems.length) { - (0, utilsTs_1.getSelectText)(selectedItemsClear, select); - } - else { - if (_this.multiselectTag) { - select.appendChild(ulMultipul); - } - else { - if (Array.isArray(_this.selectedItems)) { - select.innerText = _this.selectedItems.join(','); - } - } - } - } - } - else { - select.textContent = item.title; - _this.selectedItems = item.title; - (0, utilsTs_1.nativeOptionOrdinary)(nativeOption, item.title); - options.forEach(function (option) { - option.classList.remove('active'); - }); - option.classList.add('active'); - } - (0, utilsTs_1.clearSelect)(select, _this.element, selectedItemsClear); - }); - }); - }; - /** - * Приватный метод рендера экземпляра класса DropDown - * @protected - * @method #checkTheme - * @description Изменяет цветовую схему с темной на светлую. - */ - CGSelect.prototype.checkTheme = function () { - var select = this.element.querySelector('.cg-select'); - var caret = this.element.querySelector('.caret'); - var list = this.element.querySelector('ul.list'); - var search = this.element.querySelector('.inputSearch'); - if (this.darkTheme == false) { - select.classList.add('selectWhite'); - caret.classList.add('caretWhite'); - list.classList.add('listWhite'); - if (this.searchMode == true) { - search.classList.add('inputWhite'); - } - } - else if (this.darkTheme == true) { - return; - } - else { - throw new Error('Styles error or invalid value entered!'); - } - }; - /** - * Приватный метод экземпляра класса DropDown - * @protected - * @param {boolean} nativeSelectMode параметр отвечающий за добавления нативного селекта. - * @description Изменяет отображение селекта на мобильных устройствах - * @method selectMode - */ - CGSelect.prototype.selectMode = function (nativeSelectMode) { - var win = window.outerWidth; - if (nativeSelectMode === true) { - var select = this.element.querySelector('.cg-select'); - var list = this.element.querySelector('.list'); - var nativeSelect = this.element.querySelector('.nativeSelect'); - if (win < 576) { - select.classList.add('displayHide'); - list.classList.add('displayHide'); - nativeSelect.classList.add('nativeSelectActive'); - } - else if (win > 576) { - select.classList.remove('displayHide'); - list.classList.remove('displayHide'); - nativeSelect.classList.remove('nativeSelectActive'); - nativeSelect.classList.add('displayHide'); - } - } - else { - return; - } - }; - /** - * Метод который реализует поиск элементов в селекте - * @protected - * @param {string} random уникальное значение для input элемента. - * @method searchMode - */ - CGSelect.prototype.searchModeSelect = function (random) { - var input = this.element.querySelector("#searchSelect-".concat(random)); - var searchSelect = this.element.querySelectorAll('.list__item'); - var result = document.createElement('p'); - var textNode; - if (this.language && this.language === 'ru') { - textNode = document.createTextNode("".concat(languageTS_1.ru.textInListSearch)); - } - else { - textNode = document.createTextNode("".concat(languageTS_1.en.textInListSearch)); - } - result.appendChild(textNode); - result.classList.add('displayHide'); - result.classList.add('noRezult'); - input.parentElement.appendChild(result); - input.addEventListener('click', function (e) { - e.stopPropagation(); - }); - if (input instanceof HTMLInputElement) { - input.oninput = function () { - var valueSearch = input.value.trim().toLowerCase(); - var anyMatch = false; - if (valueSearch != '') { - searchSelect.forEach(function (elem) { - var isMatching = new RegExp(valueSearch, 'gi').test(elem.textContent); - anyMatch = anyMatch || isMatching; - if (elem.textContent.toLowerCase().search(valueSearch) == -1) { - elem.classList.add('displayHide'); - } - else { - elem.classList.remove('displayHide'); - } - }); - result.classList.toggle('displayHide', anyMatch); - } - else { - searchSelect.forEach(function (elem) { - elem.classList.remove('displayHide'); - result.classList.add('displayHide'); - }); - } - }; - } - }; - /** - * Приватный метод экземпляра класса DropDown - * @protected - * @param {boolean} listDisplayMode параметр отвечающий за отображение выбора в виде модального окна. - * @description Изменяет отображение листа с выбором в виде модального окна. - * @method displayMode - */ - CGSelect.prototype.displayMode = function (listDisplayMode) { - if (listDisplayMode) { - var modal_1 = document.createElement('div'); - var body_1 = document.querySelector('body'); - var list_1 = this.list; - modal_1.appendChild(list_1); - this.element.appendChild(modal_1); - this.element.addEventListener('click', function () { - modal_1.classList.toggle('modal'); - list_1.classList.toggle('listModal'); - body_1.classList.toggle('overflowHide'); - }); - } - else { - return; - } - }; - // Public methods - /** - * Метод экземпляра класса DropDown - * @param {number} numberItem номер возвращаемого элемента - * @returns {HTMLElement} возвращает ссылку на выбранный HTML элемент - * @method getElement - */ - CGSelect.prototype.getElement = function (numberItem) { - if (numberItem > this.items.length) { - return; - } - return this.items[numberItem]; - }; - /** - * Метод экземпляра класса DropDown - * @param {object} language объект в котором находятся поля для подключения языка имеет два обязательных поля placeholder, textInListSearch - * @description метод позволяющий заменить плейсхолдер в поиске и текст который выводится если нет результата - * @method addLanguage - */ - CGSelect.prototype.addLanguage = function (language) { - var placeholder = language.placeholder, textInListSearch = language.textInListSearch, selectPlaceholder = language.selectPlaceholder; - var select = this.element.querySelector('.selected'); - var textNodeSelect = document.createTextNode(selectPlaceholder); - select.appendChild(textNodeSelect); - if (this.searchMode) { - var search = this.element.querySelector('.inputSearch'); - var textNoRezult = this.element.querySelector('.noRezult'); - var textNode = document.createTextNode(textInListSearch); - search.setAttribute('placeholder', placeholder); - search.setAttribute('placeholder', placeholder); - textNoRezult.textContent = ''; - textNoRezult.appendChild(textNode); - } - }; - /** - * Метод экземпляра класса DropDown - * @param {HTMLInputElement} button - HTML кнопка - * @param {string} method - метод открытия open/close - * @description Метод позволяющий открывать/закрывать селект с помощью кнопок - * @method buttonControl - */ - CGSelect.prototype.buttonControl = function (button, method) { - var _this = this; - if (this.listDisplayMode) { - return; - } - this.btnCntr = button; - button.addEventListener('click', function () { - if (method.toLowerCase() === 'open') { - _this.open(true); - } - else if (method.toLowerCase() === 'close') { - _this.close(); - } - else { - return; - } - }); - }; - /** - * Метод экземпляра класса DropDown - * @param {boolean} value - Передаваемый параметр для добавления атрибута disabled; - * @description Метод позволяющий переключать состояние селекта disabled, - * @method disabled - */ - CGSelect.prototype.disabled = function (value) { - var select = this.element.querySelector('.cg-select'); - var nativeSelect = this.element.querySelector('.nativeSelect'); - if (value === true) { - this.element.setAttribute('disabled', 'true'); - nativeSelect.setAttribute('disabled', 'true'); - select.classList.add('disabled'); - } - else { - this.element.removeAttribute('disabled'); - nativeSelect.removeAttribute('disabled'); - select.classList.remove('disabled'); - } - }; - /** - * Метод экземпляра класса DropDown - * @param {string | object} item добавляемый елемент - * @description добавляет переданный элемент в конец списка и перерисовывает список. Не может использоваться при передачи элементов с категорями - * @method addItem - */ - CGSelect.prototype.addItem = function (item) { - if (this.category) { - console.log('can`t add item to category'); - return; - } - if (!item) { - return false; - } - var index = this.items.length; - this.items.push((0, utilsTs_1.getFormatItem)(item, index)); - this.render(); - }; - /** - * Метод экземпляра класса DropDown - * @param {number} index индекс удаляемого элемента - * @description удаляет елемент по индексу из списка и перерисовывает его. Не может использоваться при передачи элементов с категорями. - * @method deleteItem - */ - CGSelect.prototype.deleteItem = function (index) { - if (this.category) { - console.log('can`t add item to category'); - return; - } - var item = this.items[index]; - this.items.splice(index, 1); - this.render(); - }; - /** - * Метод экземпляра класса DropDown - * @description удаляет все елементы из списка и перерисовывает его. - * @method deleteItemAll - */ - CGSelect.prototype.deleteItemAll = function () { - this.items.splice(0, this.items.length); - this.render(); - }; - /** - * Метод экземпляра класса DropDown - * @param {number} index индекс выбранного элемента - * @description выбирает элемент который будет изначально отрисовываться в селекте - * @method selectIndex - */ - CGSelect.prototype.selectIndex = function (index) { - if (this.category) { - console.log('can`t add item to category'); - return; - } - var options = this.element.querySelectorAll('.list__item'); - if (index > options.length) { - return; - } - var select = options[index].innerText; - this.render(select); - }; - return CGSelect; -}()); -exports.CGSelect = CGSelect; diff --git a/src/cg-selectTS.ts b/src/cg-selectTS.ts index faa5e46..4277e50 100644 --- a/src/cg-selectTS.ts +++ b/src/cg-selectTS.ts @@ -32,8 +32,7 @@ import './main.scss'; */ export class CGSelect implements ICgSelect { // Настройки селекта - - selector: string; + selector?: string; selected?: string; placeholder?: string; items?: IItems[] | string[] | any; @@ -56,22 +55,22 @@ export class CGSelect implements ICgSelect { * Созданный HTML елемент * @type {Element | null} */ - private element: Element | null; + private element!: Element | null; /** * Созданный список(ul), с классом list * @type {Element | null | undefined} */ - private list: Element | null | undefined; + private list!: Element | null; /** * Настройки селекта передаваемые при создании экземпляра класса * @type {ICgSelect} */ - private options: ICgSelect; + private options!: ICgSelect; /** * Уникальный Id для елементов * @type {string} */ - private randomId: string; + private randomId!: string; /** * Переменная для управления каретки * @type {Element | null | undefined} @@ -81,12 +80,12 @@ export class CGSelect implements ICgSelect { * Переданные категории * @type {string} */ - private category: string; + private category?: string; /** * Выбранный или массив выбранных элементов из списка * @type {string[] | string} */ - private selectedItems: string[] | string; + private selectedItems!: string[] | string; /** * Массив индексов выбранных элементов * @type {number[]} @@ -96,7 +95,7 @@ export class CGSelect implements ICgSelect { * Кнопка, для управления селектом * @type {Element | null} */ - private btnCntr: Element | null; + private btnCntr?: Element | null; /** * @param {ICgSelect} setting Объект принимающий настройки селекта @@ -221,7 +220,7 @@ export class CGSelect implements ICgSelect { this.selected = selected; this.placeholder = placeholder; - const elem = document.querySelector(this.selector); + const elem = document.querySelector(this.selector!); this.element = elem; this.element?.addEventListener('click', (e) => { @@ -247,9 +246,11 @@ export class CGSelect implements ICgSelect { if (itemInputs.category && itemInputs.categoryItems) { this.category = itemInputs.category!; this.items.push(this.category); - itemInputs.categoryItems.forEach((categoryItem, indexCategory: number) => { - this.items.push(getFormatItem(categoryItem, indexCategory)); - }); + itemInputs.categoryItems.forEach( + (categoryItem: string | IItems | any, indexCategory: number) => { + this.items.push(getFormatItem(categoryItem, indexCategory)); + }, + ); } else { this.items.push(getFormatItem(itemInputs.ItemValue, index)); } @@ -421,7 +422,7 @@ export class CGSelect implements ICgSelect { this.element!.appendChild(nativeSelect); - this.items.filter((item, index) => { + this.items.filter((item: IItems | string | any, index: number) => { if (typeof item !== 'object') { this.items.splice(index, 1); } diff --git a/src/components/create-element/create-element.interface.js b/src/components/create-element/create-element.interface.js deleted file mode 100644 index 0e34578..0000000 --- a/src/components/create-element/create-element.interface.js +++ /dev/null @@ -1,2 +0,0 @@ -"use strict"; -exports.__esModule = true; diff --git a/src/components/create-element/create-elementTs.js b/src/components/create-element/create-elementTs.js deleted file mode 100644 index bd8f9b0..0000000 --- a/src/components/create-element/create-elementTs.js +++ /dev/null @@ -1,103 +0,0 @@ -"use strict"; -exports.__esModule = true; -exports.createInputSearch = exports.createBreadCrumb = exports.createNativeSelectOption = exports.createNativeSelect = void 0; -var utilsTs_1 = require("../utils/utilsTs"); -/** - * Метод который создает нативный селект - * @returns {HTMLSelectElement} Возвращает созданный нативный селект - */ -function createNativeSelect() { - var nativeSelect = document.createElement('select'); - nativeSelect.setAttribute('name', 'dataSelect'); - nativeSelect.classList.add('nativeSelect'); - return nativeSelect; -} -exports.createNativeSelect = createNativeSelect; -/** - * Метод который создает Options для нативного селекта - * @returns {HTMLOptionElement} Возвращает созданные Options нативного селекта - */ -function createNativeSelectOption() { - var nativeOption = document.createElement('option'); - nativeOption.classList.add('nativeSelect__nativeOption'); - return nativeOption; -} -exports.createNativeSelectOption = createNativeSelectOption; -/** - * Метод который создает и отвечает за поведение chips - * @param {ICreateBreadCrumb} data объект в котором содержатся настройки и элементы селекта - * @param {string} title имя выбранного элемента для отрисовки chips - * @param {number} index индекс выбранного элемента для отрисовки chips - * @param {string} id уникальное id выбранного элемента - * @returns {HTMLElement} возвращает сформированный HTMLElement chips item - */ -function createBreadCrumb(data, title, index, id) { - var element = data.element, option = data.option, indexes = data.indexes, selectedItems = data.selectedItems; - var placeholder = option.placeholder, styles = option.styles; - var selected = element === null || element === void 0 ? void 0 : element.querySelector('.selected'); - var nativeOption = element.querySelectorAll('.nativeSelect__nativeOption'); - var liChip = document.createElement('li'); - var textNode = document.createTextNode(title); - var svgIcon = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); - var path1 = document.createElementNS('http://www.w3.org/2000/svg', 'path'); - var path2 = document.createElementNS('http://www.w3.org/2000/svg', 'path'); - svgIcon.setAttribute('viewBox', '0 0 10 10'); - path1.setAttribute('d', 'M3,7 L7,3'); - path2.setAttribute('d', 'M3,3 L7,7'); - liChip.setAttribute('id', "tag-".concat(index, "-").concat(id)); - svgIcon.classList.add('svg-icon'); - svgIcon.appendChild(path1); - svgIcon.appendChild(path2); - liChip.appendChild(textNode); - liChip.appendChild(svgIcon); - if (styles) { - // const { chips } = styles; - // customStylesFormat(chips, liChip); - } - svgIcon.addEventListener('click', function (event) { - event.preventDefault(); - event.stopPropagation(); - (0, utilsTs_1.nativeOptionMultiple)(nativeOption, title, false); - var deleteIcon = indexes.indexOf(index); - var checkBox; - indexes.splice(deleteIcon, 1); - selectedItems.splice(deleteIcon, 1); - if (id) { - checkBox = document.getElementById("chbox-".concat(id)); - } - else { - checkBox = document.getElementById("chbox-".concat(index)); - } - checkBox.checked = false; - checkBox.parentElement.classList.remove('active'); - if (!selectedItems.length) { - selected.innerText = placeholder; - } - liChip.parentElement.removeChild(liChip); - }); - return liChip; -} -exports.createBreadCrumb = createBreadCrumb; -/** - * Метод который создает поиск элементов в селекте - * @param {string} random уникальное значение для input элемента. - * @param {string} lenguage текст на определенном языке переданный из файла language.js - * @returns {HTMLInputElement} Возвращает сформированный input елемент. - */ -function createInputSearch(random, lenguage) { - var inputSearch = document.createElement('input'); - inputSearch.type = 'text'; - inputSearch.classList.add('inputSearch'); - inputSearch.setAttribute('id', "searchSelect-".concat(random)); - if (lenguage) { - inputSearch.setAttribute('placeholder', "".concat(lenguage)); - } - else { - inputSearch.setAttribute('placeholder', 'Search...'); - } - inputSearch.addEventListener('click', function (e) { - e.preventDefault(); - }); - return inputSearch; -} -exports.createInputSearch = createInputSearch; diff --git a/src/components/utils/urils.interface.js b/src/components/utils/urils.interface.js deleted file mode 100644 index 0e34578..0000000 --- a/src/components/utils/urils.interface.js +++ /dev/null @@ -1,2 +0,0 @@ -"use strict"; -exports.__esModule = true; diff --git a/src/components/utils/urils.interface.ts b/src/components/utils/urils.interface.ts index a949fd0..630f2ee 100644 --- a/src/components/utils/urils.interface.ts +++ b/src/components/utils/urils.interface.ts @@ -10,7 +10,7 @@ export interface IDataItem { * Необязательный параметр. Массив с элементами. * @type {IItems[] | string[] | any} */ - categoryItems?: IItems[] | string[] | any; + categoryItems?: IItems[] | string[]; /** * Значение переданного элемента. * @type {string | IItems | number} diff --git a/src/components/utils/utilsTs.js b/src/components/utils/utilsTs.js deleted file mode 100644 index 3181b8d..0000000 --- a/src/components/utils/utilsTs.js +++ /dev/null @@ -1,210 +0,0 @@ -"use strict"; -/** - * Utils module - * @module Utils - */ -exports.__esModule = true; -exports.customStylesFormat = exports.customStyles = exports.nativeOptionMultiple = exports.nativeOptionOrdinary = exports.clearSelect = exports.createSelected = exports.checkItemStruct = exports.getSelectText = exports.getFormatItem = void 0; -/** - * Преобразование каждого елемента полученного из поля Items; - * @param {any} dataItem полученный елемент переданный при создании селекта может быть как object / string - * @param {number} index индекс этого элемента - * @returns {IItems} возвращает сформированный объект - */ -function getFormatItem(dataItem, index) { - var random = Math.random().toString(36).substring(2, 10); - var item; - if (checkItemStruct(dataItem)) { - return dataItem; - } - else { - item = { - id: random, - title: dataItem, - value: index - }; - return item; - } -} -exports.getFormatItem = getFormatItem; -/** - * Вставка изначального текста селекта(до выбора) - * @param {ITextSelect} data объект в котором находяться title селекта - * @param {HTMLElement | null | undefined} select елемент селекта, куда будет вставляться title - * @returns {HTMLElement} возвращает сформированный елемент селекта - */ -function getSelectText(data, select) { - var placeholder = data.placeholder, selected = data.selected; - if (placeholder) { - select.innerText = placeholder; - } - else if (selected) { - select.innerText = selected; - } - else { - select.innerText = 'Select...'; - } - return select; -} -exports.getSelectText = getSelectText; -/** - * Проверка содержит ли item указанные свойства, - * @param {object} item проверяемый на определенную структуру элемент - * @returns {boolean} возвращает true/false если item содержит указанные свойства - */ -function checkItemStruct(item) { - if (item && typeof item !== 'object') { - return false; - } - return item.hasOwnProperty('id') && item.hasOwnProperty('title') && item.hasOwnProperty('value'); -} -exports.checkItemStruct = checkItemStruct; -/** - * Создание кнопки выбора элементов - * @param {HTMLElement} element созданный экземпляр класса DropDown - * @param {string} content placeholer передаваемый из настроек селекта - * @param {object} styles не обязательный параметр. Объект в котором находяться настройки кастомизации частей селекта - */ -function createSelected(element, content, styles) { - var select = document.createElement('div'); - var selected = document.createElement('p'); - var caret = document.createElement('div'); - select.classList.add('cg-select'); - selected.classList.add('selected'); - caret.classList.add('caret'); - select.appendChild(selected); - select.appendChild(caret); - if (content) { - var text = document.createTextNode(content); - selected.appendChild(text); - element === null || element === void 0 ? void 0 : element.appendChild(select); - } - else if (styles) { - customStyles(element, styles); - select.setAttribute('style', "".concat(styles)); - selected.setAttribute('style', "".concat(styles)); - caret.setAttribute('style', "".concat(styles)); - } -} -exports.createSelected = createSelected; -/** - * Создание кнопки отчиски селекта, при единичном выборе. - * @param {HTMLElement} select место в селекте которое будет переназначено на ''. - * @param {Element} element экземпляр класса DropDown. - * @param {ISelectedItems} dataSelectText текст который отрисовывается в селекте. - */ -function clearSelect(select, element, dataSelectText) { - var selectedItems = dataSelectText.selectedItems, indexes = dataSelectText.indexes, darkTheme = dataSelectText.darkTheme, multiselectTag = dataSelectText.multiselectTag; - var options = element.querySelectorAll('.list__item'); - var ulMultiSelect = element.querySelector('.multiselect-tag'); - var svgIcon = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); - var path1 = document.createElementNS('http://www.w3.org/2000/svg', 'path'); - var path2 = document.createElementNS('http://www.w3.org/2000/svg', 'path'); - var checkBox = element.querySelectorAll('li input'); - svgIcon.setAttribute('viewBox', '0 0 10 10'); - path1.setAttribute('d', 'M2,8 L8,2'); - path2.setAttribute('d', 'M2,2 L8,8'); - svgIcon.appendChild(path1); - svgIcon.appendChild(path2); - if (multiselectTag) { - return; - } - if (darkTheme === true || !darkTheme) { - path1.classList.add('pathWhite'); - path2.classList.add('pathWhite'); - } - if (darkTheme === false) { - path1.classList.add('pathBlack'); - path2.classList.add('pathBlack'); - } - svgIcon.classList.add('svg-icon'); - svgIcon.classList.add('svg-clear'); - select.appendChild(svgIcon); - svgIcon.addEventListener('click', function () { - select.innerText = ''; - if (Array.isArray(selectedItems)) { - selectedItems.splice(0); - indexes.splice(0); - } - checkBox.forEach(function (item) { - if (item instanceof HTMLInputElement) { - item.checked = false; - } - }); - getSelectText(dataSelectText, select); - options.forEach(function (option) { - option.classList.remove('active'); - }); - }); -} -exports.clearSelect = clearSelect; -/** - * Поведение нативного(одинарного) селекта при выборе кастомного - * @param {NodeList} element NodeList нативного селекта - * @param {any} item выбранный элемент в кастомном селекте - */ -function nativeOptionOrdinary(element, item) { - element.forEach(function (option) { - option.removeAttribute('selected'); - if (option.textContent === item) { - option.setAttribute('selected', 'selected'); - } - }); -} -exports.nativeOptionOrdinary = nativeOptionOrdinary; -/** - * Поведение нативного(Multiple) селекта при выборе в кастомном - * @param {NodeListOf | undefined} element NodeList нативного селекта - * @param {string} item выбранный элемент в кастомном селекте - * @param {boolean} condition специальный флаг при котором добавляются/убераются атрибуты у нативного селекта - */ -function nativeOptionMultiple(element, item, condition) { - element.forEach(function (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; - } - }); -} -exports.nativeOptionMultiple = nativeOptionMultiple; -/** - * Поиск и стилизация елементов полученных из styles экземпляра DropDown - * @param {Element} element созданный экземпляр класса DropDown - * @param {object} styles объект в котором находяться настройки кастомизации частей селекта - */ -function customStyles(element, styles) { - var cgSelect = element.querySelector('.cg-select'); - var caretSelect = element.querySelector('.caret'); - var placeholderSelect = element.querySelector('.selected'); - var lableItem = element.parentElement.querySelector('h1.label'); - customStylesFormat(styles.head, cgSelect); - customStylesFormat(styles.caret, caretSelect); - customStylesFormat(styles.lable, lableItem); - if (placeholderSelect) { - customStylesFormat(styles.placeholder, placeholderSelect); - } -} -exports.customStyles = customStyles; -/** - * Универсальный метод для стилизации селекта - * @param {object} elemOption объект полученное из объекта styles у которого мы получаем ключ-значение стилей - * @param {HTMLElement} selector HTMLElement подвергающиеся кастомизации - */ -function customStylesFormat(elemOption, selector) { - if (elemOption) { - Object.entries(elemOption).forEach(function (_a) { - var key = _a[0], value = _a[1]; - selector.style[key] = value; - }); - } -} -exports.customStylesFormat = customStylesFormat; diff --git a/src/interfaces/cg-select.interface.js b/src/interfaces/cg-select.interface.js deleted file mode 100644 index 0e34578..0000000 --- a/src/interfaces/cg-select.interface.js +++ /dev/null @@ -1,2 +0,0 @@ -"use strict"; -exports.__esModule = true; diff --git a/src/interfaces/cg-select.interface.ts b/src/interfaces/cg-select.interface.ts index 8da039c..d020db4 100644 --- a/src/interfaces/cg-select.interface.ts +++ b/src/interfaces/cg-select.interface.ts @@ -5,7 +5,7 @@ export interface ICgSelect { * Уникальный селектор - *обязательный параметр(индефикатор), который задаеться при создании селекта. * @type {string} */ - selector: string; + selector?: string; /** * Необязательный параметр, в который передается элемент который будет выбран изначально в селекте. * @type {string} diff --git a/src/interfaces/items.interface.js b/src/interfaces/items.interface.js deleted file mode 100644 index 0e34578..0000000 --- a/src/interfaces/items.interface.js +++ /dev/null @@ -1,2 +0,0 @@ -"use strict"; -exports.__esModule = true; diff --git a/src/interfaces/language.interface.js b/src/interfaces/language.interface.js deleted file mode 100644 index 0e34578..0000000 --- a/src/interfaces/language.interface.js +++ /dev/null @@ -1,2 +0,0 @@ -"use strict"; -exports.__esModule = true; diff --git a/src/language/languageTS.js b/src/language/languageTS.js deleted file mode 100644 index 1e4e0ca..0000000 --- a/src/language/languageTS.js +++ /dev/null @@ -1,13 +0,0 @@ -"use strict"; -exports.__esModule = true; -exports.en = exports.ru = void 0; -exports.ru = { - selectPlaceholder: 'Выберите элемент...', - placeholder: 'Поиск...', - textInListSearch: 'Совпадений нет...' -}; -exports.en = { - selectPlaceholder: 'Select element...', - placeholder: 'Search...', - textInListSearch: 'No matches...' -}; diff --git a/tsconfig.json b/tsconfig.json index 2e03881..518d585 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -10,7 +10,7 @@ // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ /* Language and Environment */ - "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ + "target": "es2017", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ // "jsx": "preserve", /* Specify what JSX code is generated. */ // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ From 05422784672491e609c5e1d276fcadab6bbd3870 Mon Sep 17 00:00:00 2001 From: Max Date: Mon, 16 Jan 2023 15:43:45 +0300 Subject: [PATCH 18/21] Added descriptions in interfaces --- package.json | 2 +- .../create-element/create-element.interface.ts | 3 +++ src/components/utils/urils.interface.ts | 6 ++++++ src/interfaces/cg-select.interface.ts | 6 ++++++ src/interfaces/items.interface.ts | 3 +++ src/interfaces/language.interface.ts | 3 +++ tsconfig.json | 15 +++++++-------- 7 files changed, 29 insertions(+), 9 deletions(-) diff --git a/package.json b/package.json index 10a7f63..9b9c8b7 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "homepage": "https://cg-select.itguild.info", "scripts": { "start": "parcel example/index.html -p 4500 --open ", - "build": "parcel build index.js", + "build": "parcel build index.ts", "deploy": "gh-pages -d dist", "predeploy": "npm run build" }, diff --git a/src/components/create-element/create-element.interface.ts b/src/components/create-element/create-element.interface.ts index b0acac0..e80974e 100644 --- a/src/components/create-element/create-element.interface.ts +++ b/src/components/create-element/create-element.interface.ts @@ -1,5 +1,8 @@ import { ICgSelect } from '../../interfaces/cg-select.interface'; +/** + * @description Настройки для создания чипсов. + */ export interface ICreateBreadCrumb { /** * Определенный экземпляр класса. diff --git a/src/components/utils/urils.interface.ts b/src/components/utils/urils.interface.ts index 630f2ee..d5887a2 100644 --- a/src/components/utils/urils.interface.ts +++ b/src/components/utils/urils.interface.ts @@ -1,5 +1,8 @@ import { IItems } from '../../interfaces/items.interface'; +/** + * @description Настройки получаемых элементов. + */ export interface IDataItem { /** * Необязательный параметр. Категория группы элементов. @@ -18,6 +21,9 @@ export interface IDataItem { ItemValue: string | IItems | number; } +/** + * @description Настройки для текста селекта и тд. + */ export interface ISelectedItems { /** * Placeholder необязательный параметр, в который передается текст плейсхолдера селекта. diff --git a/src/interfaces/cg-select.interface.ts b/src/interfaces/cg-select.interface.ts index d020db4..6d0c9c1 100644 --- a/src/interfaces/cg-select.interface.ts +++ b/src/interfaces/cg-select.interface.ts @@ -1,5 +1,8 @@ import { IItems } from './items.interface'; +/** + * @description Настройки селекта. + */ export interface ICgSelect { /** * Уникальный селектор - *обязательный параметр(индефикатор), который задаеться при создании селекта. @@ -91,6 +94,9 @@ export interface ICgSelect { multiselectTag?: boolean; } +/** + * @description Настройки стилей. + */ export interface IStyle { /** * Кастомизация кнопки селекта. diff --git a/src/interfaces/items.interface.ts b/src/interfaces/items.interface.ts index b827cfd..a6c1616 100644 --- a/src/interfaces/items.interface.ts +++ b/src/interfaces/items.interface.ts @@ -1,3 +1,6 @@ +/** + * @description Строение элемента. + */ export interface IItems { /** * Уникальное ID элемента diff --git a/src/interfaces/language.interface.ts b/src/interfaces/language.interface.ts index c2665f7..c9a63e5 100644 --- a/src/interfaces/language.interface.ts +++ b/src/interfaces/language.interface.ts @@ -1,3 +1,6 @@ +/** + * @description Настройки для добавления языков. + */ export interface ILanguage { /** * Текст в поиске. diff --git a/tsconfig.json b/tsconfig.json index 518d585..358226c 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,5 @@ { "compilerOptions": { - /* Projects */ // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ @@ -10,7 +9,7 @@ // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ /* Language and Environment */ - "target": "es2017", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ + "target": "es2017" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ // "jsx": "preserve", /* Specify what JSX code is generated. */ // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ @@ -24,7 +23,7 @@ // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ /* Modules */ - "module": "commonjs", /* Specify what module code is generated. */ + "module": "commonjs" /* Specify what module code is generated. */, // "rootDir": "./", /* Specify the root folder within your source files. */ // "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ @@ -48,7 +47,7 @@ // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ - // "outDir": "./", /* Specify an output folder for all emitted files. */ + "outDir": "build" /* Specify an output folder for all emitted files. */, // "removeComments": true, /* Disable emitting comments. */ // "noEmit": true, /* Disable emitting files from a compilation. */ // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ @@ -70,12 +69,12 @@ /* Interop Constraints */ // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ - "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ + "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */, // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ - "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ + "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, /* Type Checking */ - "strict": true, /* Enable all strict type-checking options. */ + "strict": true /* Enable all strict type-checking options. */, // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ @@ -97,6 +96,6 @@ /* Completeness */ // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ - "skipLibCheck": true /* Skip type checking all .d.ts files. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */ } } From bf9dc01ad503d198d575a1beaf9df53ea68f87b9 Mon Sep 17 00:00:00 2001 From: Max Date: Mon, 16 Jan 2023 19:30:44 +0300 Subject: [PATCH 19/21] Fixed packege.json --- index.js | 3 -- package.json | 2 +- .../create-element.interface.ts | 2 +- src/components/utils/urils.interface.ts | 2 +- src/components/utils/utilsTs.ts | 7 ++--- src/language/languageTS.ts | 2 +- tsconfig.json | 30 ++++--------------- 7 files changed, 13 insertions(+), 35 deletions(-) delete mode 100644 index.js diff --git a/index.js b/index.js deleted file mode 100644 index f7f8241..0000000 --- a/index.js +++ /dev/null @@ -1,3 +0,0 @@ -import { DropDown } from './src/cg-select'; - -export default DropDown; diff --git a/package.json b/package.json index 9b9c8b7..99a468a 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "homepage": "https://cg-select.itguild.info", "scripts": { "start": "parcel example/index.html -p 4500 --open ", - "build": "parcel build index.ts", + "build": "parcel build ./src/cg-selectTS.ts --no-cache", "deploy": "gh-pages -d dist", "predeploy": "npm run build" }, diff --git a/src/components/create-element/create-element.interface.ts b/src/components/create-element/create-element.interface.ts index e80974e..88e9320 100644 --- a/src/components/create-element/create-element.interface.ts +++ b/src/components/create-element/create-element.interface.ts @@ -1,4 +1,4 @@ -import { ICgSelect } from '../../interfaces/cg-select.interface'; +import { ICgSelect } from 'interfaces/cg-select.interface'; /** * @description Настройки для создания чипсов. diff --git a/src/components/utils/urils.interface.ts b/src/components/utils/urils.interface.ts index d5887a2..a4df672 100644 --- a/src/components/utils/urils.interface.ts +++ b/src/components/utils/urils.interface.ts @@ -1,4 +1,4 @@ -import { IItems } from '../../interfaces/items.interface'; +import { IItems } from 'interfaces/items.interface'; /** * @description Настройки получаемых элементов. diff --git a/src/components/utils/utilsTs.ts b/src/components/utils/utilsTs.ts index c6cf502..16dbdfc 100644 --- a/src/components/utils/utilsTs.ts +++ b/src/components/utils/utilsTs.ts @@ -2,10 +2,9 @@ * Utils module * @module Utils */ - -import { IStyle } from '../../interfaces/cg-select.interface'; -import { IItems } from '../../interfaces/items.interface'; -import { IDataItem, ISelectedItems } from './urils.interface'; +import { IStyle } from 'interfaces/cg-select.interface'; +import { IItems } from 'interfaces/items.interface'; +import { ISelectedItems } from './urils.interface'; /** * Преобразование каждого елемента полученного из поля Items; diff --git a/src/language/languageTS.ts b/src/language/languageTS.ts index 41212b9..de90939 100644 --- a/src/language/languageTS.ts +++ b/src/language/languageTS.ts @@ -1,4 +1,4 @@ -import { ILanguage } from '../interfaces/language.interface'; +import { ILanguage } from 'interfaces/language.interface'; export const ru: ILanguage = { selectPlaceholder: 'Выберите элемент...', diff --git a/tsconfig.json b/tsconfig.json index 358226c..583ac15 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,4 +1,5 @@ { + "include": ["src/**/*", "index.ts"], "compilerOptions": { /* Projects */ // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ @@ -24,9 +25,9 @@ /* Modules */ "module": "commonjs" /* Specify what module code is generated. */, - // "rootDir": "./", /* Specify the root folder within your source files. */ + "rootDir": "./" /* Specify the root folder within your source files. */, // "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ - // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ + "baseUrl": "./src" /* Specify the base directory to resolve non-relative module names. */, // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ @@ -47,7 +48,7 @@ // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ - "outDir": "build" /* Specify an output folder for all emitted files. */, + "outDir": "./dist" /* Specify an output folder for all emitted files. */, // "removeComments": true, /* Disable emitting comments. */ // "noEmit": true, /* Disable emitting files from a compilation. */ // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ @@ -68,31 +69,12 @@ /* Interop Constraints */ // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ - // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ + "allowSyntheticDefaultImports": true /* Allow 'import x from y' when a module doesn't have a default export. */, "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */, // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, - /* Type Checking */ - "strict": true /* Enable all strict type-checking options. */, - // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ - // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ - // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ - // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ - // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ - // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ - // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ - // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ - // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ - // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ - // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ - // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ - // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ - // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ - // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ - // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ - // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ - // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ + "strict": true, /* Completeness */ // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ From 8897e12464c75908d43835c8719d1f474f91b876 Mon Sep 17 00:00:00 2001 From: Max Date: Tue, 17 Jan 2023 20:21:43 +0300 Subject: [PATCH 20/21] Debuging and repare code --- example/index.html | 4 +- example/index.js | 99 +++---- example/indexTs.ts | 268 +++++++++++++++--- index.ts => index.js | 0 package.json | 2 +- src/cg-selectTS.ts | 15 +- .../create-element/create-elementTs.ts | 6 +- src/components/utils/utilsTs.ts | 5 +- src/interfaces/cg-select.interface.ts | 5 + tsconfig.json | 2 +- 10 files changed, 306 insertions(+), 100 deletions(-) rename index.ts => index.js (100%) diff --git a/example/index.html b/example/index.html index 4a483c4..5582628 100644 --- a/example/index.html +++ b/example/index.html @@ -27,7 +27,7 @@ @@ -356,5 +356,5 @@ - + diff --git a/example/index.js b/example/index.js index a440293..e957dde 100644 --- a/example/index.js +++ b/example/index.js @@ -1,34 +1,34 @@ -import DropDown from '../index'; +import { CGSelect } from '../src/cg-selectTS'; import './example'; // ------------------------------Обычный селект-------------------- -// const dropdown = new DropDown({ -// selector: '.cg-dropdown_one', -// placeholder: 'Выберите авто', -// lable: 'EXAMPLE', -// items: [ -// 'BMW', -// { -// id: '213sade', -// title: 'Opel', -// value: 1, -// }, -// 'Mersedes', -// 'MAN', -// 'Ferari', -// ], -// styles: { -// head: { -// width: '830px', -// }, -// list: { -// width: '824px', -// }, -// }, -// }); +const dropdown = new CGSelect({ + selector: '.cg-dropdown_one', + placeholder: 'Выберите авто', + lable: 'EXAMPLE', + items: [ + 'BMW', + { + id: '213sade', + title: 'Opel', + value: 1, + }, + 'Mersedes', + 'MAN', + 'Ferari', + ], + styles: { + head: { + width: '830px', + }, + list: { + width: '824px', + }, + }, +}); // ------------------------------NativeSelect----------------------- -const dropdownNativeSelect = new DropDown({ +const dropdownNativeSelect = new CGSelect({ selector: '.cg-dropdown_selectNative', placeholder: 'Выберите авто', nativeSelectMode: true, @@ -43,7 +43,7 @@ const dropdownNativeSelect = new DropDown({ 'MAN', 'Ferari', 'Kamaz', - 'Ural' + 'Ural', ], styles: { head: { @@ -56,7 +56,7 @@ const dropdownNativeSelect = new DropDown({ }); // ------------------------------listDisplayMode-------------------- -const dropdownlistDisplayMode = new DropDown({ +const dropdownlistDisplayMode = new CGSelect({ selector: '.cg-dropdown_listDisplayMode', placeholder: 'Выберите авто', listDisplayMode: true, @@ -81,26 +81,8 @@ const dropdownlistDisplayMode = new DropDown({ }, }); -// ------------------------------URL-------------------- -const dropdown3 = new DropDown({ - selector: '.cg-dropdown_three', - placeholder: 'URL', - url: 'https://jsonplaceholder.typicode.com/users', - searchMode: true, - darkTheme: false, - language: 'ru', - styles: { - head: { - width: '830px', - }, - list: { - width: '824px', - }, - }, -}); - // --------------------------------Категории-------------------------- -const dropdown4 = new DropDown({ +const dropdown4 = new CGSelect({ selector: '.cg-dropdown_categories', placeholder: 'Выберите регион', searchMode: true, @@ -145,7 +127,7 @@ const dropdown4 = new DropDown({ }); //----------------управление с помощью кнопок---------------------------------- -const dropdownBtn = new DropDown({ +const dropdownBtn = new CGSelect({ selector: '.cg-dropdown_usedBtn', placeholder: 'Выберите авто', searchMode: true, @@ -192,7 +174,7 @@ dropdownBtn.buttonControl(buttonOpen, 'open'); dropdownBtn.buttonControl(buttonClose, 'close'); //-------------------------Функция Disabled---------------------------------- -const dropdownDisabled = new DropDown({ +const dropdownDisabled = new CGSelect({ selector: '.cg-dropdown_checkboxDisable', placeholder: 'Выберите авто', searchMode: true, @@ -230,3 +212,22 @@ chbox.addEventListener('click', () => { dropdownDisabled.disabled(true); } }); + +// ------------------------------URL-------------------- +const dropdown3 = new CGSelect({ + selector: '.cg-dropdown_three', + placeholder: 'URL', + url: 'https://jsonplaceholder.typicode.com/todos', + searchMode: true, + darkTheme: false, + language: 'ru', + styles: { + head: { + width: '830px', + }, + list: { + width: '824px', + }, + }, + multiselect: true, +}); diff --git a/example/indexTs.ts b/example/indexTs.ts index dfa4a3a..fd3ad5f 100644 --- a/example/indexTs.ts +++ b/example/indexTs.ts @@ -1,36 +1,234 @@ -import { CGSelect } from '../src/cg-selectTS'; +// import { CGSelect } from '../src/cg-selectTS'; +// import './example'; -const dropdn = new CGSelect({ - selector: '.cg-dropdown_one', - placeholder: 'Выберите авто', - items: [ - 'BMW', - { - id: '213sade', - title: 'Opel', - value: 1, - }, - 'Mersedes', - 'MAN', - 'max', - ], - styles: { - head: { - width: '830px', - }, - list: { - width: '824px', - }, - placeholder: { - maxWidth: '500px ', - }, - }, - // url - // listDisplayMode: true, - // searchMode: true, - // nativeSelectMode: true - // event: 'mouseenter', - // buttonControl - multiselect: true, - multiselectTag: true, -}); +// // ------------------------------Обычный селект-------------------- +// const dropdn = new CGSelect({ +// selector: '.cg-dropdown_one', +// placeholder: 'Выберите авто', +// lable: 'EXAMPLE', +// items: [ +// 'BMW', +// { +// id: '213sade', +// title: 'Opel', +// value: 1, +// }, +// 'Mersedes', +// 'MAN', +// 'Ferari', +// ], +// styles: { +// head: { +// width: '830px', +// }, +// list: { +// width: '824px', +// }, +// }, +// }); + +// // ------------------------------NativeSelect----------------------- +// const dropdownNativeSelect = new CGSelect({ +// selector: '.cg-dropdown_selectNative', +// placeholder: 'Выберите авто', +// nativeSelectMode: true, +// items: [ +// 'BMW', +// { +// id: '213sade', +// title: 'Opel', +// value: 1, +// }, +// 'Mersedes', +// 'MAN', +// 'Ferari', +// 'Kamaz', +// 'Ural', +// ], +// styles: { +// head: { +// width: '830px', +// }, +// list: { +// width: '824px', +// }, +// }, +// }); + +// // console.log(); + +// // ------------------------------listDisplayMode-------------------- +// const dropdownlistDisplayMode = new CGSelect({ +// selector: '.cg-dropdown_listDisplayMode', +// placeholder: 'Выберите авто', +// listDisplayMode: true, +// items: [ +// 'BMW', +// { +// id: '213sade', +// title: 'Opel', +// value: 1, +// }, +// 'Mersedes', +// 'MAN', +// 'Ferari', +// ], +// styles: { +// head: { +// width: '830px', +// }, +// list: { +// width: '824px', +// }, +// }, +// }); + +// // ------------------------------URL-------------------- +// const dropdown3 = new CGSelect({ +// selector: '.cg-dropdown_three', +// placeholder: 'URL', +// url: 'https://jsonplaceholder.typicode.com/users', +// searchMode: true, +// darkTheme: false, +// language: 'ru', +// styles: { +// head: { +// width: '830px', +// }, +// list: { +// width: '824px', +// }, +// }, +// }); + +// // --------------------------------Категории-------------------------- +// const dropdown4 = new CGSelect({ +// selector: '.cg-dropdown_categories', +// placeholder: 'Выберите регион', +// searchMode: true, +// items: [ +// { +// category: 'Russia', +// categoryItems: [ +// { +// id: '28qwds', +// title: 'Москва', +// value: 0, +// }, +// , +// 'Ростов-на-дону', +// 'Саратов', +// 'Волгоград', +// 'Донецк', +// ], +// }, +// { +// category: 'USA', +// categoryItems: ['Alabama', 'Texas', 'Colorado', 'Klirens', 'Los-Angeles'], +// }, +// { +// category: 'France', +// categoryItems: ['Paris'], +// }, +// ], +// styles: { +// head: { +// width: '830px', +// }, +// list: { +// width: '824px', +// }, +// placeholder: { +// maxWidth: '500px ', +// }, +// }, +// multiselect: true, +// multiselectTag: true, +// }); + +// //----------------управление с помощью кнопок---------------------------------- +// const dropdownBtn = new CGSelect({ +// selector: '.cg-dropdown_usedBtn', +// placeholder: 'Выберите авто', +// searchMode: true, +// items: [ +// 'BMW', +// { +// id: '213sade', +// title: 'Opel', +// value: 1, +// }, +// 'Mersedes', +// 'MAN', +// 'max', +// ], +// styles: { +// head: { +// width: '830px', +// color: 'black', +// backgroundColor: 'rgb(176 223 167)', +// }, +// list: { +// width: '824px', +// color: 'black', +// backgroundColor: 'rgb(176 223 167)', +// }, +// caret: { +// borderTop: '6px solid black', +// }, +// search: { +// backgroundColor: '#d7ffff', +// borderRadius: '5px', +// borderBottom: 'none', +// width: '95%', +// color: 'black', +// }, +// }, +// multiselect: true, +// }); + +// const buttonOpen = document.querySelector('.button__open'); +// const buttonClose = document.querySelector('.button__close'); + +// dropdownBtn.buttonControl(buttonOpen!, 'open'); +// dropdownBtn.buttonControl(buttonClose!, 'close'); + +// //-------------------------Функция Disabled---------------------------------- +// const dropdownDisabled = new CGSelect({ +// selector: '.cg-dropdown_checkboxDisable', +// placeholder: 'Выберите авто', +// searchMode: true, +// items: [ +// 'BMW', +// { +// id: '213sade', +// title: 'Opel', +// value: 1, +// }, +// 'Mersedes', +// 'MAN', +// 'max', +// ], +// styles: { +// head: { +// width: '830px', +// }, +// list: { +// width: '824px', +// }, +// placeholder: { +// maxWidth: '500px ', +// }, +// }, +// multiselect: true, +// }); +// dropdownDisabled.disabled(true); +// let chbox = document.getElementById('checkboxDisable') as HTMLInputElement; + +// chbox!.addEventListener('click', () => { +// if (chbox!.checked == true) { +// dropdownDisabled.disabled(false); +// } else { +// dropdownDisabled.disabled(true); +// } +// }); diff --git a/index.ts b/index.js similarity index 100% rename from index.ts rename to index.js diff --git a/package.json b/package.json index 99a468a..bba2e97 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "homepage": "https://cg-select.itguild.info", "scripts": { "start": "parcel example/index.html -p 4500 --open ", - "build": "parcel build ./src/cg-selectTS.ts --no-cache", + "build": "parcel build example/index.html --no-cache", "deploy": "gh-pages -d dist", "predeploy": "npm run build" }, diff --git a/src/cg-selectTS.ts b/src/cg-selectTS.ts index 4277e50..cf965e7 100644 --- a/src/cg-selectTS.ts +++ b/src/cg-selectTS.ts @@ -230,10 +230,11 @@ export class CGSelect implements ICgSelect { this.items = []; - if (!this.items && this.url) { + if (this.url && !items) { this.renderUrl(); return; } + createSelected; items.forEach((dataItem: any, index: number) => { @@ -373,12 +374,9 @@ export class CGSelect implements ICgSelect { * @description Рендер елементов в селекте переданных с URL и их настойка */ private async renderUrl() { - if (this.items || !this.url) { - return; - } - - const response = await fetch(this.url); + const response = await fetch(this.url!); const dataUrl = await response.json(); + console.log(dataUrl); const nativeSelect = createNativeSelect(); @@ -554,7 +552,10 @@ export class CGSelect implements ICgSelect { const select: HTMLElement | null | undefined = this.element?.querySelector('.selected'); const nativeOption = this.element!.querySelectorAll('.nativeSelect__nativeOption'); - let selectedItemsClear: ISelectedItems; + let selectedItemsClear: ISelectedItems = { + placeholder: this.placeholder!, + selected: this.selected!, + }; const ulMultipul = document.createElement('ul'); diff --git a/src/components/create-element/create-elementTs.ts b/src/components/create-element/create-elementTs.ts index 83786c2..6564e76 100644 --- a/src/components/create-element/create-elementTs.ts +++ b/src/components/create-element/create-elementTs.ts @@ -1,4 +1,4 @@ -import { nativeOptionMultiple } from '../utils/utilsTs'; +import { customStylesFormat, nativeOptionMultiple } from '../utils/utilsTs'; import { ICreateBreadCrumb } from './create-element.interface'; /** @@ -63,8 +63,8 @@ export function createBreadCrumb( liChip.appendChild(svgIcon); if (styles) { - // const { chips } = styles; - // customStylesFormat(chips, liChip); + const { chips } = styles; + customStylesFormat(chips!, liChip); } svgIcon.addEventListener('click', (event) => { diff --git a/src/components/utils/utilsTs.ts b/src/components/utils/utilsTs.ts index 16dbdfc..b4d0773 100644 --- a/src/components/utils/utilsTs.ts +++ b/src/components/utils/utilsTs.ts @@ -48,6 +48,7 @@ export function getSelectText( } else { select!.innerText = 'Select...'; } + return select!; } @@ -116,7 +117,7 @@ export function clearSelect(select: HTMLElement, element: Element, dataSelectTex svgIcon.appendChild(path1); svgIcon.appendChild(path2); - if (multiselectTag) { + if (multiselectTag && multiselectTag == true) { return; } @@ -162,7 +163,7 @@ export function clearSelect(select: HTMLElement, element: Element, dataSelectTex * @param {NodeList} element NodeList нативного селекта * @param {any} item выбранный элемент в кастомном селекте */ -export function nativeOptionOrdinary(element: NodeListOf | undefined, item: any) { +export function nativeOptionOrdinary(element: NodeListOf | undefined, item: string) { element!.forEach((option) => { option.removeAttribute('selected'); if (option.textContent === item) { diff --git a/src/interfaces/cg-select.interface.ts b/src/interfaces/cg-select.interface.ts index 6d0c9c1..1d7d7e6 100644 --- a/src/interfaces/cg-select.interface.ts +++ b/src/interfaces/cg-select.interface.ts @@ -128,4 +128,9 @@ export interface IStyle { * @type {object} */ search?: object; + /** + * Кастомизация чипсов с выбранными элементами + * @type {object} + */ + chips?: object; } diff --git a/tsconfig.json b/tsconfig.json index 583ac15..85dd01f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,5 +1,5 @@ { - "include": ["src/**/*", "index.ts"], + // "include": ["src/**/*", "index.ts"], "compilerOptions": { /* Projects */ // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ From ba6def3f218600ffd4ff35a550d64e5936faa062 Mon Sep 17 00:00:00 2001 From: Max Date: Wed, 18 Jan 2023 19:40:24 +0300 Subject: [PATCH 21/21] Finished in working to TS --- CHANGELOG.md | 2 +- README.md | 5 +- example/index.html | 17 +- example/index.js | 2 +- example/indexTs.ts | 234 ----- index.js | 2 +- package.json | 2 +- src/cg-select.js | 923 ------------------ src/{cg-selectTS.ts => cg-select.ts} | 26 +- src/components/create-element.js | 121 --- ...{create-elementTs.ts => create-element.ts} | 2 +- src/components/utils.js | 227 ----- src/components/utils/{utilsTs.ts => utils.ts} | 9 +- src/language/language.js | 11 - src/language/{languageTS.ts => language.ts} | 0 15 files changed, 34 insertions(+), 1549 deletions(-) delete mode 100644 example/indexTs.ts delete mode 100644 src/cg-select.js rename src/{cg-selectTS.ts => cg-select.ts} (99%) delete mode 100644 src/components/create-element.js rename src/components/create-element/{create-elementTs.ts => create-element.ts} (99%) delete mode 100644 src/components/utils.js rename src/components/utils/{utilsTs.ts => utils.ts} (97%) delete mode 100644 src/language/language.js rename src/language/{languageTS.ts => language.ts} (100%) diff --git a/CHANGELOG.md b/CHANGELOG.md index f179c9c..fb88d10 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,4 +24,4 @@ ### 00.00.2023 - обновление 0.2.1 - Весь селект переписан на ts. -- Документация и реадми переписаны на Английский. +- Исправленны баги и недочеты. diff --git a/README.md b/README.md index 0fcabf1..c820155 100644 --- a/README.md +++ b/README.md @@ -45,10 +45,9 @@ npm i cg-select ### Пример создния обычного селекта ```javascript -import { DropDown } from 'cg-select/src/cg-select'; -import 'cg-select/src/main.scss'; +import { CGSelect } from 'cg-select'; -const dropdown = new DropDown({ +const dropdown = new CGSelect({ selector: '.cg-dropdown_selector', placeholder: 'Выберите авто', items: [ diff --git a/example/index.html b/example/index.html index 5582628..f0d4cda 100644 --- a/example/index.html +++ b/example/index.html @@ -27,7 +27,7 @@ @@ -46,7 +46,7 @@
-              const dropdown = new DropDown({
+              const dropdown = new CGSelect({
                 selector: '.cg-dropdown_one', 
                 placeholder: 'Выберите авто', 
                 lable: 'EXAMPLE', 
@@ -89,7 +89,7 @@
           
           
             
-              const dropdown = new DropDown({
+              const dropdown = new CGSelect({
                 selector: '.cg-dropdown_one', 
                 placeholder: 'Выберите авто', 
                 nativeSelectMode: true,
@@ -133,7 +133,7 @@
 
           
             
-              const dropdown = new DropDown({
+              const dropdown = new CGSelect({
                 selector: '.cg-dropdown_listDisplayMode', 
                 placeholder: 'Выберите авто', 
                 listDisplayMode: true,
@@ -171,7 +171,7 @@
 
         
           
-            const dropdown = new DropDown({
+            const dropdown = new CGSelect({
               selector: '.cg-dropdown_three', 
               placeholder: 'URL', 
               url: 'https://jsonplaceholder.typicode.com/users',            
@@ -201,7 +201,7 @@
 
         
           
-            const dropdown = new DropDown({
+            const dropdown = new CGSelect({
               selector: '.cg-dropdown_categories', 
               placeholder: 'Выберите регион', 
               searchMode: true,
@@ -267,7 +267,7 @@
 
         
           
-            const dropdown = new DropDown({
+            const dropdown = new CGSelect({
               selector: '.cg-dropdown_usedBtn', 
               placeholder: 'Выберите авто', 
               searchMode: true,
@@ -323,7 +323,7 @@
         
         
           
-            const dropdown = new DropDown({
+            const dropdown = new CGSelect({
               selector: '.cg-dropdown_checkboxDisable', 
               placeholder: 'Выберите авто', 
               searchMode: true,
@@ -356,5 +356,4 @@
     
   
   
-  
 
diff --git a/example/index.js b/example/index.js
index e957dde..55d9aaa 100644
--- a/example/index.js
+++ b/example/index.js
@@ -1,4 +1,4 @@
-import { CGSelect } from '../src/cg-selectTS';
+import { CGSelect } from '../src/cg-select';
 import './example';
 
 // ------------------------------Обычный селект--------------------
diff --git a/example/indexTs.ts b/example/indexTs.ts
deleted file mode 100644
index fd3ad5f..0000000
--- a/example/indexTs.ts
+++ /dev/null
@@ -1,234 +0,0 @@
-// import { CGSelect } from '../src/cg-selectTS';
-// import './example';
-
-// // ------------------------------Обычный селект--------------------
-// const dropdn = new CGSelect({
-//   selector: '.cg-dropdown_one',
-//   placeholder: 'Выберите авто',
-//   lable: 'EXAMPLE',
-//   items: [
-//     'BMW',
-//     {
-//       id: '213sade',
-//       title: 'Opel',
-//       value: 1,
-//     },
-//     'Mersedes',
-//     'MAN',
-//     'Ferari',
-//   ],
-//   styles: {
-//     head: {
-//       width: '830px',
-//     },
-//     list: {
-//       width: '824px',
-//     },
-//   },
-// });
-
-// // ------------------------------NativeSelect-----------------------
-// const dropdownNativeSelect = new CGSelect({
-//   selector: '.cg-dropdown_selectNative',
-//   placeholder: 'Выберите авто',
-//   nativeSelectMode: true,
-//   items: [
-//     'BMW',
-//     {
-//       id: '213sade',
-//       title: 'Opel',
-//       value: 1,
-//     },
-//     'Mersedes',
-//     'MAN',
-//     'Ferari',
-//     'Kamaz',
-//     'Ural',
-//   ],
-//   styles: {
-//     head: {
-//       width: '830px',
-//     },
-//     list: {
-//       width: '824px',
-//     },
-//   },
-// });
-
-// // console.log();
-
-// // ------------------------------listDisplayMode--------------------
-// const dropdownlistDisplayMode = new CGSelect({
-//   selector: '.cg-dropdown_listDisplayMode',
-//   placeholder: 'Выберите авто',
-//   listDisplayMode: true,
-//   items: [
-//     'BMW',
-//     {
-//       id: '213sade',
-//       title: 'Opel',
-//       value: 1,
-//     },
-//     'Mersedes',
-//     'MAN',
-//     'Ferari',
-//   ],
-//   styles: {
-//     head: {
-//       width: '830px',
-//     },
-//     list: {
-//       width: '824px',
-//     },
-//   },
-// });
-
-// // ------------------------------URL--------------------
-// const dropdown3 = new CGSelect({
-//   selector: '.cg-dropdown_three',
-//   placeholder: 'URL',
-//   url: 'https://jsonplaceholder.typicode.com/users',
-//   searchMode: true,
-//   darkTheme: false,
-//   language: 'ru',
-//   styles: {
-//     head: {
-//       width: '830px',
-//     },
-//     list: {
-//       width: '824px',
-//     },
-//   },
-// });
-
-// // --------------------------------Категории--------------------------
-// const dropdown4 = new CGSelect({
-//   selector: '.cg-dropdown_categories',
-//   placeholder: 'Выберите регион',
-//   searchMode: true,
-//   items: [
-//     {
-//       category: 'Russia',
-//       categoryItems: [
-//         {
-//           id: '28qwds',
-//           title: 'Москва',
-//           value: 0,
-//         },
-//         ,
-//         'Ростов-на-дону',
-//         'Саратов',
-//         'Волгоград',
-//         'Донецк',
-//       ],
-//     },
-//     {
-//       category: 'USA',
-//       categoryItems: ['Alabama', 'Texas', 'Colorado', 'Klirens', 'Los-Angeles'],
-//     },
-//     {
-//       category: 'France',
-//       categoryItems: ['Paris'],
-//     },
-//   ],
-//   styles: {
-//     head: {
-//       width: '830px',
-//     },
-//     list: {
-//       width: '824px',
-//     },
-//     placeholder: {
-//       maxWidth: '500px ',
-//     },
-//   },
-//   multiselect: true,
-//   multiselectTag: true,
-// });
-
-// //----------------управление с помощью кнопок----------------------------------
-// const dropdownBtn = new CGSelect({
-//   selector: '.cg-dropdown_usedBtn',
-//   placeholder: 'Выберите авто',
-//   searchMode: true,
-//   items: [
-//     'BMW',
-//     {
-//       id: '213sade',
-//       title: 'Opel',
-//       value: 1,
-//     },
-//     'Mersedes',
-//     'MAN',
-//     'max',
-//   ],
-//   styles: {
-//     head: {
-//       width: '830px',
-//       color: 'black',
-//       backgroundColor: 'rgb(176 223 167)',
-//     },
-//     list: {
-//       width: '824px',
-//       color: 'black',
-//       backgroundColor: 'rgb(176 223 167)',
-//     },
-//     caret: {
-//       borderTop: '6px solid black',
-//     },
-//     search: {
-//       backgroundColor: '#d7ffff',
-//       borderRadius: '5px',
-//       borderBottom: 'none',
-//       width: '95%',
-//       color: 'black',
-//     },
-//   },
-//   multiselect: true,
-// });
-
-// const buttonOpen = document.querySelector('.button__open');
-// const buttonClose = document.querySelector('.button__close');
-
-// dropdownBtn.buttonControl(buttonOpen!, 'open');
-// dropdownBtn.buttonControl(buttonClose!, 'close');
-
-// //-------------------------Функция Disabled----------------------------------
-// const dropdownDisabled = new CGSelect({
-//   selector: '.cg-dropdown_checkboxDisable',
-//   placeholder: 'Выберите авто',
-//   searchMode: true,
-//   items: [
-//     'BMW',
-//     {
-//       id: '213sade',
-//       title: 'Opel',
-//       value: 1,
-//     },
-//     'Mersedes',
-//     'MAN',
-//     'max',
-//   ],
-//   styles: {
-//     head: {
-//       width: '830px',
-//     },
-//     list: {
-//       width: '824px',
-//     },
-//     placeholder: {
-//       maxWidth: '500px ',
-//     },
-//   },
-//   multiselect: true,
-// });
-// dropdownDisabled.disabled(true);
-// let chbox = document.getElementById('checkboxDisable') as HTMLInputElement;
-
-// chbox!.addEventListener('click', () => {
-//   if (chbox!.checked == true) {
-//     dropdownDisabled.disabled(false);
-//   } else {
-//     dropdownDisabled.disabled(true);
-//   }
-// });
diff --git a/index.js b/index.js
index 37a4489..d3c8b2f 100644
--- a/index.js
+++ b/index.js
@@ -1,3 +1,3 @@
-import { CGSelect } from './src/cg-selectTS';
+import { CGSelect } from './src/cg-select';
 
 export default CGSelect;
diff --git a/package.json b/package.json
index bba2e97..125c31c 100644
--- a/package.json
+++ b/package.json
@@ -9,7 +9,7 @@
   "homepage": "https://cg-select.itguild.info",
   "scripts": {
     "start": "parcel example/index.html -p 4500 --open ",
-    "build": "parcel build example/index.html --no-cache",
+    "build": "parcel build example/index.js --no-cache",
     "deploy": "gh-pages -d dist",
     "predeploy": "npm run build"
   },
diff --git a/src/cg-select.js b/src/cg-select.js
deleted file mode 100644
index 3230143..0000000
--- a/src/cg-select.js
+++ /dev/null
@@ -1,923 +0,0 @@
-import {
-  createSelected,
-  customStyles,
-  getFormatItem,
-  getSelectText,
-  customStylesFormat,
-  nativeOptionMultiple,
-  nativeOptionOrdinary,
-  clearSelect,
-} from './components/utils';
-import {
-  createBreadcrumb,
-  createInputSearch,
-  createNativeSelectOption,
-  createNativeSelect,
-} from './components/create-element';
-import { ru, en } from './language/language';
-import './main.scss'
-
-/**
- * @class Описание класса DropDown
- * @description Этот класс реализовывает функционал кастомного селекта, с возможностями кастомизации.
- * @author Овсяников Максим
- */
-export class DropDown {
-  /**
-   * Созданный HTML елемент
-   * @type {HTMLElement}
-   */
-  #element;
-  /**
-   * Созданный список(ul), с классом list
-   * @type {HTMLElement}
-   */
-  #list;
-  /**
-   * Настройки селекта передаваемые при создании экземпляра класса
-   * @type {object}
-   */
-  #options;
-  /**
-   * Переменная для управления каретки
-   * @type {HTMLElement}
-   */
-  #caret;
-  /**
-   * Массив переданных элементов
-   * @type {object[]}
-   */
-  #items;
-  /**
-   * Переданные категории
-   * @type {string}
-   */
-  #category;
-  /**
-   * Выбранный или массив выбранных элементов из списка
-   * @type {object[] | object}
-   */
-  #selectedItems;
-  /**
-   * Массив индексов выбранных элементов
-   * @type {number[]}
-   */
-  #indexes = [];
-
-  /**
-   * Метод экземпляра класса DropDown
-   * @returns {string[] | string | null} Возвращает выбранные элемент(ы) в виде массива/элемента/null
-   * @description Геттер возвращающий выбранные элемент(ы) селекта
-   */
-  get value() {
-    return this.#selectedItems ?? null;
-  }
-
-  /**
-   * Метод экземпляра класса DropDown
-   * @returns {number | number[]}Возвращает индексы выбранных элемента(ов) в виде массива/пустой массив
-   * @description Геттер возвращающий индексы выбранных элемента(ов) селекта
-   */
-  get indexes() {
-    return this.#indexes ?? [];
-  }
-
-  /**
-   *
-   * @param {object} options Объект принимающий настройки селекта
-   * @constructor Конструктор класса DropDown
-   * @description  Конструктор принимает объект и рендерит селект.
-   * @example
-   * options = {
-   *  selector: 'Уникальный селектор',
-      selected: 'Выбранный элемент',
-      placeholder: '...',
-      lable: '...'
-      items: [string|number|object],
-      darkTheme: true/false,
-      searchMode: true/false,
-      closeOnSelect:  true/false,
-      nativeSelectMode: true/false,
-      listDisplayMode: true/false,
-      language: 'ru/en',
-      styles: {
-        head: {
-          background: '...',
-        },
-        list: {...},
-        chips: {...},
-        caret: {...},
-        placeholder: {...},
-        lable: {..},
-      },
-      event: '...',
-      url: 'http/...',
-      multiselect: true/false,
-      multiselectTag: true/false,
-   * }
-     
-   */
-  constructor(options = {}) {
-    this.#init(options);
-    this.#render();
-    this.#initEvent();
-    this.#closeSelectClick();
-  }
-
-  /**
-   * Метод экземпляра класса DropDown
-   * @param {string | object} item добавляемый елемент
-   * @description добавляет переданный элемент в конец списка и перерисовывает список. Не может использоваться при передачи элементов с категорями
-   * @method addItem
-   */
-  addItem(item) {
-    if (this.#category) {
-      console.log('can`t add item to category');
-      return;
-    }
-
-    if (!item) {
-      return false;
-    }
-
-    const index = this.#items.length;
-
-    this.#items.push(getFormatItem(item, index));
-    this.#render();
-  }
-
-  /**
-   * Метод экземпляра класса DropDown
-   * @param {number} index индекс удаляемого элемента
-   * @description удаляет елемент по индексу из списка и перерисовывает его. Не может использоваться при передачи элементов с категорями.
-   * @method deleteItem
-   */
-  deleteItem(index) {
-    if (this.#category) {
-      console.log('can`t add item to category');
-      return;
-    }
-
-    const item = this.#items[index];
-
-    this.#items.splice(index, 1);
-    this.#render();
-  }
-
-  /**
-   * Метод экземпляра класса DropDown
-   * @description удаляет все елементы из списка и перерисовывает его.
-   * @method deleteItemAll
-   */
-  deleteItemAll() {
-    this.#items.splice(0, this.#items.length);
-    this.#render();
-  }
-
-  /**
-   * Метод экземпляра класса DropDown
-   * @param {number} index индекс выбранного элемента
-   * @description  выбирает элемент который будет изначально отрисовываться в селекте
-   * @method selectIndex
-   */
-  selectIndex(index) {
-    if (this.#category) {
-      console.log('can`t add item to category');
-      return;
-    }
-
-    const options = this.#element.querySelectorAll('.list__item');
-
-    if (index > options.length) {
-      return;
-    }
-
-    const select = options[index].innerText;
-    this.#render(select);
-  }
-
-  /**
-   * Метод экземпляра класса DropDown
-   * @param {number} numberItem номер возвращаемого элемента
-   * @returns {HTMLElement} возвращает ссылку на выбранный HTML элемент
-   * @method getElement
-   */
-  getElement(numberItem) {
-    if (numberItem > this.#items.length) {
-      return;
-    }
-    return this.#items[numberItem];
-  }
-
-  /**
-   * Метод экземпляра класса DropDown
-   * @param {boolean} value - Передаваемый параметр для добавления атрибута disabled;
-   * @description Метод позволяющий переключать состояние селекта disabled,
-   * @method disabled
-   */
-  disabled(value) {
-    if (typeof value !== 'boolean') {
-      return;
-    }
-
-    const select = this.#element.querySelector('.cg-select');
-    const nativeSelect = this.#element.querySelector('.nativeSelect');
-    if (value === true) {
-      this.#element.setAttribute('disabled', true);
-      nativeSelect.setAttribute('disabled', true);
-      select.classList.add('disabled');
-    } else {
-      this.#element.removeAttribute('disabled');
-      nativeSelect.removeAttribute('disabled');
-      select.classList.remove('disabled');
-    }
-  }
-
-  /**
-   * Метод экземпляра класса DropDown
-   * @param {HTMLInputElement} button - HTML кнопка
-   * @param {string} method - метод открытия open/close
-   * @description Метод позволяющий открывать/закрывать селект с помощью кнопок
-   * @method buttonControl
-   */
-  buttonControl(button, method) {
-    const { listDisplayMode } = this.#options;
-
-    if (listDisplayMode === true) {
-      return;
-    }
-
-    this.btn = button;
-    button.addEventListener('click', () => {
-      if (method.toLowerCase() === 'open') {
-        this.#open(true);
-      } else if (method.toLowerCase() === 'close') {
-        this.#close();
-      } else {
-        return;
-      }
-    });
-  }
-
-  /**
-   * Метод экземпляра класса DropDown
-   * @param {object} language объект в котором находятся поля для подключения языка имеет два обязательных поля placeholder, textInListSearch
-   * @description метод позволяющий заменить плейсхолдер в поиске и текст который выводится если нет результата
-   * @method addLanguage
-   */
-  addLanguage(language) {
-    const { placeholder, textInListSearch, selectPlaceholder } = language;
-    const { searchMode } = this.#options;
-
-    const select = this.#element.querySelector('.selected');
-    const textNodeSelect = document.createTextNode(selectPlaceholder);
-    select.appendChild(textNodeSelect);
-
-    if (searchMode && searchMode == true) {
-      const search = this.#element.querySelector('.inputSearch');
-      const textNoRezult = this.#element.querySelector('.noRezult');
-      const textNode = document.createTextNode(textInListSearch);
-
-      search.setAttribute('placeholder', placeholder);
-      search.setAttribute('placeholder', placeholder);
-
-      textNoRezult.innerText = '';
-      textNoRezult.appendChild(textNode);
-    }
-  }
-
-  /**
-   * Приватный метод инициализации экземпляра класса DropDown
-   * @method #init
-   * @member
-   * @protected
-   * @param {object} options передаваемые настройки селекта
-   * @description Приватный метод. Общая инициализация селекта. Получение настоек и преобразвание элементов селекта.
-   * @example
-   *  {
-        selector: '.cg-dropdown_one',
-        placeholder: 'Выберите авто',
-        items: [
-          'BMW',
-          {
-            id: '213sade',
-            title: 'Opel',
-            value: 1,
-          },
-          'Mersedes',
-          'MAN',
-          'max',
-        ],
-        darkTheme: true,
-        multiselect: true,
-        multiselectTag: true,
-      }
-   */
-  #init(options) {
-    this.#options = options;
-    const { items, multiselect, url } = this.#options;
-
-    const elem = document.querySelector(options.selector);
-
-    //TODO: для теста в реакте нужно пересмотреть необходимость этой проверки!
-    // if (!elem) {
-    //   throw new Error(`Element with selector ${options.selector}`);
-    // }
-
-    this.#element = elem;
-
-    this.#element.addEventListener('click', (e) => {
-      e.preventDefault();
-      this.#open();
-    });
-
-    this.#items = [];
-
-    if (multiselect && multiselect == true) {
-      this.#selectedItems = [];
-    }
-
-    if (!items && url) {
-      this.#renderUrl();
-      return;
-    }
-
-    items.forEach((dataItem, index) => {
-      if (dataItem.category && dataItem.categoryItems) {
-        this.#category = dataItem.category;
-
-        this.#items.push(this.#category);
-        dataItem.categoryItems.forEach((categoryItem, indexCategory) => {
-          this.#items.push(getFormatItem(categoryItem, indexCategory));
-        });
-      } else {
-        this.#items.push(getFormatItem(dataItem, index));
-      }
-    });
-  }
-
-  /**
-   * Привaтный метод экземпляра класса DropDown
-   *
-   * @method #initSelected
-   * @param {string} select необязательный елемент. Используется в методе selectIndex
-   * @description Отрисовывает и стилизует селект
-   * @protected
-   */
-  #initSelected(select) {
-    const { styles, selected, placeholder, lable, language } = this.#options;
-
-    if (selected) {
-      createSelected(this.#element, selected);
-    } else if (placeholder) {
-      createSelected(this.#element, placeholder);
-    } else {
-      if (language && language === 'ru') {
-        createSelected(this.#element, ru.selectPlaceholder);
-      } else {
-        createSelected(this.#element, en.selectPlaceholder);
-      }
-    }
-
-    if (select) {
-      createSelected(this.#element, select, styles);
-    }
-
-    if (lable) {
-      const lableItem = document.createElement('h1');
-      const textLable = document.createTextNode(lable);
-
-      lableItem.appendChild(textLable);
-      lableItem.classList.add('label');
-
-      this.#element.insertAdjacentElement('beforebegin', lableItem);
-    }
-
-    if (styles) {
-      customStyles(this.#element, styles);
-    }
-  }
-
-  /**
-   * Приватный метод рендера экземпляра класса DropDown
-   *@protected
-   * @method #render
-   * @param {string} select  необязательный елемент. Передаеться в метод initSelected
-   * @description Рендер елементов в селекте.
-   */
-  #render(select) {
-    const {
-      styles,
-      multiselect,
-      searchMode,
-      multiselectTag,
-      darkTheme,
-      language,
-      nativeSelectMode,
-      listDisplayMode,
-    } = this.#options;
-
-    const random = Math.random().toString(36).substring(2, 10);
-
-    if (select || (select && styles)) {
-      this.#initSelected(select);
-      customStyles(this.#element, styles);
-    } else {
-      this.#initSelected();
-    }
-
-    const ulList = document.createElement('ul');
-    const nativeSelect = createNativeSelect();
-
-    let inputSearch = '';
-    this.random = random;
-
-    if (searchMode) {
-      if (language === 'ru') {
-        inputSearch = createInputSearch(random, ru.placeholder);
-      } else {
-        inputSearch = createInputSearch(random, en.placeholder);
-      }
-      const { search } = styles;
-      customStylesFormat(search, inputSearch);
-      ulList.appendChild(inputSearch);
-    }
-
-    ulList.classList.add('list');
-
-    if (styles) {
-      const { list } = styles;
-      customStylesFormat(list, ulList);
-    }
-
-    this.#element.appendChild(ulList);
-
-    this.#items.forEach((dataItem) => {
-      this.#element.appendChild(nativeSelect);
-
-      const liItem = document.createElement('li');
-      const nativeOption = createNativeSelectOption();
-      const strongItem = document.createElement('strong');
-
-      liItem.classList.add('list__item');
-      strongItem.classList.add('category');
-
-      if (multiselect && multiselect == true) {
-        const checkBox = document.createElement('input');
-        checkBox.type = 'checkbox';
-        checkBox.setAttribute('id', `chbox-${dataItem.id}`);
-        liItem.appendChild(checkBox);
-
-        if (multiselectTag && multiselectTag == true) {
-          checkBox.classList.add('displayHide');
-        }
-
-        nativeSelect.setAttribute('multiple', 'multiple');
-      }
-
-      let textNode = '';
-
-      if (dataItem.title) {
-        nativeOption.text = dataItem.title;
-        nativeOption.value = dataItem.title;
-        textNode = document.createTextNode(dataItem.title);
-
-        nativeSelect.appendChild(nativeOption);
-        liItem.appendChild(textNode);
-        ulList.appendChild(liItem);
-      } else {
-        textNode = document.createTextNode(dataItem);
-        strongItem.appendChild(textNode);
-        ulList.appendChild(strongItem);
-      }
-    });
-
-    this.#items.filter((item, index) => {
-      if (typeof item !== 'object') {
-        this.#items.splice(index, 1);
-      }
-      return item;
-    });
-
-    if (darkTheme == false) {
-      this.#checkTheme();
-    }
-
-    if (nativeSelectMode === true) {
-      this.#selectMode(nativeSelectMode);
-    }
-
-    this.#list = this.#element.querySelector('.list');
-    this.#caret = this.#element.querySelector('.caret');
-
-    if (listDisplayMode === true) {
-      this.#displayMode(listDisplayMode);
-    }
-
-    this.#addOptionsBehaviour();
-  }
-
-  /**
-   * Приватный метод рендера экземпляра класса DropDown
-   * @protected
-   * @method #checkTheme
-   * @description Изменяет цветовую схему с темной на светлую.
-   */
-  #checkTheme() {
-    const { darkTheme, searchMode } = this.#options;
-
-    const select = this.#element.querySelector('.cg-select');
-    const caret = this.#element.querySelector('.caret');
-    const list = this.#element.querySelector('ul.list');
-    const search = this.#element.querySelector('.inputSearch');
-
-    if (darkTheme == false) {
-      select.classList.add('selectWhite');
-      caret.classList.add('caretWhite');
-      list.classList.add('listWhite');
-
-      if (searchMode == true) {
-        search.classList.add('inputWhite');
-      }
-    } else if (darkTheme == true || !darkTheme) {
-      return;
-    } else {
-      throw new Error('Styles error or invalid value entered!');
-    }
-  }
-
-  /**
-   * Приватный метод рендера экземпляра класса DropDown
-   * @protected
-   * @method #renderUrl
-   * @description Рендер елементов в селекте переданных с URL и их настойка
-   */
-  async #renderUrl() {
-    const { url, items, multiselect, multiselectTag } = this.#options;
-
-    if (items) {
-      return;
-    }
-
-    if (!url) {
-      return;
-    }
-
-    const response = await fetch(url);
-    const dataUrl = await response.json();
-
-    const nativeSelect = createNativeSelect();
-
-    dataUrl.forEach((dataItem, index) => {
-      const item = {
-        id: dataItem.id,
-        title: dataItem.name,
-        value: index,
-      };
-      const ulUrl = this.#element.querySelector('.list');
-
-      const nativeOption = createNativeSelectOption();
-      const liUrl = document.createElement('li');
-      const textUrl = document.createTextNode(item.title);
-
-      if (multiselect && multiselect == true) {
-        const checkBox = document.createElement('input');
-        checkBox.type = 'checkbox';
-        if (multiselectTag && multiselectTag == true) {
-          checkBox.classList.add('displayHide');
-        }
-
-        checkBox.setAttribute('id', `chbox-${item.id}`);
-        nativeSelect.setAttribute('multiple', 'multiple');
-
-        liUrl.appendChild(checkBox);
-      }
-
-      liUrl.classList.add('list__item');
-      nativeOption.value = item.title;
-      nativeOption.text = item.title;
-
-      nativeSelect.appendChild(nativeOption);
-      liUrl.appendChild(textUrl);
-      ulUrl.appendChild(liUrl);
-
-      this.#items.push(item);
-    });
-
-    this.#element.appendChild(nativeSelect);
-
-    this.#items.filter((item, index) => {
-      if (typeof item !== 'object') {
-        this.#items.splice(index, 1);
-      }
-      return item;
-    });
-
-    this.#addOptionsBehaviour();
-  }
-
-  /**
-   * Приватный метод экземпляра класса DropDown
-   * @protected
-   * @param {boolean} oneClick необязательный параметр передаваемый из функции buttonControl
-   * @description Открывает список для выбора элемента
-   * @method #open
-   */
-  #open(oneClick) {
-    if (oneClick === true) {
-      this.#list.classList.add('open');
-      this.#caret.classList.add('caret_rotate');
-    } else {
-      this.#list.classList.toggle('open');
-      this.#caret.classList.toggle('caret_rotate');
-    }
-  }
-
-  /**
-   * Приватный метод экземпляра класса DropDown
-   * @protected
-   * @description Закрывает список
-   * @method #close
-   */
-  #close() {
-    this.#list.classList.remove('open');
-    this.#caret.classList.remove('caret_rotate');
-  }
-
-  /**
-   * Приватный метод экземпляра класса DropDown
-   * @protected
-   * @description Метод реализовывающий выбор элементов в разных режимах. Обычный/Мультиселект/Мультиселект + Мультиселект Таг.
-   * @method #addOptionsBehaviour
-   */
-  #addOptionsBehaviour() {
-    const {
-      multiselect,
-      placeholder,
-      selected,
-      multiselectTag,
-      searchMode,
-      closeOnSelect,
-      darkTheme,
-    } = this.#options;
-
-    const options = this.#element.querySelectorAll('.list__item');
-    const select = this.#element.querySelector('.selected');
-    const nativeOption = this.#element.querySelectorAll('.nativeSelect__nativeOption');
-
-    const ulMultipul = document.createElement('ul');
-
-    if (multiselect && multiselect == true) {
-      ulMultipul.classList.add('multiselect-tag');
-      select.classList.add('overflow-hidden');
-    }
-
-    if (searchMode && searchMode === true) {
-      this.#searchMode(this.random);
-    }
-
-    options.forEach((option, index) => {
-      option.addEventListener('click', (event) => {
-        const dataSelectText = {
-          placeholder,
-          selected,
-          selectedItems: this.#selectedItems,
-          indexes: this.#indexes,
-          darkTheme,
-          multiselectTag,
-        };
-
-        const item = this.#items[index];
-
-        if (closeOnSelect == false || (multiselect && multiselect == true)) {
-          event.stopPropagation();
-          event.preventDefault();
-        }
-
-        const checkIndex = this.#indexes.indexOf(index);
-
-        if (multiselect && multiselect == true) {
-          option.classList.toggle('active');
-          const checkBox = option.querySelector('input[type="checkbox"]');
-
-          if (checkBox) {
-            if (!(event.target instanceof HTMLInputElement)) {
-              checkBox.checked = !checkBox.checked;
-            }
-
-            if (checkIndex === -1) {
-              nativeOptionMultiple(nativeOption, item.title, true);
-              this.#indexes.push(index);
-              select.innerText = '';
-
-              if (multiselectTag && multiselectTag == true) {
-                this.#selectedItems.push(item);
-                select.appendChild(ulMultipul);
-
-                const data = {
-                  option: this.#options,
-                  element: this.#element,
-                  indexes: this.#indexes,
-                  selectedItems: this.#selectedItems,
-                };
-
-                ulMultipul.appendChild(createBreadcrumb(data, item.title, index, item.id));
-              } else {
-                this.#selectedItems.push(item.title);
-                select.innerText = this.#selectedItems;
-              }
-            } else {
-              if (multiselectTag && multiselectTag == true) {
-                const tagItem = document.getElementById(`tag-${index}-${item.id}`);
-                ulMultipul.removeChild(tagItem);
-              }
-
-              this.#indexes.splice(checkIndex, 1);
-              this.#selectedItems.splice(checkIndex, 1);
-              nativeOptionMultiple(nativeOption, item.title, false);
-            }
-
-            if (!this.#selectedItems.length) {
-              getSelectText(dataSelectText, select);
-            } else {
-              if (multiselectTag && multiselectTag == true) {
-                select.appendChild(ulMultipul);
-              } else {
-                select.innerText = this.#selectedItems;
-              }
-            }
-          }
-        } else {
-          select.innerText = item.title;
-          this.#selectedItems = item;
-
-          nativeOptionOrdinary(nativeOption, item.title);
-
-          options.forEach((option) => {
-            option.classList.remove('active');
-          });
-          option.classList.add('active');
-        }
-
-        clearSelect(select, this.#element, dataSelectText);
-      });
-    });
-  }
-
-  /**
-   * Метод который реализует поиск элементов в селекте
-   * @protected
-   * @param {string} random уникальное значение для input элемента.
-   * @method #searchMode
-   */
-  #searchMode(random) {
-    const { language } = this.#options;
-
-    const input = this.#element.querySelector(`#searchSelect-${random}`);
-    const searchSelect = this.#element.querySelectorAll('.list__item');
-    const result = document.createElement('p');
-
-    let textNode = '';
-    if (language && language === 'ru') {
-      textNode = document.createTextNode(`${ru.textInListSearch}`);
-    } else {
-      textNode = document.createTextNode(`${en.textInListSearch}`);
-    }
-
-    result.appendChild(textNode);
-    result.classList.add('displayHide');
-    result.classList.add('noRezult');
-    input.parentElement.appendChild(result);
-
-    input.addEventListener('click', (e) => {
-      e.stopPropagation();
-    });
-
-    input.oninput = function () {
-      let valueSearch = this.value.trim().toLowerCase();
-      let anyMatch = false;
-
-      if (valueSearch != '') {
-        searchSelect.forEach((elem) => {
-          let isMatching = new RegExp(valueSearch, 'gi').test(elem.textContent);
-          anyMatch = anyMatch || isMatching;
-
-          if (elem.textContent.toLowerCase().search(valueSearch) == -1) {
-            elem.classList.add('displayHide');
-          } else {
-            elem.classList.remove('displayHide');
-          }
-        });
-
-        result.classList.toggle('displayHide', anyMatch);
-      } else {
-        searchSelect.forEach((elem) => {
-          elem.classList.remove('displayHide');
-          result.classList.add('displayHide');
-        });
-      }
-    };
-  }
-
-  /**
-   * Приватный метод экземпляра класса DropDown
-   * @protected
-   * @description Открывает и закрывает список по переданному эвенту
-   * @method #initEvent
-   */
-  #initEvent() {
-    const { event } = this.#options;
-    if (!event) {
-      return;
-    }
-
-    if (event) {
-      if (event === 'mouseenter') {
-        this.#element.addEventListener(event, () => {
-          this.#open();
-        });
-        this.#element.addEventListener('mouseleave', () => {
-          this.#close();
-        });
-      }
-    }
-  }
-
-  /**
-   * Приватный метод экземпляра класса DropDown
-   * @protected
-   * @description Закрывает список по клику вне элемента
-   * @method #closeSelectClick
-   */
-  #closeSelectClick() {
-    const dropdown = document.querySelector(`${this.#options.selector}`);
-
-    document.addEventListener('click', (e) => {
-      const withinBoundaries = e.composedPath().includes(dropdown);
-      if (!withinBoundaries) {
-        if (this.btn) {
-          return;
-        } else {
-          this.#close();
-        }
-      }
-    });
-  }
-
-  /**
-   * Приватный метод экземпляра класса DropDown
-   * @protected
-   * @param {boolean} nativeSelectMode параметр отвечающий за добавления нативного селекта.
-   * @description Изменяет отображение селекта на мобильных устройствах
-   * @method #selectMode
-   */
-  #selectMode(nativeSelectMode) {
-    let win = window.outerWidth;
-
-    if (nativeSelectMode === true) {
-      const select = this.#element.querySelector('.cg-select');
-      const list = this.#element.querySelector('.list');
-      const nativeSelect = this.#element.querySelector('.nativeSelect');
-
-      if (win < 576) {
-        select.classList.add('displayHide');
-        list.classList.add('displayHide');
-        nativeSelect.classList.add('nativeSelectActive');
-      } else if (win > 576) {
-        select.classList.remove('displayHide');
-        list.classList.remove('displayHide');
-        nativeSelect.classList.remove('nativeSelectActive');
-        nativeSelect.classList.add('displayHide');
-      }
-    } else {
-      return;
-    }
-  }
-
-  /**
-   * Приватный метод экземпляра класса DropDown
-   * @protected
-   * @param {boolean} listDisplayMode параметр отвечающий за отображение выбора в виде модального окна.
-   * @description Изменяет отображение листа с выбором в виде модального окна.
-   * @method #displayMode
-   */
-  #displayMode(listDisplayMode) {
-    if (listDisplayMode === true) {
-      const modal = document.createElement('div');
-      const body = document.querySelector('body');
-      const list = this.#list;
-
-      modal.appendChild(list);
-      this.#element.appendChild(modal);
-
-      this.#element.addEventListener('click', () => {
-        modal.classList.toggle('modal');
-        list.classList.toggle('listModal');
-        body.classList.toggle('overflowHide');
-      });
-    } else {
-      return;
-    }
-  }
-}
-
diff --git a/src/cg-selectTS.ts b/src/cg-select.ts
similarity index 99%
rename from src/cg-selectTS.ts
rename to src/cg-select.ts
index cf965e7..ae78cc7 100644
--- a/src/cg-selectTS.ts
+++ b/src/cg-select.ts
@@ -3,7 +3,7 @@ import {
   createInputSearch,
   createNativeSelect,
   createNativeSelectOption,
-} from './components/create-element/create-elementTs';
+} from './components/create-element/create-element';
 import { ICreateBreadCrumb } from './components/create-element/create-element.interface';
 
 import {
@@ -15,12 +15,12 @@ import {
   getSelectText,
   nativeOptionMultiple,
   nativeOptionOrdinary,
-} from './components/utils/utilsTs';
+} from './components/utils/utils';
 import { IDataItem, ISelectedItems } from './components/utils/urils.interface';
 
 import { ICgSelect, IStyle } from './interfaces/cg-select.interface';
 import { IItems } from './interfaces/items.interface';
-import { ru, en } from './language/languageTS';
+import { ru, en } from './language/language';
 import { ILanguage } from './interfaces/language.interface';
 
 import './main.scss';
@@ -235,7 +235,15 @@ export class CGSelect implements ICgSelect {
       return;
     }
 
-    createSelected;
+    if (this.lable) {
+      const lableItem = document.createElement('h1');
+      const textLable = document.createTextNode(this.lable);
+
+      lableItem.appendChild(textLable);
+      lableItem.classList.add('label');
+
+      this.element!.insertAdjacentElement('beforebegin', lableItem);
+    }
 
     items.forEach((dataItem: any, index: number) => {
       let itemInputs: IDataItem = {
@@ -454,16 +462,6 @@ export class CGSelect implements ICgSelect {
       createSelected(this.element!, select, this.styles);
     }
 
-    if (this.lable) {
-      const lableItem = document.createElement('h1');
-      const textLable = document.createTextNode(this.lable);
-
-      lableItem.appendChild(textLable);
-      lableItem.classList.add('label');
-
-      this.element!.insertAdjacentElement('beforebegin', lableItem);
-    }
-
     if (this.styles) {
       customStyles(this.element!, this.styles);
     }
diff --git a/src/components/create-element.js b/src/components/create-element.js
deleted file mode 100644
index bf9b5d7..0000000
--- a/src/components/create-element.js
+++ /dev/null
@@ -1,121 +0,0 @@
-import { customStylesFormat, nativeOptionMultiple } from './utils';
-/**
- * @module createBreadcrumb
- */
-
-/**
- * Метод который создает и отвечает за поведение chips
- * @param {object} data объект в котором содержатся настройки и элементы селекта
- * @param {string} title имя выбранного элемента для отрисовки chips
- * @param {number} index индекс выбранного элемента для отрисовки chips
- * @param {string} id уникальное id выбранного элемента
- * @returns {HTMLElement} возвращает сформированный HTMLElement chips item
- */
-export function createBreadcrumb(data, title, index, id) {
-  const { element, option, indexes, selectedItems } = data;
-  const { placeholder, styles } = option;
-
-  const selected = element.querySelector('.selected');
-  const nativeOption = element.querySelectorAll('.nativeSelect__nativeOption');
-
-  const liChip = document.createElement('li');
-  const textNode = document.createTextNode(title);
-  const svgIcon = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
-  const path1 = document.createElementNS('http://www.w3.org/2000/svg', 'path');
-  const path2 = document.createElementNS('http://www.w3.org/2000/svg', 'path');
-
-  svgIcon.setAttribute('viewBox', '0 0 10 10');
-  path1.setAttribute('d', 'M3,7 L7,3');
-  path2.setAttribute('d', 'M3,3 L7,7');
-  liChip.setAttribute('id', `tag-${index}-${id}`);
-
-  svgIcon.classList.add('svg-icon');
-
-  svgIcon.appendChild(path1);
-  svgIcon.appendChild(path2);
-  liChip.appendChild(textNode);
-  liChip.appendChild(svgIcon);
-
-  if (styles) {
-    const { chips } = styles;
-    customStylesFormat(chips, liChip);
-  }
-
-  svgIcon.addEventListener('click', (event) => {
-    event.preventDefault();
-    event.stopPropagation();
-    nativeOptionMultiple(nativeOption, title, false);
-
-    const deleteIcon = indexes.indexOf(index);
-    let checkBox = '';
-
-    indexes.splice(deleteIcon, 1);
-    selectedItems.splice(deleteIcon, 1);
-
-    if (id) {
-      checkBox = document.getElementById(`chbox-${id}`);
-    } else {
-      checkBox = document.getElementById(`chbox-${index}`);
-    }
-
-    checkBox.checked = false;
-    checkBox.parentElement.classList.remove('active');
-
-    if (!selectedItems.length) {
-      selected.innerText = placeholder;
-    }
-
-    liChip.parentElement.removeChild(liChip);
-  });
-
-  return liChip;
-}
-
-/**
- * Метод который создает нативный селект
- * @returns {HTMLSelectElement} Возвращает созданный нативный селект
- */
-export function createNativeSelect() {
-  const nativeSelect = document.createElement('select');
-
-  nativeSelect.setAttribute('name', 'dataSelect');
-  nativeSelect.classList.add('nativeSelect');
-  return nativeSelect;
-}
-
-/**
- * Метод который создает Options для нативного селекта
- * @returns {HTMLOptionElement} Возвращает созданные Options нативного селекта
- */
-export function createNativeSelectOption() {
-  const nativeOption = document.createElement('option');
-
-  nativeOption.classList.add('nativeSelect__nativeOption');
-  return nativeOption;
-}
-
-/**
- * Метод который создает поиск элементов в селекте
- * @param {string} random уникальное значение для input элемента.
- * @param {string} lenguage текст на определенном языке переданный из файла language.js
- * @returns {HTMLInputElement} Возвращает сформированный input елемент.
- */
-export function createInputSearch(random, lenguage) {
-  const inputSearch = document.createElement('input');
-
-  inputSearch.type = 'text';
-  inputSearch.classList.add('inputSearch');
-  inputSearch.setAttribute('id', `searchSelect-${random}`);
-
-  if (lenguage) {
-    inputSearch.setAttribute('placeholder', `${lenguage}`);
-  } else {
-    inputSearch.setAttribute('placeholder', 'Search...');
-  }
-
-  inputSearch.addEventListener('click', (e) => {
-    e.preventDefault();
-  });
-
-  return inputSearch;
-}
diff --git a/src/components/create-element/create-elementTs.ts b/src/components/create-element/create-element.ts
similarity index 99%
rename from src/components/create-element/create-elementTs.ts
rename to src/components/create-element/create-element.ts
index 6564e76..62c021d 100644
--- a/src/components/create-element/create-elementTs.ts
+++ b/src/components/create-element/create-element.ts
@@ -1,4 +1,4 @@
-import { customStylesFormat, nativeOptionMultiple } from '../utils/utilsTs';
+import { customStylesFormat, nativeOptionMultiple } from '../utils/utils';
 import { ICreateBreadCrumb } from './create-element.interface';
 
 /**
diff --git a/src/components/utils.js b/src/components/utils.js
deleted file mode 100644
index 9e3c371..0000000
--- a/src/components/utils.js
+++ /dev/null
@@ -1,227 +0,0 @@
-/**
- * Utils module
- * @module Utils
- */
-
-/**
- * Создание кнопки выбора элементов
- * @param {HTMLElement} element созданный экземпляр класса DropDown
- * @param {string} content placeholer передаваемый из настроек селекта
- * @param {object} styles не обязательный параметр. Объект в котором находяться настройки кастомизации частей селекта
- */
-export function createSelected(element, content, styles) {
-  if (content) {
-    element.innerHTML = `
-      
-

${content}

-
-
- `; - } - - if (styles) { - customStyles(element, styles); - - element.innerHTML = ` -
-

${content}

-
-
- `; - } -} - -/** - * Поиск и стилизация елементов полученных из styles экземпляра DropDown - * @param {HTMLElement} element созданный экземпляр класса DropDown - * @param {object} styles объект в котором находяться настройки кастомизации частей селекта - */ -export function customStyles(element, styles) { - if (!styles) { - return; - } - - const { head, caret, placeholder, lable } = styles; - - const cgSelect = element.querySelector('.cg-select'); - const caretSelect = element.querySelector('.caret'); - const placeholderSelect = element.querySelector('.selected'); - const lableItem = element.parentElement.querySelector('h1.label'); - - customStylesFormat(head, cgSelect); - customStylesFormat(caret, caretSelect); - customStylesFormat(lable, lableItem); - - if (placeholderSelect) { - customStylesFormat(placeholder, placeholderSelect); - } -} - -/** - * Универсальный метод для стилизации селекта - * @param {object} elemOption объект полученное из объекта styles у которого мы получаем ключ-значение стилей - * @param {HTMLElement} selector HTMLElement подвергающиеся кастомизации - */ -export function customStylesFormat(elemOption, selector) { - if (elemOption) { - Object.entries(elemOption).forEach(([key, value]) => { - selector.style[key] = value; - }); - } -} - -/** - * Проверка содержит ли item указанные свойства, - * @param {object} item проверяемый на определенную структуру элемент - * @returns {boolean} возвращает true/false если item содержит указанные свойства - */ -export function checkItemStruct(item) { - if (item && typeof item !== 'object') { - return false; - } - - return item.hasOwnProperty('id') && item.hasOwnProperty('title') && item.hasOwnProperty('value'); -} - -/** - * Вставка изначального текста селекта(до выбора) - * @param {object} data объект в котором находяться title селекта - * @param {HTMLElement} select елемент селекта, куда будет вставляться title - * @returns {HTMLElement} возвращает сформированный елемент селекта - */ -export function getSelectText(data, select) { - const { placeholder, selected } = data; - - if (placeholder) { - select.innerText = placeholder; - } else if (selected) { - select.innerText = selected; - } else { - select.innerText = 'Select...'; - } - return select; -} - -/** - * Преобразование каждого елемента полученного из поля Items; - * @param {object | string} dataItem полученный елемент переданный при создании селекта может быть как object/string - * @param {number} index индекс этого элемента - * @returns {object} возвращает сформированный объект - */ -export function getFormatItem(dataItem, index) { - const random = Math.random().toString(36).substring(2, 10); - let item = {}; - - if (checkItemStruct(dataItem)) { - item = { - id: dataItem.id, - title: dataItem.title, - value: index, - }; - } else { - item = { - id: random, - title: dataItem, - value: index, - }; - } - - return item; -} - -/** - * Поведение нативного(одинарного) селекта при выборе кастомного - * @param {NodeList} element NodeList нативного селекта - * @param {object} item выбранный элемент в кастомном селекте - */ -export function nativeOptionOrdinary(element, item) { - element.forEach((option) => { - option.removeAttribute('selected'); - if (option.textContent === item) { - option.setAttribute('selected', 'selected'); - } - }); -} - -/** - * Поведение нативного(Multiple) селекта при выборе в кастомном - * @param {NodeList} element NodeList нативного селекта - * @param {object} item выбранный элемент в кастомном селекте - * @param {boolean} condition специальный флаг при котором добавляются/убераются атрибуты у нативного селекта - */ -export function nativeOptionMultiple(element, item, condition) { - 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; - } - }); -} - -/** - * Создание кнопки отчиски селекта, при единичном выборе. - * @param {HTMLElement} select место в селекте которое будет переназначено на ''. - * @param {HTMLElement} element экземпляр класса DropDown. - * @param {object} dataSelectText текст который отрисовывается в селекте. - */ -export function clearSelect(select, element, dataSelectText) { - const { selectedItems, indexes, darkTheme, multiselectTag } = dataSelectText; - - const options = element.querySelectorAll('.list__item'); - const ulMultiSelect = element.querySelector('.multiselect-tag'); - const svgIcon = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); - const path1 = document.createElementNS('http://www.w3.org/2000/svg', 'path'); - const path2 = document.createElementNS('http://www.w3.org/2000/svg', 'path'); - const checkBox = element.querySelectorAll('li input'); - - svgIcon.setAttribute('viewBox', '0 0 10 10'); - path1.setAttribute('d', 'M2,8 L8,2'); - path2.setAttribute('d', 'M2,2 L8,8'); - svgIcon.appendChild(path1); - svgIcon.appendChild(path2); - - if (multiselectTag && multiselectTag == true) { - return; - } - - if (darkTheme === true || !darkTheme) { - path1.classList.add('pathWhite'); - path2.classList.add('pathWhite'); - } - - if (darkTheme === false) { - path1.classList.add('pathBlack'); - path2.classList.add('pathBlack'); - } - - svgIcon.classList.add('svg-icon'); - svgIcon.classList.add('svg-clear'); - - select.appendChild(svgIcon); - - svgIcon.addEventListener('click', () => { - select.innerText = ''; - - if (Array.isArray(selectedItems)) { - selectedItems.splice(0); - indexes.splice(0); - } - - checkBox.forEach((item) => { - item.checked = false; - }); - - getSelectText(dataSelectText, select); - - options.forEach((option) => { - option.classList.remove('active'); - }); - }); -} diff --git a/src/components/utils/utilsTs.ts b/src/components/utils/utils.ts similarity index 97% rename from src/components/utils/utilsTs.ts rename to src/components/utils/utils.ts index b4d0773..c424ea4 100644 --- a/src/components/utils/utilsTs.ts +++ b/src/components/utils/utils.ts @@ -86,7 +86,8 @@ export function createSelected(element: Element, content?: string, styles?: ISty if (content) { const text = document.createTextNode(content); selected.appendChild(text); - element?.appendChild(select); + element.innerHTML = ''; + element?.insertAdjacentElement('afterbegin', select); } else if (styles) { customStyles(element!, styles); select.setAttribute('style', `${styles}`); @@ -105,7 +106,7 @@ export function clearSelect(select: HTMLElement, element: Element, dataSelectTex const { selectedItems, indexes, darkTheme, multiselectTag } = dataSelectText; const options = element.querySelectorAll('.list__item'); - const ulMultiSelect = element.querySelector('.multiselect-tag'); + const nativeOption = element!.querySelectorAll('.nativeSelect__nativeOption'); const svgIcon = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); const path1 = document.createElementNS('http://www.w3.org/2000/svg', 'path'); const path2 = document.createElementNS('http://www.w3.org/2000/svg', 'path'); @@ -139,6 +140,10 @@ export function clearSelect(select: HTMLElement, element: Element, dataSelectTex svgIcon.addEventListener('click', () => { select!.innerText = ''; + nativeOption.forEach((option) => { + option.removeAttribute('selected'); + }); + if (Array.isArray(selectedItems)) { selectedItems!.splice(0); indexes!.splice(0); diff --git a/src/language/language.js b/src/language/language.js deleted file mode 100644 index 3b6ecb0..0000000 --- a/src/language/language.js +++ /dev/null @@ -1,11 +0,0 @@ -export const ru = { - selectPlaceholder: 'Выберите элемент...', - placeholder: 'Поиск...', - textInListSearch: 'Совпадений нет...', -}; - -export const en = { - selectPlaceholder: 'Select element...', - placeholder: 'Search...', - textInListSearch: 'No matches...', -}; diff --git a/src/language/languageTS.ts b/src/language/language.ts similarity index 100% rename from src/language/languageTS.ts rename to src/language/language.ts