@abydahana/iconpicker 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +303 -0
- package/dist/core/font-loader.d.ts +2 -0
- package/dist/core/font-loader.d.ts.map +1 -0
- package/dist/core/font-loader.js +35 -0
- package/dist/core/font-loader.js.map +1 -0
- package/dist/core/grid.d.ts +26 -0
- package/dist/core/grid.d.ts.map +1 -0
- package/dist/core/grid.js +101 -0
- package/dist/core/grid.js.map +1 -0
- package/dist/core/icon-picker.d.ts +29 -0
- package/dist/core/icon-picker.d.ts.map +1 -0
- package/dist/core/icon-picker.js +314 -0
- package/dist/core/icon-picker.js.map +1 -0
- package/dist/core/popover.d.ts +17 -0
- package/dist/core/popover.d.ts.map +1 -0
- package/dist/core/popover.js +96 -0
- package/dist/core/popover.js.map +1 -0
- package/dist/dom/template.d.ts +18 -0
- package/dist/dom/template.d.ts.map +1 -0
- package/dist/dom/template.js +121 -0
- package/dist/dom/template.js.map +1 -0
- package/dist/iconpicker.css +547 -0
- package/dist/iconsets/bootstrap.d.ts +3 -0
- package/dist/iconsets/bootstrap.d.ts.map +1 -0
- package/dist/iconsets/bootstrap.js +2059 -0
- package/dist/iconsets/bootstrap.js.map +1 -0
- package/dist/iconsets/boxicons.d.ts +3 -0
- package/dist/iconsets/boxicons.d.ts.map +1 -0
- package/dist/iconsets/boxicons.js +823 -0
- package/dist/iconsets/boxicons.js.map +1 -0
- package/dist/iconsets/fontawesome.d.ts +3 -0
- package/dist/iconsets/fontawesome.d.ts.map +1 -0
- package/dist/iconsets/fontawesome.js +1904 -0
- package/dist/iconsets/fontawesome.js.map +1 -0
- package/dist/iconsets/index.d.ts +10 -0
- package/dist/iconsets/index.d.ts.map +1 -0
- package/dist/iconsets/index.js +29 -0
- package/dist/iconsets/index.js.map +1 -0
- package/dist/iconsets/lucide.d.ts +3 -0
- package/dist/iconsets/lucide.d.ts.map +1 -0
- package/dist/iconsets/lucide.js +1816 -0
- package/dist/iconsets/lucide.js.map +1 -0
- package/dist/iconsets/mdi.d.ts +3 -0
- package/dist/iconsets/mdi.d.ts.map +1 -0
- package/dist/iconsets/mdi.js +7457 -0
- package/dist/iconsets/mdi.js.map +1 -0
- package/dist/iconsets/remix.d.ts +3 -0
- package/dist/iconsets/remix.d.ts.map +1 -0
- package/dist/iconsets/remix.js +2901 -0
- package/dist/iconsets/remix.js.map +1 -0
- package/dist/iconsets/tabler.d.ts +3 -0
- package/dist/iconsets/tabler.d.ts.map +1 -0
- package/dist/iconsets/tabler.js +4888 -0
- package/dist/iconsets/tabler.js.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -0
- package/dist/themes/aksara.css +72 -0
- package/dist/themes/base.css +211 -0
- package/dist/themes/bootstrap.css +70 -0
- package/dist/themes/default.css +72 -0
- package/dist/themes/tailwind.css +112 -0
- package/dist/types.d.ts +35 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +69 -0
- package/src/core/font-loader.ts +38 -0
- package/src/core/grid.ts +129 -0
- package/src/core/icon-picker.ts +353 -0
- package/src/core/popover.ts +113 -0
- package/src/dom/template.ts +173 -0
- package/src/iconsets/bootstrap.ts +2060 -0
- package/src/iconsets/boxicons.ts +824 -0
- package/src/iconsets/fontawesome.ts +1905 -0
- package/src/iconsets/index.ts +31 -0
- package/src/iconsets/lucide.ts +1817 -0
- package/src/iconsets/mdi.ts +7458 -0
- package/src/iconsets/remix.ts +2902 -0
- package/src/iconsets/tabler.ts +4889 -0
- package/src/index.ts +18 -0
- package/src/themes/aksara.css +72 -0
- package/src/themes/base.css +211 -0
- package/src/themes/bootstrap.css +70 -0
- package/src/themes/default.css +72 -0
- package/src/themes/index.css +5 -0
- package/src/themes/tailwind.css +112 -0
- package/src/types.ts +37 -0
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @abydahana/iconpicker Tailwind UI Theme
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
.iconpicker-theme-tailwind {
|
|
6
|
+
background-color: #ffffff;
|
|
7
|
+
color: #0f172a;
|
|
8
|
+
border: 1px solid #e2e8f0;
|
|
9
|
+
border-radius: 0.75rem;
|
|
10
|
+
box-shadow:
|
|
11
|
+
0 10px 25px -5px rgba(0, 0, 0, 0.1),
|
|
12
|
+
0 8px 10px -6px rgba(0, 0, 0, 0.1);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.iconpicker-theme-tailwind .iconpicker-search-input {
|
|
16
|
+
background-color: #f8fafc;
|
|
17
|
+
color: #0f172a;
|
|
18
|
+
border: 1px solid #e2e8f0;
|
|
19
|
+
border-radius: 0.5rem;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.iconpicker-theme-tailwind .iconpicker-search-input:focus {
|
|
23
|
+
background-color: #ffffff;
|
|
24
|
+
border-color: #6366f1;
|
|
25
|
+
box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.2);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.iconpicker-theme-tailwind .iconpicker-tab {
|
|
29
|
+
color: #64748b;
|
|
30
|
+
border-radius: 0.375rem;
|
|
31
|
+
font-weight: 500;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.iconpicker-theme-tailwind .iconpicker-tab:hover {
|
|
35
|
+
background-color: #f1f5f9;
|
|
36
|
+
color: #0f172a;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.iconpicker-theme-tailwind .iconpicker-tab.is-active {
|
|
40
|
+
background-color: #6366f1;
|
|
41
|
+
color: #ffffff;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.iconpicker-theme-tailwind .iconpicker-item {
|
|
45
|
+
color: #334155;
|
|
46
|
+
border-radius: 0.5rem;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.iconpicker-theme-tailwind .iconpicker-item:hover {
|
|
50
|
+
background-color: #f1f5f9;
|
|
51
|
+
border-color: #cbd5e1;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.iconpicker-theme-tailwind .iconpicker-item.is-selected {
|
|
55
|
+
background-color: #6366f1;
|
|
56
|
+
color: #ffffff;
|
|
57
|
+
border-color: #6366f1;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.iconpicker-theme-tailwind .iconpicker-footer {
|
|
61
|
+
border-top-color: #f1f5f9;
|
|
62
|
+
background-color: #f8fafc;
|
|
63
|
+
border-bottom-left-radius: 0.75rem;
|
|
64
|
+
border-bottom-right-radius: 0.75rem;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.iconpicker-theme-tailwind .iconpicker-btn-clear {
|
|
68
|
+
color: #ef4444;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.iconpicker-theme-tailwind .iconpicker-btn-clear:hover {
|
|
72
|
+
background-color: #fee2e2;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/* Dark mode auto support for Tailwind theme */
|
|
76
|
+
@media (prefers-color-scheme: dark) {
|
|
77
|
+
.iconpicker-theme-tailwind {
|
|
78
|
+
background-color: #0f172a;
|
|
79
|
+
color: #f8fafc;
|
|
80
|
+
border-color: #1e293b;
|
|
81
|
+
box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.5);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.iconpicker-theme-tailwind .iconpicker-search-input {
|
|
85
|
+
background-color: #1e293b;
|
|
86
|
+
color: #f8fafc;
|
|
87
|
+
border-color: #334155;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.iconpicker-theme-tailwind .iconpicker-tab {
|
|
91
|
+
color: #94a3b8;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.iconpicker-theme-tailwind .iconpicker-tab:hover {
|
|
95
|
+
background-color: #1e293b;
|
|
96
|
+
color: #f8fafc;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.iconpicker-theme-tailwind .iconpicker-item {
|
|
100
|
+
color: #cbd5e1;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
.iconpicker-theme-tailwind .iconpicker-item:hover {
|
|
104
|
+
background-color: #1e293b;
|
|
105
|
+
border-color: #334155;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.iconpicker-theme-tailwind .iconpicker-footer {
|
|
109
|
+
border-top-color: #1e293b;
|
|
110
|
+
background-color: #0b1120;
|
|
111
|
+
}
|
|
112
|
+
}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export interface IconItem {
|
|
2
|
+
name: string;
|
|
3
|
+
className: string;
|
|
4
|
+
set: string;
|
|
5
|
+
keywords?: string[];
|
|
6
|
+
}
|
|
7
|
+
export interface IconSetDefinition {
|
|
8
|
+
id: string;
|
|
9
|
+
title: string;
|
|
10
|
+
prefix: string;
|
|
11
|
+
formatter?: (name: string) => string;
|
|
12
|
+
icons: string[];
|
|
13
|
+
}
|
|
14
|
+
export type IconPickerTheme = "aksara" | "bootstrap" | "tailwind" | "default";
|
|
15
|
+
export type IconPickerPlacement = "bottom-start" | "bottom-end" | "bottom" | "top-start" | "top-end" | "top" | "auto";
|
|
16
|
+
export interface IconPickerOptions {
|
|
17
|
+
theme?: IconPickerTheme;
|
|
18
|
+
placement?: IconPickerPlacement;
|
|
19
|
+
iconSets?: (string | IconSetDefinition)[];
|
|
20
|
+
defaultSet?: string;
|
|
21
|
+
searchPlaceholder?: string;
|
|
22
|
+
value?: string;
|
|
23
|
+
container?: HTMLElement | string;
|
|
24
|
+
showTabs?: boolean;
|
|
25
|
+
showFooter?: boolean;
|
|
26
|
+
closeOnSelect?: boolean;
|
|
27
|
+
emptyText?: string;
|
|
28
|
+
itemsPerPage?: number;
|
|
29
|
+
loadFonts?: boolean;
|
|
30
|
+
fontUrls?: Record<string, string>;
|
|
31
|
+
onSelect?: (icon: IconItem) => void;
|
|
32
|
+
onOpen?: () => void;
|
|
33
|
+
onClose?: () => void;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IACrC,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,MAAM,eAAe,GAAG,QAAQ,GAAG,WAAW,GAAG,UAAU,GAAG,SAAS,CAAC;AAC9E,MAAM,MAAM,mBAAmB,GAAG,cAAc,GAAG,YAAY,GAAG,QAAQ,GAAG,WAAW,GAAG,SAAS,GAAG,KAAK,GAAG,MAAM,CAAC;AAEtH,MAAM,WAAW,iBAAiB;IAChC,KAAK,CAAC,EAAE,eAAe,CAAC;IACxB,SAAS,CAAC,EAAE,mBAAmB,CAAC;IAChC,QAAQ,CAAC,EAAE,CAAC,MAAM,GAAG,iBAAiB,CAAC,EAAE,CAAC;IAC1C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,WAAW,GAAG,MAAM,CAAC;IACjC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,QAAQ,KAAK,IAAI,CAAC;IACpC,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@abydahana/iconpicker",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Universal, framework-agnostic floating popover icon picker with multi-pack support",
|
|
5
|
+
"author": "Aby Dahana",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"main": "dist/index.js",
|
|
9
|
+
"module": "dist/index.js",
|
|
10
|
+
"types": "dist/index.d.ts",
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"import": "./dist/index.js",
|
|
15
|
+
"default": "./dist/index.js"
|
|
16
|
+
},
|
|
17
|
+
"./src": {
|
|
18
|
+
"types": "./src/index.ts",
|
|
19
|
+
"import": "./src/index.ts",
|
|
20
|
+
"default": "./src/index.ts"
|
|
21
|
+
},
|
|
22
|
+
"./css": "./dist/iconpicker.css",
|
|
23
|
+
"./themes/*": "./dist/themes/*"
|
|
24
|
+
},
|
|
25
|
+
"files": [
|
|
26
|
+
"dist",
|
|
27
|
+
"src",
|
|
28
|
+
"README.md",
|
|
29
|
+
"LICENSE"
|
|
30
|
+
],
|
|
31
|
+
"publishConfig": {
|
|
32
|
+
"access": "public"
|
|
33
|
+
},
|
|
34
|
+
"scripts": {
|
|
35
|
+
"build": "node --import tsx build.ts",
|
|
36
|
+
"check": "tsc --noEmit",
|
|
37
|
+
"lint": "eslint src build.ts scripts eslint.config.js",
|
|
38
|
+
"lint:fix": "eslint src build.ts scripts eslint.config.js --fix",
|
|
39
|
+
"format": "prettier --write . && eslint src build.ts scripts eslint.config.js --fix",
|
|
40
|
+
"format:check": "prettier --check . && eslint src build.ts scripts eslint.config.js",
|
|
41
|
+
"all": "npm run format && npm run lint && npm run build",
|
|
42
|
+
"prepublishOnly": "npm run all"
|
|
43
|
+
},
|
|
44
|
+
"keywords": [
|
|
45
|
+
"iconpicker",
|
|
46
|
+
"icon-picker",
|
|
47
|
+
"icons",
|
|
48
|
+
"popover",
|
|
49
|
+
"mdi",
|
|
50
|
+
"fontawesome",
|
|
51
|
+
"bootstrap-icons",
|
|
52
|
+
"tabler-icons",
|
|
53
|
+
"remixicon",
|
|
54
|
+
"boxicons",
|
|
55
|
+
"lucide",
|
|
56
|
+
"aksara-ui",
|
|
57
|
+
"tailwind"
|
|
58
|
+
],
|
|
59
|
+
"devDependencies": {
|
|
60
|
+
"@eslint/js": "^10.0.1",
|
|
61
|
+
"@types/node": "^26.4.1",
|
|
62
|
+
"eslint": "^10.10.0",
|
|
63
|
+
"eslint-config-prettier": "^10.1.8",
|
|
64
|
+
"prettier": "^3.9.6",
|
|
65
|
+
"tsx": "^4.19.3",
|
|
66
|
+
"typescript": "^5.8.2",
|
|
67
|
+
"typescript-eslint": "^8.69.0"
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
const DEFAULT_FONT_URLS: Record<string, string> = {
|
|
2
|
+
mdi: "https://cdn.jsdelivr.net/npm/@mdi/font@7.4.47/css/materialdesignicons.min.css",
|
|
3
|
+
fa: "https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/all.min.css",
|
|
4
|
+
fontawesome: "https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/all.min.css",
|
|
5
|
+
bi: "https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css",
|
|
6
|
+
bootstrap: "https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css",
|
|
7
|
+
tabler: "https://cdn.jsdelivr.net/npm/@tabler/icons-webfont@3.19.0/dist/tabler-icons.min.css",
|
|
8
|
+
ti: "https://cdn.jsdelivr.net/npm/@tabler/icons-webfont@3.19.0/dist/tabler-icons.min.css",
|
|
9
|
+
remix: "https://cdn.jsdelivr.net/npm/remixicon@4.3.0/fonts/remixicon.css",
|
|
10
|
+
ri: "https://cdn.jsdelivr.net/npm/remixicon@4.3.0/fonts/remixicon.css",
|
|
11
|
+
boxicons: "https://unpkg.com/boxicons@2.1.4/css/boxicons.min.css",
|
|
12
|
+
bx: "https://unpkg.com/boxicons@2.1.4/css/boxicons.min.css"
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const loadedFonts = new Set<string>();
|
|
16
|
+
|
|
17
|
+
export function loadIconFont(setId: string, customUrls?: Record<string, string>): void {
|
|
18
|
+
if (typeof document === "undefined") return;
|
|
19
|
+
|
|
20
|
+
const normalized = setId.toLowerCase();
|
|
21
|
+
const url = customUrls?.[normalized] || DEFAULT_FONT_URLS[normalized];
|
|
22
|
+
if (!url || loadedFonts.has(normalized)) return;
|
|
23
|
+
|
|
24
|
+
// Check if link already exists in head
|
|
25
|
+
const selector = `link[data-iconpicker-font="${normalized}"]`;
|
|
26
|
+
if (document.querySelector(selector)) {
|
|
27
|
+
loadedFonts.add(normalized);
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const link = document.createElement("link");
|
|
32
|
+
link.rel = "stylesheet";
|
|
33
|
+
link.href = url;
|
|
34
|
+
link.setAttribute("data-iconpicker-font", normalized);
|
|
35
|
+
|
|
36
|
+
document.head.appendChild(link);
|
|
37
|
+
loadedFonts.add(normalized);
|
|
38
|
+
}
|
package/src/core/grid.ts
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import type { IconItem, IconSetDefinition } from "../types";
|
|
2
|
+
|
|
3
|
+
export interface GridOptions {
|
|
4
|
+
container: HTMLElement;
|
|
5
|
+
bodyElement: HTMLElement;
|
|
6
|
+
emptyElement: HTMLElement;
|
|
7
|
+
chunkSize?: number;
|
|
8
|
+
onSelect: (icon: IconItem) => void;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export class IconGrid {
|
|
12
|
+
private container: HTMLElement;
|
|
13
|
+
private bodyElement: HTMLElement;
|
|
14
|
+
private emptyElement: HTMLElement;
|
|
15
|
+
private chunkSize: number;
|
|
16
|
+
private onSelect: (icon: IconItem) => void;
|
|
17
|
+
|
|
18
|
+
private currentIcons: string[] = [];
|
|
19
|
+
private currentSet: IconSetDefinition | null = null;
|
|
20
|
+
private renderedCount = 0;
|
|
21
|
+
private selectedValue = "";
|
|
22
|
+
private scrollListener: () => void;
|
|
23
|
+
|
|
24
|
+
constructor(options: GridOptions) {
|
|
25
|
+
this.container = options.container;
|
|
26
|
+
this.bodyElement = options.bodyElement;
|
|
27
|
+
this.emptyElement = options.emptyElement;
|
|
28
|
+
this.chunkSize = options.chunkSize || 120;
|
|
29
|
+
this.onSelect = options.onSelect;
|
|
30
|
+
|
|
31
|
+
this.scrollListener = () => {
|
|
32
|
+
const { scrollTop, clientHeight, scrollHeight } = this.bodyElement;
|
|
33
|
+
if (scrollTop + clientHeight >= scrollHeight - 150) {
|
|
34
|
+
this.renderNextChunk();
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
this.bodyElement.addEventListener("scroll", this.scrollListener, { passive: true });
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
public setIcons(icons: string[], set: IconSetDefinition, selectedValue = ""): void {
|
|
42
|
+
this.currentIcons = icons;
|
|
43
|
+
this.currentSet = set;
|
|
44
|
+
this.selectedValue = selectedValue;
|
|
45
|
+
this.renderedCount = 0;
|
|
46
|
+
this.container.innerHTML = "";
|
|
47
|
+
this.bodyElement.scrollTop = 0;
|
|
48
|
+
|
|
49
|
+
if (icons.length === 0) {
|
|
50
|
+
this.emptyElement.style.display = "block";
|
|
51
|
+
this.container.style.display = "none";
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
this.emptyElement.style.display = "none";
|
|
56
|
+
this.container.style.display = "grid";
|
|
57
|
+
this.renderNextChunk();
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
public setSelectedValue(val: string): void {
|
|
61
|
+
this.selectedValue = val;
|
|
62
|
+
const buttons = this.container.querySelectorAll<HTMLButtonElement>(".iconpicker-item");
|
|
63
|
+
for (const btn of buttons) {
|
|
64
|
+
const iconClass = btn.getAttribute("data-icon-class");
|
|
65
|
+
if (iconClass === val) {
|
|
66
|
+
btn.classList.add("is-selected");
|
|
67
|
+
btn.setAttribute("aria-selected", "true");
|
|
68
|
+
} else {
|
|
69
|
+
btn.classList.remove("is-selected");
|
|
70
|
+
btn.removeAttribute("aria-selected");
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
private renderNextChunk(): void {
|
|
76
|
+
if (!this.currentSet || this.renderedCount >= this.currentIcons.length) {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const nextBatch = this.currentIcons.slice(this.renderedCount, this.renderedCount + this.chunkSize);
|
|
81
|
+
|
|
82
|
+
const fragment = document.createDocumentFragment();
|
|
83
|
+
|
|
84
|
+
for (const iconName of nextBatch) {
|
|
85
|
+
const className = this.currentSet.formatter
|
|
86
|
+
? this.currentSet.formatter(iconName)
|
|
87
|
+
: `${this.currentSet.prefix}${iconName}`;
|
|
88
|
+
|
|
89
|
+
const isSelected = className === this.selectedValue;
|
|
90
|
+
|
|
91
|
+
const btn = document.createElement("button");
|
|
92
|
+
btn.type = "button";
|
|
93
|
+
btn.className = `iconpicker-item ${isSelected ? "is-selected" : ""}`;
|
|
94
|
+
btn.title = iconName;
|
|
95
|
+
btn.setAttribute("aria-label", iconName);
|
|
96
|
+
btn.setAttribute("role", "option");
|
|
97
|
+
btn.setAttribute("data-icon-name", iconName);
|
|
98
|
+
btn.setAttribute("data-icon-class", className);
|
|
99
|
+
if (isSelected) {
|
|
100
|
+
btn.setAttribute("aria-selected", "true");
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const iconEl = document.createElement("i");
|
|
104
|
+
iconEl.className = className;
|
|
105
|
+
iconEl.setAttribute("aria-hidden", "true");
|
|
106
|
+
|
|
107
|
+
btn.appendChild(iconEl);
|
|
108
|
+
|
|
109
|
+
btn.addEventListener("click", (e) => {
|
|
110
|
+
e.preventDefault();
|
|
111
|
+
e.stopPropagation();
|
|
112
|
+
this.onSelect({
|
|
113
|
+
name: iconName,
|
|
114
|
+
className,
|
|
115
|
+
set: this.currentSet!.id
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
fragment.appendChild(btn);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
this.container.appendChild(fragment);
|
|
123
|
+
this.renderedCount += nextBatch.length;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
public destroy(): void {
|
|
127
|
+
this.bodyElement.removeEventListener("scroll", this.scrollListener);
|
|
128
|
+
}
|
|
129
|
+
}
|