@nuralyui/iconpicker 0.0.1
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/bundle.js +2796 -0
- package/bundle.js.gz +0 -0
- package/controllers/event.controller.d.ts +38 -0
- package/controllers/event.controller.d.ts.map +1 -0
- package/controllers/event.controller.js +68 -0
- package/controllers/event.controller.js.map +1 -0
- package/controllers/index.d.ts +9 -0
- package/controllers/index.d.ts.map +1 -0
- package/controllers/index.js +9 -0
- package/controllers/index.js.map +1 -0
- package/controllers/search.controller.d.ts +34 -0
- package/controllers/search.controller.d.ts.map +1 -0
- package/controllers/search.controller.js +55 -0
- package/controllers/search.controller.js.map +1 -0
- package/controllers/selection.controller.d.ts +27 -0
- package/controllers/selection.controller.d.ts.map +1 -0
- package/controllers/selection.controller.js +39 -0
- package/controllers/selection.controller.js.map +1 -0
- package/icon-picker.component.d.ts +119 -0
- package/icon-picker.component.d.ts.map +1 -0
- package/icon-picker.component.js +337 -0
- package/icon-picker.component.js.map +1 -0
- package/icon-picker.constant.d.ts +15 -0
- package/icon-picker.constant.d.ts.map +1 -0
- package/icon-picker.constant.js +31 -0
- package/icon-picker.constant.js.map +1 -0
- package/icon-picker.style.d.ts +8 -0
- package/icon-picker.style.d.ts.map +1 -0
- package/icon-picker.style.js +216 -0
- package/icon-picker.style.js.map +1 -0
- package/icon-picker.types.d.ts +49 -0
- package/icon-picker.types.d.ts.map +1 -0
- package/icon-picker.types.js +7 -0
- package/icon-picker.types.js.map +1 -0
- package/index.d.ts +9 -0
- package/index.d.ts.map +1 -0
- package/index.js +9 -0
- package/index.js.map +1 -0
- package/interfaces/icon-picker.interface.d.ts +13 -0
- package/interfaces/icon-picker.interface.d.ts.map +1 -0
- package/interfaces/icon-picker.interface.js +7 -0
- package/interfaces/icon-picker.interface.js.map +1 -0
- package/interfaces/index.d.ts +7 -0
- package/interfaces/index.d.ts.map +1 -0
- package/interfaces/index.js +7 -0
- package/interfaces/index.js.map +1 -0
- package/package.json +37 -0
- package/react.d.ts +14 -0
- package/react.d.ts.map +1 -0
- package/react.js +21 -0
- package/react.js.map +1 -0
- package/utils/icon-filter.utils.d.ts +29 -0
- package/utils/icon-filter.utils.d.ts.map +1 -0
- package/utils/icon-filter.utils.js +96 -0
- package/utils/icon-filter.utils.js.map +1 -0
- package/utils/icon-loader.utils.d.ts +39 -0
- package/utils/icon-loader.utils.d.ts.map +1 -0
- package/utils/icon-loader.utils.js +115 -0
- package/utils/icon-loader.utils.js.map +1 -0
- package/utils/index.d.ts +8 -0
- package/utils/index.d.ts.map +1 -0
- package/utils/index.js +8 -0
- package/utils/index.js.map +1 -0
- package/utils/lucide-icons.d.ts +10 -0
- package/utils/lucide-icons.d.ts.map +1 -0
- package/utils/lucide-icons.js +1624 -0
- package/utils/lucide-icons.js.map +1 -0
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2023 Nuraly, Laabidi Aymen
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
7
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
8
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
9
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
10
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
11
|
+
};
|
|
12
|
+
import { LitElement, html, nothing } from 'lit';
|
|
13
|
+
import { customElement, property, state } from 'lit/decorators.js';
|
|
14
|
+
import { styleMap } from 'lit/directives/style-map.js';
|
|
15
|
+
import { classMap } from 'lit/directives/class-map.js';
|
|
16
|
+
import { NuralyUIBaseMixin } from '@nuralyui/common/mixins';
|
|
17
|
+
import '@lit-labs/virtualizer';
|
|
18
|
+
import { grid } from '@lit-labs/virtualizer/layouts/grid.js';
|
|
19
|
+
// Import required components
|
|
20
|
+
import '../dropdown/dropdown.component.js';
|
|
21
|
+
import '../input/input.component.js';
|
|
22
|
+
import '../icon/icon.component.js';
|
|
23
|
+
import '../button/button.component.js';
|
|
24
|
+
// Import styles and types
|
|
25
|
+
import styles from './icon-picker.style.js';
|
|
26
|
+
import { EMPTY_STRING } from './icon-picker.types.js';
|
|
27
|
+
import { DEFAULT_PLACEHOLDER, DEFAULT_SEARCH_PLACEHOLDER, DEFAULT_EMPTY_MESSAGE, SEARCH_DEBOUNCE_DELAY } from './icon-picker.constant.js';
|
|
28
|
+
// Import controllers
|
|
29
|
+
import { IconPickerSelectionController, IconPickerSearchController, IconPickerEventController } from './controllers/index.js';
|
|
30
|
+
// Import utilities
|
|
31
|
+
import { IconLoaderUtils } from './utils/index.js';
|
|
32
|
+
/**
|
|
33
|
+
* Advanced icon picker component with search, virtual scrolling, and accessibility.
|
|
34
|
+
*
|
|
35
|
+
* Uses Lucide icons (1500+ beautiful icons) and provides an intuitive selection interface with
|
|
36
|
+
* search filtering, keyboard navigation, and multiple display options.
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```html
|
|
40
|
+
* <!-- Basic usage -->
|
|
41
|
+
* <nr-icon-picker></nr-icon-picker>
|
|
42
|
+
*
|
|
43
|
+
* <!-- With value -->
|
|
44
|
+
* <nr-icon-picker value="heart"></nr-icon-picker>
|
|
45
|
+
*
|
|
46
|
+
* <!-- Custom configuration -->
|
|
47
|
+
* <nr-icon-picker
|
|
48
|
+
* value="star"
|
|
49
|
+
* size="large"
|
|
50
|
+
* placement="top"
|
|
51
|
+
* show-search
|
|
52
|
+
* show-clear>
|
|
53
|
+
* </nr-icon-picker>
|
|
54
|
+
* ```
|
|
55
|
+
*
|
|
56
|
+
* @fires nr-icon-picker-change - Icon selection changed
|
|
57
|
+
* @fires nr-icon-picker-open - Dropdown opened
|
|
58
|
+
* @fires nr-icon-picker-close - Dropdown closed
|
|
59
|
+
* @fires nr-icon-picker-search - Search query changed
|
|
60
|
+
* @fires nr-icon-picker-clear - Selection cleared
|
|
61
|
+
*
|
|
62
|
+
* @cssproperty --icon-picker-dropdown-width - Width of dropdown
|
|
63
|
+
* @cssproperty --icon-picker-icon-size - Size of icon items
|
|
64
|
+
* @cssproperty --icon-picker-selected-bg - Selected icon background
|
|
65
|
+
* @cssproperty --icon-picker-selected-border - Selected icon border
|
|
66
|
+
*/
|
|
67
|
+
let NrIconPickerElement = class NrIconPickerElement extends NuralyUIBaseMixin(LitElement) {
|
|
68
|
+
constructor() {
|
|
69
|
+
super(...arguments);
|
|
70
|
+
this.requiredComponents = ['nr-dropdown', 'nr-input', 'nr-icon', 'nr-button'];
|
|
71
|
+
// Controllers
|
|
72
|
+
this.selectionController = new IconPickerSelectionController(this);
|
|
73
|
+
this.searchController = new IconPickerSearchController(this, SEARCH_DEBOUNCE_DELAY);
|
|
74
|
+
this.eventController = new IconPickerEventController(this);
|
|
75
|
+
// Public properties
|
|
76
|
+
this.value = EMPTY_STRING;
|
|
77
|
+
this.size = "small" /* IconPickerSize.Small */;
|
|
78
|
+
this.placement = "auto" /* IconPickerPlacement.Auto */;
|
|
79
|
+
this.trigger = "manual" /* IconPickerTrigger.Manual */;
|
|
80
|
+
this.disabled = false;
|
|
81
|
+
this.readonly = false;
|
|
82
|
+
this.placeholder = DEFAULT_PLACEHOLDER;
|
|
83
|
+
this.iconTypes = ["solid" /* IconType.Solid */];
|
|
84
|
+
this.showSearch = true;
|
|
85
|
+
this.showClear = true;
|
|
86
|
+
this.maxVisible = 500;
|
|
87
|
+
// Internal state
|
|
88
|
+
this.dropdownOpen = false;
|
|
89
|
+
this.allIcons = [];
|
|
90
|
+
this.filteredIcons = [];
|
|
91
|
+
this.searchQuery = EMPTY_STRING;
|
|
92
|
+
this.selectedIcon = null;
|
|
93
|
+
this.isLoading = false;
|
|
94
|
+
}
|
|
95
|
+
connectedCallback() {
|
|
96
|
+
super.connectedCallback();
|
|
97
|
+
this.loadIcons();
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Load icons from Lucide library
|
|
101
|
+
*/
|
|
102
|
+
loadIcons() {
|
|
103
|
+
this.isLoading = true;
|
|
104
|
+
try {
|
|
105
|
+
this.allIcons = IconLoaderUtils.loadIcons(this.iconTypes);
|
|
106
|
+
this.filteredIcons = [...this.allIcons];
|
|
107
|
+
// Set selected icon if value is provided
|
|
108
|
+
if (this.value) {
|
|
109
|
+
this.selectedIcon = this.allIcons.find(icon => icon.name === this.value) || null;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
catch (error) {
|
|
113
|
+
console.error('Failed to load icons:', error);
|
|
114
|
+
}
|
|
115
|
+
finally {
|
|
116
|
+
this.isLoading = false;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Handle icon selection
|
|
121
|
+
*/
|
|
122
|
+
handleIconSelect(icon) {
|
|
123
|
+
this.selectionController.selectIcon(icon);
|
|
124
|
+
this.eventController.dispatchChangeEvent(icon.name, icon);
|
|
125
|
+
this.dropdownOpen = false;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Handle search input
|
|
129
|
+
*/
|
|
130
|
+
handleSearchInput(e) {
|
|
131
|
+
const query = e.detail.value;
|
|
132
|
+
this.searchController.search(query);
|
|
133
|
+
this.eventController.dispatchSearchEvent(query);
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Handle clear button
|
|
137
|
+
*/
|
|
138
|
+
handleClear(e) {
|
|
139
|
+
e.stopPropagation();
|
|
140
|
+
this.selectionController.clearSelection();
|
|
141
|
+
this.eventController.dispatchClearEvent();
|
|
142
|
+
this.eventController.dispatchChangeEvent(EMPTY_STRING, null);
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Handle dropdown open
|
|
146
|
+
*/
|
|
147
|
+
handleDropdownOpen() {
|
|
148
|
+
this.dropdownOpen = true;
|
|
149
|
+
this.eventController.dispatchOpenEvent();
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Handle dropdown close
|
|
153
|
+
*/
|
|
154
|
+
handleDropdownClose() {
|
|
155
|
+
this.dropdownOpen = false;
|
|
156
|
+
this.searchController.clearSearch();
|
|
157
|
+
this.eventController.dispatchCloseEvent();
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Toggle dropdown
|
|
161
|
+
*/
|
|
162
|
+
toggleDropdown() {
|
|
163
|
+
this.dropdownOpen = !this.dropdownOpen;
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Render trigger button
|
|
167
|
+
*/
|
|
168
|
+
renderTrigger() {
|
|
169
|
+
return html `
|
|
170
|
+
<nr-button
|
|
171
|
+
class="trigger-button"
|
|
172
|
+
.disabled=${this.disabled}
|
|
173
|
+
size=${this.size}
|
|
174
|
+
@click=${this.toggleDropdown}
|
|
175
|
+
>
|
|
176
|
+
${this.selectedIcon
|
|
177
|
+
? html `
|
|
178
|
+
<nr-icon class="icon-preview" .name=${this.selectedIcon.name}></nr-icon>
|
|
179
|
+
<span class="icon-name">${this.selectedIcon.name}</span>
|
|
180
|
+
`
|
|
181
|
+
: html `<span class="placeholder">${this.placeholder}</span>`}
|
|
182
|
+
${this.showClear && this.selectedIcon
|
|
183
|
+
? html `
|
|
184
|
+
<nr-icon
|
|
185
|
+
name="times"
|
|
186
|
+
@click=${this.handleClear}
|
|
187
|
+
style="margin-left: auto; cursor: pointer;"
|
|
188
|
+
></nr-icon>
|
|
189
|
+
`
|
|
190
|
+
: nothing}
|
|
191
|
+
</nr-button>
|
|
192
|
+
`;
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Render icon grid
|
|
196
|
+
*/
|
|
197
|
+
renderIconGrid() {
|
|
198
|
+
if (this.isLoading) {
|
|
199
|
+
return html `
|
|
200
|
+
<div class="loading-state">
|
|
201
|
+
<nr-icon name="spinner"></nr-icon>
|
|
202
|
+
<div class="empty-message">Loading icons...</div>
|
|
203
|
+
</div>
|
|
204
|
+
`;
|
|
205
|
+
}
|
|
206
|
+
if (this.filteredIcons.length === 0) {
|
|
207
|
+
return html `
|
|
208
|
+
<div class="empty-state">
|
|
209
|
+
<nr-icon name="search"></nr-icon>
|
|
210
|
+
<div class="empty-message">${DEFAULT_EMPTY_MESSAGE}</div>
|
|
211
|
+
</div>
|
|
212
|
+
`;
|
|
213
|
+
}
|
|
214
|
+
// Limit visible icons for performance
|
|
215
|
+
const visibleIcons = this.filteredIcons.slice(0, this.maxVisible);
|
|
216
|
+
return html `
|
|
217
|
+
<div class="dropdown-content">
|
|
218
|
+
${this.showSearch
|
|
219
|
+
? html `
|
|
220
|
+
<div class="search-container">
|
|
221
|
+
<nr-input
|
|
222
|
+
size="small"
|
|
223
|
+
.placeholder=${DEFAULT_SEARCH_PLACEHOLDER}
|
|
224
|
+
.value=${this.searchQuery}
|
|
225
|
+
@nr-input=${this.handleSearchInput}
|
|
226
|
+
autocomplete="off"
|
|
227
|
+
>
|
|
228
|
+
<nr-icon slot="addon-before" name="search"></nr-icon>
|
|
229
|
+
</nr-input>
|
|
230
|
+
</div>
|
|
231
|
+
`
|
|
232
|
+
: nothing}
|
|
233
|
+
<div class="icons-grid-container">
|
|
234
|
+
<lit-virtualizer
|
|
235
|
+
.items=${visibleIcons}
|
|
236
|
+
.layout=${grid({ itemSize: '40px' })}
|
|
237
|
+
.renderItem=${((icon) => html `
|
|
238
|
+
<div
|
|
239
|
+
class=${classMap({
|
|
240
|
+
'icon-item': true,
|
|
241
|
+
'selected': this.selectionController.isSelected(icon)
|
|
242
|
+
})}
|
|
243
|
+
@click=${() => this.handleIconSelect(icon)}
|
|
244
|
+
tabindex="0"
|
|
245
|
+
role="button"
|
|
246
|
+
aria-label="Select ${icon.name} icon"
|
|
247
|
+
>
|
|
248
|
+
<nr-icon .name=${icon.name}></nr-icon>
|
|
249
|
+
</div>
|
|
250
|
+
`)}
|
|
251
|
+
></lit-virtualizer>
|
|
252
|
+
</div>
|
|
253
|
+
</div>
|
|
254
|
+
`;
|
|
255
|
+
}
|
|
256
|
+
render() {
|
|
257
|
+
return html `
|
|
258
|
+
<nr-dropdown
|
|
259
|
+
.open=${this.dropdownOpen}
|
|
260
|
+
trigger="manual"
|
|
261
|
+
.placement=${this.placement}
|
|
262
|
+
.closeOnOutsideClick=${true}
|
|
263
|
+
.closeOnEscape=${true}
|
|
264
|
+
@nr-dropdown-open=${this.handleDropdownOpen}
|
|
265
|
+
@nr-dropdown-close=${this.handleDropdownClose}
|
|
266
|
+
style=${styleMap({
|
|
267
|
+
'--dropdown-width': 'var(--icon-picker-dropdown-width)',
|
|
268
|
+
'--dropdown-max-height': 'var(--icon-picker-dropdown-max-height)'
|
|
269
|
+
})}
|
|
270
|
+
>
|
|
271
|
+
<div slot="trigger" class="trigger-container">
|
|
272
|
+
${this.renderTrigger()}
|
|
273
|
+
</div>
|
|
274
|
+
<div slot="content">
|
|
275
|
+
${this.renderIconGrid()}
|
|
276
|
+
</div>
|
|
277
|
+
</nr-dropdown>
|
|
278
|
+
`;
|
|
279
|
+
}
|
|
280
|
+
};
|
|
281
|
+
NrIconPickerElement.styles = styles;
|
|
282
|
+
__decorate([
|
|
283
|
+
property({ type: String, reflect: true })
|
|
284
|
+
], NrIconPickerElement.prototype, "value", void 0);
|
|
285
|
+
__decorate([
|
|
286
|
+
property({ type: String, reflect: true })
|
|
287
|
+
], NrIconPickerElement.prototype, "size", void 0);
|
|
288
|
+
__decorate([
|
|
289
|
+
property({ type: String })
|
|
290
|
+
], NrIconPickerElement.prototype, "placement", void 0);
|
|
291
|
+
__decorate([
|
|
292
|
+
property({ type: String })
|
|
293
|
+
], NrIconPickerElement.prototype, "trigger", void 0);
|
|
294
|
+
__decorate([
|
|
295
|
+
property({ type: Boolean, reflect: true })
|
|
296
|
+
], NrIconPickerElement.prototype, "disabled", void 0);
|
|
297
|
+
__decorate([
|
|
298
|
+
property({ type: Boolean })
|
|
299
|
+
], NrIconPickerElement.prototype, "readonly", void 0);
|
|
300
|
+
__decorate([
|
|
301
|
+
property({ type: String })
|
|
302
|
+
], NrIconPickerElement.prototype, "placeholder", void 0);
|
|
303
|
+
__decorate([
|
|
304
|
+
property({ type: Array })
|
|
305
|
+
], NrIconPickerElement.prototype, "iconTypes", void 0);
|
|
306
|
+
__decorate([
|
|
307
|
+
property({ type: Boolean, attribute: 'show-search' })
|
|
308
|
+
], NrIconPickerElement.prototype, "showSearch", void 0);
|
|
309
|
+
__decorate([
|
|
310
|
+
property({ type: Boolean, attribute: 'show-clear' })
|
|
311
|
+
], NrIconPickerElement.prototype, "showClear", void 0);
|
|
312
|
+
__decorate([
|
|
313
|
+
property({ type: Number, attribute: 'max-visible' })
|
|
314
|
+
], NrIconPickerElement.prototype, "maxVisible", void 0);
|
|
315
|
+
__decorate([
|
|
316
|
+
state()
|
|
317
|
+
], NrIconPickerElement.prototype, "dropdownOpen", void 0);
|
|
318
|
+
__decorate([
|
|
319
|
+
state()
|
|
320
|
+
], NrIconPickerElement.prototype, "allIcons", void 0);
|
|
321
|
+
__decorate([
|
|
322
|
+
state()
|
|
323
|
+
], NrIconPickerElement.prototype, "filteredIcons", void 0);
|
|
324
|
+
__decorate([
|
|
325
|
+
state()
|
|
326
|
+
], NrIconPickerElement.prototype, "searchQuery", void 0);
|
|
327
|
+
__decorate([
|
|
328
|
+
state()
|
|
329
|
+
], NrIconPickerElement.prototype, "selectedIcon", void 0);
|
|
330
|
+
__decorate([
|
|
331
|
+
state()
|
|
332
|
+
], NrIconPickerElement.prototype, "isLoading", void 0);
|
|
333
|
+
NrIconPickerElement = __decorate([
|
|
334
|
+
customElement('nr-icon-picker')
|
|
335
|
+
], NrIconPickerElement);
|
|
336
|
+
export { NrIconPickerElement };
|
|
337
|
+
//# sourceMappingURL=icon-picker.component.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"icon-picker.component.js","sourceRoot":"","sources":["../../../../src/components/iconpicker/icon-picker.component.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @license\n * Copyright 2023 Nuraly, Laabidi Aymen\n * SPDX-License-Identifier: MIT\n */\n\nimport { LitElement, html, nothing } from 'lit';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport { styleMap } from 'lit/directives/style-map.js';\nimport { classMap } from 'lit/directives/class-map.js';\nimport { NuralyUIBaseMixin } from '@nuralyui/common/mixins';\nimport '@lit-labs/virtualizer';\nimport { grid } from '@lit-labs/virtualizer/layouts/grid.js';\n\n// Import required components\nimport '../dropdown/dropdown.component.js';\nimport '../input/input.component.js';\nimport '../icon/icon.component.js';\nimport '../button/button.component.js';\n\n// Import styles and types\nimport styles from './icon-picker.style.js';\nimport {\n IconPickerSize,\n IconPickerPlacement,\n IconPickerTrigger,\n IconType,\n EMPTY_STRING\n} from './icon-picker.types.js';\nimport type { IconPickerIcon } from './icon-picker.types.js';\nimport {\n DEFAULT_PLACEHOLDER,\n DEFAULT_SEARCH_PLACEHOLDER,\n DEFAULT_EMPTY_MESSAGE,\n SEARCH_DEBOUNCE_DELAY\n} from './icon-picker.constant.js';\n\n// Import controllers\nimport {\n IconPickerSelectionController,\n IconPickerSearchController,\n IconPickerEventController\n} from './controllers/index.js';\n\n// Import utilities\nimport { IconLoaderUtils } from './utils/index.js';\n\n// Import interfaces\nimport type { IconPickerHost } from './interfaces/index.js';\n\n/**\n * Advanced icon picker component with search, virtual scrolling, and accessibility.\n * \n * Uses Lucide icons (1500+ beautiful icons) and provides an intuitive selection interface with\n * search filtering, keyboard navigation, and multiple display options.\n * \n * @example\n * ```html\n * <!-- Basic usage -->\n * <nr-icon-picker></nr-icon-picker>\n * \n * <!-- With value -->\n * <nr-icon-picker value=\"heart\"></nr-icon-picker>\n * \n * <!-- Custom configuration -->\n * <nr-icon-picker\n * value=\"star\"\n * size=\"large\"\n * placement=\"top\"\n * show-search\n * show-clear>\n * </nr-icon-picker>\n * ```\n * \n * @fires nr-icon-picker-change - Icon selection changed\n * @fires nr-icon-picker-open - Dropdown opened\n * @fires nr-icon-picker-close - Dropdown closed\n * @fires nr-icon-picker-search - Search query changed\n * @fires nr-icon-picker-clear - Selection cleared\n * \n * @cssproperty --icon-picker-dropdown-width - Width of dropdown\n * @cssproperty --icon-picker-icon-size - Size of icon items\n * @cssproperty --icon-picker-selected-bg - Selected icon background\n * @cssproperty --icon-picker-selected-border - Selected icon border\n */\n@customElement('nr-icon-picker')\nexport class NrIconPickerElement extends NuralyUIBaseMixin(LitElement) implements IconPickerHost {\n static override styles = styles;\n\n override requiredComponents = ['nr-dropdown', 'nr-input', 'nr-icon', 'nr-button'];\n\n // Controllers\n private selectionController = new IconPickerSelectionController(this);\n private searchController = new IconPickerSearchController(this, SEARCH_DEBOUNCE_DELAY);\n private eventController = new IconPickerEventController(this);\n\n // Public properties\n @property({ type: String, reflect: true }) value = EMPTY_STRING;\n @property({ type: String, reflect: true }) size = IconPickerSize.Small;\n @property({ type: String }) placement: string = IconPickerPlacement.Auto;\n @property({ type: String }) trigger: string = IconPickerTrigger.Manual;\n @property({ type: Boolean, reflect: true }) disabled = false;\n @property({ type: Boolean }) readonly = false;\n @property({ type: String }) placeholder = DEFAULT_PLACEHOLDER;\n @property({ type: Array }) iconTypes: IconType[] = [IconType.Solid];\n @property({ type: Boolean, attribute: 'show-search' }) showSearch = true;\n @property({ type: Boolean, attribute: 'show-clear' }) showClear = true;\n @property({ type: Number, attribute: 'max-visible' }) maxVisible = 500;\n\n // Internal state\n @state() dropdownOpen = false;\n @state() allIcons: IconPickerIcon[] = [];\n @state() filteredIcons: IconPickerIcon[] = [];\n @state() searchQuery = EMPTY_STRING;\n @state() selectedIcon: IconPickerIcon | null = null;\n @state() isLoading = false;\n\n override connectedCallback() {\n super.connectedCallback();\n this.loadIcons();\n }\n\n /**\n * Load icons from Lucide library\n */\n private loadIcons(): void {\n this.isLoading = true;\n try {\n this.allIcons = IconLoaderUtils.loadIcons(this.iconTypes);\n this.filteredIcons = [...this.allIcons];\n \n // Set selected icon if value is provided\n if (this.value) {\n this.selectedIcon = this.allIcons.find(icon => icon.name === this.value) || null;\n }\n } catch (error) {\n console.error('Failed to load icons:', error);\n } finally {\n this.isLoading = false;\n }\n }\n\n /**\n * Handle icon selection\n */\n handleIconSelect(icon: IconPickerIcon): void {\n this.selectionController.selectIcon(icon);\n this.eventController.dispatchChangeEvent(icon.name, icon);\n this.dropdownOpen = false;\n }\n\n /**\n * Handle search input\n */\n private handleSearchInput(e: CustomEvent): void {\n const query = e.detail.value;\n this.searchController.search(query);\n this.eventController.dispatchSearchEvent(query);\n }\n\n /**\n * Handle clear button\n */\n private handleClear(e: Event): void {\n e.stopPropagation();\n this.selectionController.clearSelection();\n this.eventController.dispatchClearEvent();\n this.eventController.dispatchChangeEvent(EMPTY_STRING, null);\n }\n\n /**\n * Handle dropdown open\n */\n private handleDropdownOpen(): void {\n this.dropdownOpen = true;\n this.eventController.dispatchOpenEvent();\n }\n\n /**\n * Handle dropdown close\n */\n private handleDropdownClose(): void {\n this.dropdownOpen = false;\n this.searchController.clearSearch();\n this.eventController.dispatchCloseEvent();\n }\n\n /**\n * Toggle dropdown\n */\n private toggleDropdown(): void {\n this.dropdownOpen = !this.dropdownOpen;\n }\n\n /**\n * Render trigger button\n */\n private renderTrigger() {\n return html`\n <nr-button\n class=\"trigger-button\"\n .disabled=${this.disabled}\n size=${this.size}\n @click=${this.toggleDropdown}\n >\n ${this.selectedIcon\n ? html`\n <nr-icon class=\"icon-preview\" .name=${this.selectedIcon.name}></nr-icon>\n <span class=\"icon-name\">${this.selectedIcon.name}</span>\n `\n : html`<span class=\"placeholder\">${this.placeholder}</span>`\n }\n ${this.showClear && this.selectedIcon\n ? html`\n <nr-icon\n name=\"times\"\n @click=${this.handleClear}\n style=\"margin-left: auto; cursor: pointer;\"\n ></nr-icon>\n `\n : nothing\n }\n </nr-button>\n `;\n }\n\n /**\n * Render icon grid\n */\n private renderIconGrid() {\n if (this.isLoading) {\n return html`\n <div class=\"loading-state\">\n <nr-icon name=\"spinner\"></nr-icon>\n <div class=\"empty-message\">Loading icons...</div>\n </div>\n `;\n }\n\n if (this.filteredIcons.length === 0) {\n return html`\n <div class=\"empty-state\">\n <nr-icon name=\"search\"></nr-icon>\n <div class=\"empty-message\">${DEFAULT_EMPTY_MESSAGE}</div>\n </div>\n `;\n }\n\n // Limit visible icons for performance\n const visibleIcons = this.filteredIcons.slice(0, this.maxVisible);\n\n return html`\n <div class=\"dropdown-content\">\n ${this.showSearch\n ? html`\n <div class=\"search-container\">\n <nr-input\n size=\"small\"\n .placeholder=${DEFAULT_SEARCH_PLACEHOLDER}\n .value=${this.searchQuery}\n @nr-input=${this.handleSearchInput}\n autocomplete=\"off\"\n >\n <nr-icon slot=\"addon-before\" name=\"search\"></nr-icon>\n </nr-input>\n </div>\n `\n : nothing\n }\n <div class=\"icons-grid-container\">\n <lit-virtualizer\n .items=${visibleIcons}\n .layout=${grid({ itemSize: '40px' })}\n .renderItem=${((icon: IconPickerIcon) => html`\n <div\n class=${classMap({\n 'icon-item': true,\n 'selected': this.selectionController.isSelected(icon)\n })}\n @click=${() => this.handleIconSelect(icon)}\n tabindex=\"0\"\n role=\"button\"\n aria-label=\"Select ${icon.name} icon\"\n >\n <nr-icon .name=${icon.name}></nr-icon>\n </div>\n `) as any}\n ></lit-virtualizer>\n </div>\n </div>\n `;\n }\n\n override render() {\n return html`\n <nr-dropdown\n .open=${this.dropdownOpen}\n trigger=\"manual\"\n .placement=${this.placement as any}\n .closeOnOutsideClick=${true}\n .closeOnEscape=${true}\n @nr-dropdown-open=${this.handleDropdownOpen}\n @nr-dropdown-close=${this.handleDropdownClose}\n style=${styleMap({\n '--dropdown-width': 'var(--icon-picker-dropdown-width)',\n '--dropdown-max-height': 'var(--icon-picker-dropdown-max-height)'\n })}\n >\n <div slot=\"trigger\" class=\"trigger-container\">\n ${this.renderTrigger()}\n </div>\n <div slot=\"content\">\n ${this.renderIconGrid()}\n </div>\n </nr-dropdown>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'nr-icon-picker': NrIconPickerElement;\n }\n}\n"]}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2023 Nuraly, Laabidi Aymen
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
export declare const DEFAULT_PLACEHOLDER = "Select icon";
|
|
7
|
+
export declare const DEFAULT_SEARCH_PLACEHOLDER = "Search icons...";
|
|
8
|
+
export declare const DEFAULT_EMPTY_MESSAGE = "No icons found";
|
|
9
|
+
export declare const DEFAULT_GRID_SIZE = "32px";
|
|
10
|
+
export declare const DEFAULT_MAX_VISIBLE_ICONS = 500;
|
|
11
|
+
export declare const DEFAULT_DROPDOWN_WIDTH = "320px";
|
|
12
|
+
export declare const DEFAULT_DROPDOWN_MAX_HEIGHT = "380px";
|
|
13
|
+
export declare const ICON_CATEGORIES: readonly ["all", "arrow", "communication", "file", "interface", "media", "social", "text", "utility", "business", "design", "shapes"];
|
|
14
|
+
export declare const SEARCH_DEBOUNCE_DELAY = 300;
|
|
15
|
+
//# sourceMappingURL=icon-picker.constant.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"icon-picker.constant.d.ts","sourceRoot":"","sources":["../../../../src/components/iconpicker/icon-picker.constant.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,eAAO,MAAM,mBAAmB,gBAAgB,CAAC;AACjD,eAAO,MAAM,0BAA0B,oBAAoB,CAAC;AAC5D,eAAO,MAAM,qBAAqB,mBAAmB,CAAC;AACtD,eAAO,MAAM,iBAAiB,SAAS,CAAC;AACxC,eAAO,MAAM,yBAAyB,MAAM,CAAC;AAC7C,eAAO,MAAM,sBAAsB,UAAU,CAAC;AAC9C,eAAO,MAAM,2BAA2B,UAAU,CAAC;AAGnD,eAAO,MAAM,eAAe,uIAalB,CAAC;AAGX,eAAO,MAAM,qBAAqB,MAAM,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2023 Nuraly, Laabidi Aymen
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
// Default configuration
|
|
7
|
+
export const DEFAULT_PLACEHOLDER = 'Select icon';
|
|
8
|
+
export const DEFAULT_SEARCH_PLACEHOLDER = 'Search icons...';
|
|
9
|
+
export const DEFAULT_EMPTY_MESSAGE = 'No icons found';
|
|
10
|
+
export const DEFAULT_GRID_SIZE = '32px';
|
|
11
|
+
export const DEFAULT_MAX_VISIBLE_ICONS = 500;
|
|
12
|
+
export const DEFAULT_DROPDOWN_WIDTH = '320px';
|
|
13
|
+
export const DEFAULT_DROPDOWN_MAX_HEIGHT = '380px';
|
|
14
|
+
// Icon categories
|
|
15
|
+
export const ICON_CATEGORIES = [
|
|
16
|
+
'all',
|
|
17
|
+
'arrow',
|
|
18
|
+
'communication',
|
|
19
|
+
'file',
|
|
20
|
+
'interface',
|
|
21
|
+
'media',
|
|
22
|
+
'social',
|
|
23
|
+
'text',
|
|
24
|
+
'utility',
|
|
25
|
+
'business',
|
|
26
|
+
'design',
|
|
27
|
+
'shapes'
|
|
28
|
+
];
|
|
29
|
+
// Search debounce delay
|
|
30
|
+
export const SEARCH_DEBOUNCE_DELAY = 300;
|
|
31
|
+
//# sourceMappingURL=icon-picker.constant.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"icon-picker.constant.js","sourceRoot":"","sources":["../../../../src/components/iconpicker/icon-picker.constant.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,wBAAwB;AACxB,MAAM,CAAC,MAAM,mBAAmB,GAAG,aAAa,CAAC;AACjD,MAAM,CAAC,MAAM,0BAA0B,GAAG,iBAAiB,CAAC;AAC5D,MAAM,CAAC,MAAM,qBAAqB,GAAG,gBAAgB,CAAC;AACtD,MAAM,CAAC,MAAM,iBAAiB,GAAG,MAAM,CAAC;AACxC,MAAM,CAAC,MAAM,yBAAyB,GAAG,GAAG,CAAC;AAC7C,MAAM,CAAC,MAAM,sBAAsB,GAAG,OAAO,CAAC;AAC9C,MAAM,CAAC,MAAM,2BAA2B,GAAG,OAAO,CAAC;AAEnD,kBAAkB;AAClB,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,KAAK;IACL,OAAO;IACP,eAAe;IACf,MAAM;IACN,WAAW;IACX,OAAO;IACP,QAAQ;IACR,MAAM;IACN,SAAS;IACT,UAAU;IACV,QAAQ;IACR,QAAQ;CACA,CAAC;AAEX,wBAAwB;AACxB,MAAM,CAAC,MAAM,qBAAqB,GAAG,GAAG,CAAC","sourcesContent":["/**\n * @license\n * Copyright 2023 Nuraly, Laabidi Aymen\n * SPDX-License-Identifier: MIT\n */\n\n// Default configuration\nexport const DEFAULT_PLACEHOLDER = 'Select icon';\nexport const DEFAULT_SEARCH_PLACEHOLDER = 'Search icons...';\nexport const DEFAULT_EMPTY_MESSAGE = 'No icons found';\nexport const DEFAULT_GRID_SIZE = '32px';\nexport const DEFAULT_MAX_VISIBLE_ICONS = 500;\nexport const DEFAULT_DROPDOWN_WIDTH = '320px';\nexport const DEFAULT_DROPDOWN_MAX_HEIGHT = '380px';\n\n// Icon categories\nexport const ICON_CATEGORIES = [\n 'all',\n 'arrow',\n 'communication',\n 'file',\n 'interface',\n 'media',\n 'social',\n 'text',\n 'utility',\n 'business',\n 'design',\n 'shapes'\n] as const;\n\n// Search debounce delay\nexport const SEARCH_DEBOUNCE_DELAY = 300;\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"icon-picker.style.d.ts","sourceRoot":"","sources":["../../../../src/components/iconpicker/icon-picker.style.ts"],"names":[],"mappings":"AAAA;;;;GAIG;;AAIH,wBAgNE"}
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2023 Nuraly, Laabidi Aymen
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
import { css } from 'lit';
|
|
7
|
+
export default css `
|
|
8
|
+
:host {
|
|
9
|
+
/* Sizing */
|
|
10
|
+
--icon-picker-trigger-width: 100%;
|
|
11
|
+
--icon-picker-trigger-height: auto;
|
|
12
|
+
--icon-picker-dropdown-width: 320px;
|
|
13
|
+
--icon-picker-dropdown-max-height: 380px;
|
|
14
|
+
--icon-picker-grid-gap: 4px;
|
|
15
|
+
--icon-picker-icon-size: 24px;
|
|
16
|
+
--icon-picker-icon-padding: 8px;
|
|
17
|
+
|
|
18
|
+
/* Colors - Light mode */
|
|
19
|
+
--icon-picker-background: var(--nuraly-background-primary, #ffffff);
|
|
20
|
+
--icon-picker-border: var(--nuraly-border-color, #d0d0d0);
|
|
21
|
+
--icon-picker-text: var(--nuraly-text-primary, #000000);
|
|
22
|
+
--icon-picker-hover-bg: var(--nuraly-background-hover, #f5f5f5);
|
|
23
|
+
--icon-picker-selected-bg: var(--nuraly-primary-light, #e6f7ff);
|
|
24
|
+
--icon-picker-selected-border: var(--nuraly-primary-color, #1890ff);
|
|
25
|
+
--icon-picker-placeholder-color: var(--nuraly-text-secondary, #999999);
|
|
26
|
+
|
|
27
|
+
display: inline-block;
|
|
28
|
+
width: var(--icon-picker-trigger-width);
|
|
29
|
+
position: relative;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
@media (prefers-color-scheme: dark) {
|
|
33
|
+
:host {
|
|
34
|
+
--icon-picker-background: var(--nuraly-background-primary, #1f1f1f);
|
|
35
|
+
--icon-picker-border: var(--nuraly-border-color, #404040);
|
|
36
|
+
--icon-picker-text: var(--nuraly-text-primary, #ffffff);
|
|
37
|
+
--icon-picker-hover-bg: var(--nuraly-background-hover, #2a2a2a);
|
|
38
|
+
--icon-picker-selected-bg: var(--nuraly-primary-dark, #003a8c);
|
|
39
|
+
--icon-picker-selected-border: var(--nuraly-primary-color, #40a9ff);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/* Trigger container */
|
|
44
|
+
.trigger-container {
|
|
45
|
+
width: 100%;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.trigger-button {
|
|
49
|
+
width: 100%;
|
|
50
|
+
display: flex;
|
|
51
|
+
align-items: center;
|
|
52
|
+
gap: 8px;
|
|
53
|
+
padding: 0 12px;
|
|
54
|
+
cursor: pointer;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/* Icon preview in trigger */
|
|
58
|
+
.icon-preview {
|
|
59
|
+
font-size: 1.1rem;
|
|
60
|
+
display: flex;
|
|
61
|
+
align-items: center;
|
|
62
|
+
justify-content: center;
|
|
63
|
+
flex-shrink: 0;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.icon-name {
|
|
67
|
+
font-size: 0.875rem;
|
|
68
|
+
overflow: hidden;
|
|
69
|
+
text-overflow: ellipsis;
|
|
70
|
+
white-space: nowrap;
|
|
71
|
+
color: var(--icon-picker-text);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.placeholder {
|
|
75
|
+
font-size: 0.875rem;
|
|
76
|
+
color: var(--icon-picker-placeholder-color);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/* Dropdown content */
|
|
80
|
+
.dropdown-content {
|
|
81
|
+
width: var(--icon-picker-dropdown-width);
|
|
82
|
+
max-height: var(--icon-picker-dropdown-max-height);
|
|
83
|
+
background: var(--icon-picker-background);
|
|
84
|
+
display: flex;
|
|
85
|
+
flex-direction: column;
|
|
86
|
+
overflow: hidden;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/* Search container */
|
|
90
|
+
.search-container {
|
|
91
|
+
padding: 12px;
|
|
92
|
+
background: var(--icon-picker-background);
|
|
93
|
+
border-bottom: 1px solid var(--icon-picker-border);
|
|
94
|
+
flex-shrink: 0;
|
|
95
|
+
z-index: 10;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/* Icons grid container */
|
|
99
|
+
.icons-grid-container {
|
|
100
|
+
flex: 1;
|
|
101
|
+
min-height: 0;
|
|
102
|
+
overflow: auto;
|
|
103
|
+
padding: 8px;
|
|
104
|
+
background: var(--icon-picker-background);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/* Icon grid using lit-virtualizer */
|
|
108
|
+
.icons-grid {
|
|
109
|
+
display: grid;
|
|
110
|
+
grid-template-columns: repeat(auto-fill, minmax(var(--icon-picker-grid-gap), 1fr));
|
|
111
|
+
gap: var(--icon-picker-grid-gap);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/* Individual icon item */
|
|
115
|
+
.icon-item {
|
|
116
|
+
display: flex;
|
|
117
|
+
align-items: center;
|
|
118
|
+
justify-content: center;
|
|
119
|
+
padding: var(--icon-picker-icon-padding);
|
|
120
|
+
cursor: pointer;
|
|
121
|
+
border-radius: 4px;
|
|
122
|
+
border: 2px solid transparent;
|
|
123
|
+
transition: all 0.2s ease;
|
|
124
|
+
min-width: var(--icon-picker-icon-size);
|
|
125
|
+
min-height: var(--icon-picker-icon-size);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
.icon-item:hover {
|
|
129
|
+
background-color: var(--icon-picker-hover-bg);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
.icon-item.selected {
|
|
133
|
+
background-color: var(--icon-picker-selected-bg);
|
|
134
|
+
border-color: var(--icon-picker-selected-border);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
.icon-item:focus {
|
|
138
|
+
outline: 2px solid var(--icon-picker-selected-border);
|
|
139
|
+
outline-offset: 2px;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
.icon-item nr-icon {
|
|
143
|
+
font-size: var(--icon-picker-icon-size);
|
|
144
|
+
color: var(--icon-picker-text);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/* Empty state */
|
|
148
|
+
.empty-state {
|
|
149
|
+
padding: 40px 20px;
|
|
150
|
+
text-align: center;
|
|
151
|
+
color: var(--icon-picker-placeholder-color);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
.empty-state nr-icon {
|
|
155
|
+
font-size: 48px;
|
|
156
|
+
margin-bottom: 12px;
|
|
157
|
+
opacity: 0.5;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
.empty-message {
|
|
161
|
+
font-size: 0.875rem;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/* Loading state */
|
|
165
|
+
.loading-state {
|
|
166
|
+
padding: 40px 20px;
|
|
167
|
+
text-align: center;
|
|
168
|
+
color: var(--icon-picker-placeholder-color);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/* Disabled state */
|
|
172
|
+
:host([disabled]) {
|
|
173
|
+
opacity: 0.6;
|
|
174
|
+
pointer-events: none;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/* Size variants */
|
|
178
|
+
:host([size="small"]) {
|
|
179
|
+
--icon-picker-icon-size: 20px;
|
|
180
|
+
--icon-picker-icon-padding: 6px;
|
|
181
|
+
--icon-picker-dropdown-width: 280px;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
:host([size="large"]) {
|
|
185
|
+
--icon-picker-icon-size: 28px;
|
|
186
|
+
--icon-picker-icon-padding: 10px;
|
|
187
|
+
--icon-picker-dropdown-width: 360px;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/* Accessibility */
|
|
191
|
+
@media (prefers-reduced-motion: reduce) {
|
|
192
|
+
.icon-item {
|
|
193
|
+
transition: none;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/* Scrollbar styling */
|
|
198
|
+
.icons-grid-container::-webkit-scrollbar {
|
|
199
|
+
width: 8px;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
.icons-grid-container::-webkit-scrollbar-track {
|
|
203
|
+
background: transparent;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
.icons-grid-container::-webkit-scrollbar-thumb {
|
|
207
|
+
background: var(--icon-picker-border);
|
|
208
|
+
border-radius: 4px;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
.icons-grid-container::-webkit-scrollbar-thumb:hover {
|
|
212
|
+
background: var(--icon-picker-text);
|
|
213
|
+
opacity: 0.5;
|
|
214
|
+
}
|
|
215
|
+
`;
|
|
216
|
+
//# sourceMappingURL=icon-picker.style.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"icon-picker.style.js","sourceRoot":"","sources":["../../../../src/components/iconpicker/icon-picker.style.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAE1B,eAAe,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgNjB,CAAC","sourcesContent":["/**\n * @license\n * Copyright 2023 Nuraly, Laabidi Aymen\n * SPDX-License-Identifier: MIT\n */\n\nimport { css } from 'lit';\n\nexport default css`\n :host {\n /* Sizing */\n --icon-picker-trigger-width: 100%;\n --icon-picker-trigger-height: auto;\n --icon-picker-dropdown-width: 320px;\n --icon-picker-dropdown-max-height: 380px;\n --icon-picker-grid-gap: 4px;\n --icon-picker-icon-size: 24px;\n --icon-picker-icon-padding: 8px;\n \n /* Colors - Light mode */\n --icon-picker-background: var(--nuraly-background-primary, #ffffff);\n --icon-picker-border: var(--nuraly-border-color, #d0d0d0);\n --icon-picker-text: var(--nuraly-text-primary, #000000);\n --icon-picker-hover-bg: var(--nuraly-background-hover, #f5f5f5);\n --icon-picker-selected-bg: var(--nuraly-primary-light, #e6f7ff);\n --icon-picker-selected-border: var(--nuraly-primary-color, #1890ff);\n --icon-picker-placeholder-color: var(--nuraly-text-secondary, #999999);\n \n display: inline-block;\n width: var(--icon-picker-trigger-width);\n position: relative;\n }\n\n @media (prefers-color-scheme: dark) {\n :host {\n --icon-picker-background: var(--nuraly-background-primary, #1f1f1f);\n --icon-picker-border: var(--nuraly-border-color, #404040);\n --icon-picker-text: var(--nuraly-text-primary, #ffffff);\n --icon-picker-hover-bg: var(--nuraly-background-hover, #2a2a2a);\n --icon-picker-selected-bg: var(--nuraly-primary-dark, #003a8c);\n --icon-picker-selected-border: var(--nuraly-primary-color, #40a9ff);\n }\n }\n\n /* Trigger container */\n .trigger-container {\n width: 100%;\n }\n\n .trigger-button {\n width: 100%;\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 0 12px;\n cursor: pointer;\n }\n\n /* Icon preview in trigger */\n .icon-preview {\n font-size: 1.1rem;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n }\n\n .icon-name {\n font-size: 0.875rem;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n color: var(--icon-picker-text);\n }\n\n .placeholder {\n font-size: 0.875rem;\n color: var(--icon-picker-placeholder-color);\n }\n\n /* Dropdown content */\n .dropdown-content {\n width: var(--icon-picker-dropdown-width);\n max-height: var(--icon-picker-dropdown-max-height);\n background: var(--icon-picker-background);\n display: flex;\n flex-direction: column;\n overflow: hidden;\n }\n\n /* Search container */\n .search-container {\n padding: 12px;\n background: var(--icon-picker-background);\n border-bottom: 1px solid var(--icon-picker-border);\n flex-shrink: 0;\n z-index: 10;\n }\n\n /* Icons grid container */\n .icons-grid-container {\n flex: 1;\n min-height: 0;\n overflow: auto;\n padding: 8px;\n background: var(--icon-picker-background);\n }\n\n /* Icon grid using lit-virtualizer */\n .icons-grid {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(var(--icon-picker-grid-gap), 1fr));\n gap: var(--icon-picker-grid-gap);\n }\n\n /* Individual icon item */\n .icon-item {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: var(--icon-picker-icon-padding);\n cursor: pointer;\n border-radius: 4px;\n border: 2px solid transparent;\n transition: all 0.2s ease;\n min-width: var(--icon-picker-icon-size);\n min-height: var(--icon-picker-icon-size);\n }\n\n .icon-item:hover {\n background-color: var(--icon-picker-hover-bg);\n }\n\n .icon-item.selected {\n background-color: var(--icon-picker-selected-bg);\n border-color: var(--icon-picker-selected-border);\n }\n\n .icon-item:focus {\n outline: 2px solid var(--icon-picker-selected-border);\n outline-offset: 2px;\n }\n\n .icon-item nr-icon {\n font-size: var(--icon-picker-icon-size);\n color: var(--icon-picker-text);\n }\n\n /* Empty state */\n .empty-state {\n padding: 40px 20px;\n text-align: center;\n color: var(--icon-picker-placeholder-color);\n }\n\n .empty-state nr-icon {\n font-size: 48px;\n margin-bottom: 12px;\n opacity: 0.5;\n }\n\n .empty-message {\n font-size: 0.875rem;\n }\n\n /* Loading state */\n .loading-state {\n padding: 40px 20px;\n text-align: center;\n color: var(--icon-picker-placeholder-color);\n }\n\n /* Disabled state */\n :host([disabled]) {\n opacity: 0.6;\n pointer-events: none;\n }\n\n /* Size variants */\n :host([size=\"small\"]) {\n --icon-picker-icon-size: 20px;\n --icon-picker-icon-padding: 6px;\n --icon-picker-dropdown-width: 280px;\n }\n\n :host([size=\"large\"]) {\n --icon-picker-icon-size: 28px;\n --icon-picker-icon-padding: 10px;\n --icon-picker-dropdown-width: 360px;\n }\n\n /* Accessibility */\n @media (prefers-reduced-motion: reduce) {\n .icon-item {\n transition: none;\n }\n }\n\n /* Scrollbar styling */\n .icons-grid-container::-webkit-scrollbar {\n width: 8px;\n }\n\n .icons-grid-container::-webkit-scrollbar-track {\n background: transparent;\n }\n\n .icons-grid-container::-webkit-scrollbar-thumb {\n background: var(--icon-picker-border);\n border-radius: 4px;\n }\n\n .icons-grid-container::-webkit-scrollbar-thumb:hover {\n background: var(--icon-picker-text);\n opacity: 0.5;\n }\n`;\n"]}
|