@liwe3/webcomponents 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.
@@ -0,0 +1,452 @@
1
+ class g extends HTMLElement {
2
+ constructor() {
3
+ super(), this.isOpen = !1, this.selectedOptions = [], this.filteredOptions = [], this.focusedIndex = -1, this.searchValue = "", this.keyboardNavigating = !1, this.attachShadow({ mode: "open" }), this.hasAttribute("tabindex") || this.setAttribute("tabindex", "0"), this.render(), this.bindEvents();
4
+ }
5
+ static get observedAttributes() {
6
+ return ["multiple", "searchable", "placeholder", "disabled", "value", "options"];
7
+ }
8
+ attributeChangedCallback(e, t, s) {
9
+ t !== s && (e === "options" && (this.filteredOptions = [...this.options]), this.render());
10
+ }
11
+ get multiple() {
12
+ return this.hasAttribute("multiple");
13
+ }
14
+ set multiple(e) {
15
+ e ? this.setAttribute("multiple", "") : this.removeAttribute("multiple");
16
+ }
17
+ get searchable() {
18
+ return this.hasAttribute("searchable");
19
+ }
20
+ set searchable(e) {
21
+ e ? this.setAttribute("searchable", "") : this.removeAttribute("searchable");
22
+ }
23
+ get placeholder() {
24
+ return this.getAttribute("placeholder") || "Select an option";
25
+ }
26
+ set placeholder(e) {
27
+ this.setAttribute("placeholder", e);
28
+ }
29
+ get disabled() {
30
+ return this.hasAttribute("disabled");
31
+ }
32
+ set disabled(e) {
33
+ e ? this.setAttribute("disabled", "") : this.removeAttribute("disabled");
34
+ }
35
+ get value() {
36
+ return this.multiple ? this.selectedOptions.map((e) => e.value) : this.selectedOptions.length > 0 ? this.selectedOptions[0].value : "";
37
+ }
38
+ set value(e) {
39
+ if (this.multiple && Array.isArray(e))
40
+ this.selectedOptions = this.options.filter((t) => e.includes(t.value));
41
+ else {
42
+ const t = this.options.find((s) => s.value === e);
43
+ this.selectedOptions = t ? [t] : [];
44
+ }
45
+ this.render();
46
+ }
47
+ get options() {
48
+ const e = this.getAttribute("options");
49
+ if (e)
50
+ try {
51
+ return JSON.parse(e);
52
+ } catch (t) {
53
+ return console.error("Invalid options format:", t), [];
54
+ }
55
+ return [];
56
+ }
57
+ set options(e) {
58
+ this.setAttribute("options", JSON.stringify(e));
59
+ }
60
+ /**
61
+ * Opens the dropdown
62
+ */
63
+ open() {
64
+ this.disabled || (this.isOpen = !0, this.focusedIndex = -1, this.options.length > 0 && (this.filteredOptions = [...this.options]), this.render(), this._updateDropdownPosition(), this.searchable && requestAnimationFrame(() => {
65
+ const e = this.shadowRoot.querySelector(".search-input");
66
+ e && e.focus();
67
+ }), this.dispatchEvent(new CustomEvent("open")));
68
+ }
69
+ /**
70
+ * Closes the dropdown
71
+ */
72
+ close() {
73
+ this.isOpen = !1, this.focusedIndex = -1, this.searchValue = "", this.searchable && this.options.length > 0 && (this.filteredOptions = [...this.options]);
74
+ const e = this.shadowRoot.querySelector(".dropdown");
75
+ e && (e.style.top = "", e.style.left = "", e.style.width = "", e.style.maxHeight = ""), this.render(), this.dispatchEvent(new CustomEvent("close"));
76
+ }
77
+ /**
78
+ * Toggles the dropdown open/closed state
79
+ */
80
+ toggle() {
81
+ this.isOpen ? this.close() : this.open();
82
+ }
83
+ /**
84
+ * Selects an option by its value
85
+ */
86
+ selectOption(e) {
87
+ const t = this.options.find((s) => s.value === e);
88
+ t && (this.multiple ? this.selectedOptions.find((s) => s.value === e) || this.selectedOptions.push(t) : (this.selectedOptions = [t], this.close()), this.render(), this.dispatchEvent(new CustomEvent("change", { detail: { value: this.value } })));
89
+ }
90
+ /**
91
+ * Deselects an option by its value
92
+ */
93
+ deselectOption(e) {
94
+ this.selectedOptions = this.selectedOptions.filter((t) => t.value !== e), this.render(), this.dispatchEvent(new CustomEvent("change", { detail: { value: this.value } }));
95
+ }
96
+ /**
97
+ * Returns an array of currently selected options
98
+ */
99
+ getSelectedOptions() {
100
+ return [...this.selectedOptions];
101
+ }
102
+ /**
103
+ * Sets the options for the select component
104
+ */
105
+ setOptions(e) {
106
+ this.options = e, this.filteredOptions = [...e], this.selectedOptions = [], this.render();
107
+ }
108
+ /**
109
+ * Handles search functionality
110
+ */
111
+ handleSearch(e) {
112
+ this.searchValue = e, this.filteredOptions = this.options.filter(
113
+ (t) => t.label.toLowerCase().includes(e.toLowerCase())
114
+ ), this.focusedIndex = -1, this.render(), this.dispatchEvent(new CustomEvent("search", { detail: { query: e } }));
115
+ }
116
+ /**
117
+ * Updates the visual focus state without full re-render
118
+ */
119
+ updateFocusedOption() {
120
+ const e = this.shadowRoot.querySelectorAll(".option");
121
+ e.forEach((t) => t.classList.remove("focused")), this.focusedIndex >= 0 && this.focusedIndex < e.length && e[this.focusedIndex].classList.add("focused"), this.scrollToFocusedOption();
122
+ }
123
+ /**
124
+ * Scrolls the focused option into view
125
+ */
126
+ scrollToFocusedOption() {
127
+ this.focusedIndex < 0 || requestAnimationFrame(() => {
128
+ const e = this.shadowRoot.querySelector(".dropdown"), t = this.shadowRoot.querySelector(".option.focused");
129
+ if (e && t) {
130
+ const s = e.getBoundingClientRect(), o = t.getBoundingClientRect();
131
+ o.top < s.top ? e.scrollTop -= s.top - o.top : o.bottom > s.bottom && (e.scrollTop += o.bottom - s.bottom);
132
+ }
133
+ });
134
+ }
135
+ /**
136
+ * Calculates the optimal dropdown position based on viewport constraints
137
+ */
138
+ _calculateDropdownPosition() {
139
+ const e = this.shadowRoot.querySelector(".select-trigger");
140
+ if (!e) return null;
141
+ const t = e.getBoundingClientRect(), s = window.innerHeight, o = window.innerWidth, i = 200, n = 10, r = 2, l = s - t.bottom, h = t.top, u = l < i + n && h > l, p = t.width, f = Math.max(0, Math.min(t.left, o - p));
142
+ let c, a;
143
+ return u ? (a = Math.min(i, h - n), c = t.top - a - r) : (a = Math.min(i, l - n), c = t.bottom + r), {
144
+ top: Math.max(0, c),
145
+ left: f,
146
+ width: p,
147
+ maxHeight: Math.max(100, a)
148
+ // Ensure minimum height
149
+ };
150
+ }
151
+ /**
152
+ * Updates dropdown position using fixed positioning relative to viewport
153
+ */
154
+ _updateDropdownPosition() {
155
+ requestAnimationFrame(() => {
156
+ const e = this.shadowRoot.querySelector(".dropdown");
157
+ if (!e) return;
158
+ const t = this._calculateDropdownPosition();
159
+ t && (e.style.top = `${t.top}px`, e.style.left = `${t.left}px`, e.style.width = `${t.width}px`, e.style.maxHeight = `${t.maxHeight}px`);
160
+ });
161
+ }
162
+ /**
163
+ * Handles keyboard navigation
164
+ */
165
+ handleKeydown(e) {
166
+ if (!this.disabled && !e._smartSelectHandled)
167
+ switch (e._smartSelectHandled = !0, e.key) {
168
+ case "ArrowDown":
169
+ if (e.preventDefault(), this.keyboardNavigating = !0, clearTimeout(this.keyboardTimer), this.keyboardTimer = window.setTimeout(() => {
170
+ this.keyboardNavigating = !1;
171
+ }, 100), !this.isOpen)
172
+ this.open();
173
+ else {
174
+ const t = this.shadowRoot.querySelector(".search-input");
175
+ if (this.searchable && t === this.shadowRoot.activeElement) {
176
+ this.focusedIndex = 0, t.blur(), this.focus(), this.updateFocusedOption();
177
+ return;
178
+ }
179
+ const o = Math.min(this.focusedIndex + 1, this.filteredOptions.length - 1);
180
+ this.focusedIndex = o, this.updateFocusedOption();
181
+ }
182
+ break;
183
+ case "ArrowUp":
184
+ if (e.preventDefault(), this.keyboardNavigating = !0, clearTimeout(this.keyboardTimer), this.keyboardTimer = window.setTimeout(() => {
185
+ this.keyboardNavigating = !1;
186
+ }, 100), this.isOpen) {
187
+ if (this.focusedIndex === 0 && this.searchable) {
188
+ this.focusedIndex = -1, this.updateFocusedOption(), requestAnimationFrame(() => {
189
+ const i = this.shadowRoot.querySelector(".search-input");
190
+ i && (i.focus(), i.setSelectionRange(i.value.length, i.value.length));
191
+ });
192
+ return;
193
+ }
194
+ const t = this.shadowRoot.querySelector(".search-input");
195
+ if (this.searchable && t === this.shadowRoot.activeElement)
196
+ return;
197
+ const o = Math.max(this.focusedIndex - 1, -1);
198
+ this.focusedIndex = o, this.updateFocusedOption();
199
+ }
200
+ break;
201
+ case "Enter":
202
+ e.preventDefault(), this.isOpen && this.focusedIndex >= 0 && this.focusedIndex < this.filteredOptions.length ? this.selectOption(this.filteredOptions[this.focusedIndex].value) : this.isOpen || this.open();
203
+ break;
204
+ case "Escape":
205
+ e.preventDefault(), this.close();
206
+ break;
207
+ case "Tab":
208
+ this.close();
209
+ break;
210
+ }
211
+ }
212
+ /**
213
+ * Binds all event listeners
214
+ */
215
+ bindEvents() {
216
+ const e = this.handleKeydown.bind(this);
217
+ this.addEventListener("keydown", e), this.shadowRoot.addEventListener("keydown", e), this.shadowRoot.addEventListener("click", (t) => {
218
+ t.stopPropagation();
219
+ const s = t.target;
220
+ if (s.closest(".remove-tag")) {
221
+ const o = s.closest(".remove-tag").dataset.value;
222
+ o && this.deselectOption(o);
223
+ } else if (s.closest(".option")) {
224
+ const o = s.closest(".option").dataset.value;
225
+ o && this.selectOption(o);
226
+ } else s.closest(".select-trigger") && this.toggle();
227
+ }), this.shadowRoot.addEventListener("mouseover", (t) => {
228
+ if (this.keyboardNavigating) return;
229
+ const s = t.target;
230
+ if (s.closest(".option")) {
231
+ const o = s.closest(".option"), n = Array.from(this.shadowRoot.querySelectorAll(".option")).indexOf(o);
232
+ if (this.focusedIndex !== n) {
233
+ const r = this.shadowRoot.querySelector(".option.focused");
234
+ r && r.classList.remove("focused"), o.classList.add("focused"), this.focusedIndex = n;
235
+ }
236
+ }
237
+ }), this.shadowRoot.addEventListener("mouseleave", (t) => {
238
+ if (this.keyboardNavigating) return;
239
+ if (t.target.closest(".dropdown")) {
240
+ const o = this.shadowRoot.querySelector(".option.focused");
241
+ o && o.classList.remove("focused"), this.focusedIndex = -1;
242
+ }
243
+ }), this.shadowRoot.addEventListener("input", (t) => {
244
+ const s = t.target;
245
+ s.classList.contains("search-input") && this.handleSearch(s.value);
246
+ }), document.addEventListener("click", (t) => {
247
+ this.contains(t.target) || this.close();
248
+ }), window.addEventListener("resize", () => {
249
+ this.isOpen && this._updateDropdownPosition();
250
+ }), window.addEventListener("scroll", () => {
251
+ this.isOpen && this._updateDropdownPosition();
252
+ }, !0);
253
+ }
254
+ /**
255
+ * Renders the component
256
+ */
257
+ render() {
258
+ this.filteredOptions.length === 0 && this.options.length > 0 && (this.filteredOptions = [...this.options]);
259
+ const e = this.shadowRoot.querySelector(".search-input") === this.shadowRoot.activeElement, t = this.selectedOptions.length > 0 ? this.multiple ? `${this.selectedOptions.length} selected` : this.selectedOptions[0].label : this.placeholder;
260
+ this.shadowRoot.innerHTML = `
261
+ <style>
262
+ :host {
263
+ display: inline-block;
264
+ position: relative;
265
+ min-width: 200px;
266
+ font-family: var(--font-family, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif);
267
+ font-size: var(--font-size, 14px);
268
+ outline: none;
269
+ }
270
+
271
+ :host(:focus) .select-trigger {
272
+ border-color: var(--focus-color, #007bff);
273
+ box-shadow: 0 0 0 2px rgba(0, 123, 255, 0.25);
274
+ }
275
+
276
+ :host([disabled]) {
277
+ opacity: 0.6;
278
+ cursor: not-allowed;
279
+ }
280
+
281
+ .select-container {
282
+ position: relative;
283
+ }
284
+
285
+ .select-trigger {
286
+ display: flex;
287
+ align-items: center;
288
+ justify-content: space-between;
289
+ padding: var(--padding, 8px 12px);
290
+ border: var(--border, 1px solid #ccc);
291
+ border-radius: var(--border-radius, 4px);
292
+ background: var(--background, white);
293
+ cursor: pointer;
294
+ min-height: 36px;
295
+ box-sizing: border-box;
296
+ color: #333;
297
+ }
298
+
299
+ .select-trigger:focus {
300
+ outline: none;
301
+ border-color: var(--focus-color, #007bff);
302
+ box-shadow: 0 0 0 2px rgba(0, 123, 255, 0.25);
303
+ }
304
+
305
+ .select-trigger[disabled] {
306
+ cursor: not-allowed;
307
+ }
308
+
309
+ .selected-content {
310
+ display: flex;
311
+ align-items: center;
312
+ gap: 4px;
313
+ flex-wrap: wrap;
314
+ flex: 1;
315
+ }
316
+
317
+ .tag {
318
+ display: inline-flex;
319
+ align-items: center;
320
+ gap: 4px;
321
+ padding: 2px 8px;
322
+ background: var(--tag-background, #e9ecef);
323
+ border-radius: var(--tag-border-radius, 12px);
324
+ font-size: 12px;
325
+ color: var(--tag-color, #495057);
326
+ }
327
+
328
+ .remove-tag {
329
+ cursor: pointer;
330
+ color: var(--remove-color, #6c757d);
331
+ font-weight: bold;
332
+ font-size: 14px;
333
+ }
334
+
335
+ .remove-tag:hover {
336
+ color: var(--remove-hover-color, #dc3545);
337
+ }
338
+
339
+ .arrow {
340
+ width: 0;
341
+ height: 0;
342
+ border-left: 5px solid transparent;
343
+ border-right: 5px solid transparent;
344
+ border-top: 5px solid var(--arrow-color, #666);
345
+ transition: transform 0.2s;
346
+ }
347
+
348
+ .arrow.open {
349
+ transform: rotate(180deg);
350
+ }
351
+
352
+ .dropdown {
353
+ position: fixed;
354
+ z-index: 99999;
355
+ background: var(--dropdown-background, white);
356
+ border: var(--dropdown-border, 1px solid #ccc);
357
+ border-radius: var(--dropdown-border-radius, 4px);
358
+ box-shadow: var(--dropdown-shadow, 0 2px 8px rgba(0, 0, 0, 0.1));
359
+ max-height: 200px;
360
+ overflow-y: auto;
361
+ scroll-behavior: smooth;
362
+ color: #333;
363
+ }
364
+
365
+ .search-input {
366
+ width: 100%;
367
+ padding: 8px 12px;
368
+ border: none;
369
+ border-bottom: 1px solid #eee;
370
+ font-size: 14px;
371
+ outline: none;
372
+ box-sizing: border-box;
373
+ }
374
+
375
+ .option {
376
+ padding: 8px 12px;
377
+ cursor: pointer;
378
+ color: var(--option-color, #333);
379
+ transition: background-color 0.2s;
380
+ }
381
+
382
+ .option:hover {
383
+ background-color: var(--option-hover-background, #f8f9fa);
384
+ }
385
+
386
+ .option.focused {
387
+ background-color: var(--option-focused-background, #007bff);
388
+ color: var(--option-focused-color, white);
389
+ }
390
+
391
+ .option.selected {
392
+ background-color: var(--option-selected-background, #e3f2fd);
393
+ color: var(--option-selected-color, #1976d2);
394
+ }
395
+
396
+ .no-options {
397
+ padding: 8px 12px;
398
+ color: var(--no-options-color, #6c757d);
399
+ font-style: italic;
400
+ }
401
+ </style>
402
+
403
+ <div class="select-container">
404
+ <div class="select-trigger" tabindex="-1">
405
+ <div class="selected-content">
406
+ ${this.multiple && this.selectedOptions.length > 0 ? this.selectedOptions.map((s) => `
407
+ <span class="tag">
408
+ ${s.label}
409
+ <span class="remove-tag" data-value="${s.value}">×</span>
410
+ </span>
411
+ `).join("") : `<span>${t}</span>`}
412
+ </div>
413
+ <div class="arrow ${this.isOpen ? "open" : ""}"></div>
414
+ </div>
415
+
416
+ ${this.isOpen ? `
417
+ <div class="dropdown">
418
+ ${this.searchable ? `
419
+ <input
420
+ type="text"
421
+ class="search-input"
422
+ placeholder="Search options..."
423
+ value="${this.searchValue}"
424
+ >
425
+ ` : ""}
426
+
427
+ ${this.filteredOptions.length > 0 ? this.filteredOptions.map((s, o) => `
428
+ <div
429
+ class="option ${this.selectedOptions.find((i) => i.value === s.value) ? "selected" : ""} ${o === this.focusedIndex ? "focused" : ""}"
430
+ data-value="${s.value}"
431
+ >
432
+ ${s.label}
433
+ </div>
434
+ `).join("") : '<div class="no-options">No options available</div>'}
435
+ </div>
436
+ ` : ""}
437
+ </div>
438
+ `, e && this.searchable && this.isOpen && requestAnimationFrame(() => {
439
+ const s = this.shadowRoot.querySelector(".search-input");
440
+ s && (s.focus(), s.setSelectionRange(s.value.length, s.value.length));
441
+ });
442
+ }
443
+ }
444
+ const b = (d = "liwe3-select") => {
445
+ typeof window < "u" && !window.customElements.get(d) && customElements.define(d, g);
446
+ };
447
+ b();
448
+ export {
449
+ g as SmartSelectElement,
450
+ b as defineSmartSelect
451
+ };
452
+ //# sourceMappingURL=SmartSelect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SmartSelect.js","sources":["../src/SmartSelect.ts"],"sourcesContent":["/**\n * SmartSelect Web Component\n * A customizable select dropdown with search, multi-select, and keyboard navigation\n */\n\nexport interface SelectOption {\n value: string;\n label: string;\n}\n\nexport class SmartSelectElement extends HTMLElement {\n declare shadowRoot: ShadowRoot;\n private isOpen: boolean = false;\n private selectedOptions: SelectOption[] = [];\n private filteredOptions: SelectOption[] = [];\n private focusedIndex: number = -1;\n private searchValue: string = '';\n private keyboardNavigating: boolean = false;\n private keyboardTimer?: number;\n\n constructor() {\n super();\n this.attachShadow({ mode: 'open' });\n\n // Make component focusable\n if (!this.hasAttribute('tabindex')) {\n this.setAttribute('tabindex', '0');\n }\n\n this.render();\n this.bindEvents();\n }\n\n static get observedAttributes(): string[] {\n return ['multiple', 'searchable', 'placeholder', 'disabled', 'value', 'options'];\n }\n\n attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void {\n if (oldValue !== newValue) {\n if (name === 'options') {\n this.filteredOptions = [...this.options];\n }\n this.render();\n }\n }\n\n get multiple(): boolean {\n return this.hasAttribute('multiple');\n }\n\n set multiple(value: boolean) {\n if (value) {\n this.setAttribute('multiple', '');\n } else {\n this.removeAttribute('multiple');\n }\n }\n\n get searchable(): boolean {\n return this.hasAttribute('searchable');\n }\n\n set searchable(value: boolean) {\n if (value) {\n this.setAttribute('searchable', '');\n } else {\n this.removeAttribute('searchable');\n }\n }\n\n get placeholder(): string {\n return this.getAttribute('placeholder') || 'Select an option';\n }\n\n set placeholder(value: string) {\n this.setAttribute('placeholder', value);\n }\n\n get disabled(): boolean {\n return this.hasAttribute('disabled');\n }\n\n set disabled(value: boolean) {\n if (value) {\n this.setAttribute('disabled', '');\n } else {\n this.removeAttribute('disabled');\n }\n }\n\n get value(): string | string[] {\n if (this.multiple) {\n return this.selectedOptions.map(opt => opt.value);\n }\n return this.selectedOptions.length > 0 ? this.selectedOptions[0].value : '';\n }\n\n set value(val: string | string[]) {\n if (this.multiple && Array.isArray(val)) {\n this.selectedOptions = this.options.filter(opt => val.includes(opt.value));\n } else {\n const option = this.options.find(opt => opt.value === val);\n this.selectedOptions = option ? [option] : [];\n }\n this.render();\n }\n\n get options(): SelectOption[] {\n const optionsAttr = this.getAttribute('options');\n if (optionsAttr) {\n try {\n return JSON.parse(optionsAttr);\n } catch (e) {\n console.error('Invalid options format:', e);\n return [];\n }\n }\n return [];\n }\n\n set options(opts: SelectOption[]) {\n this.setAttribute('options', JSON.stringify(opts));\n }\n\n /**\n * Opens the dropdown\n */\n open(): void {\n if (this.disabled) return;\n this.isOpen = true;\n this.focusedIndex = -1;\n if (this.options.length > 0) {\n this.filteredOptions = [...this.options];\n }\n this.render();\n\n // Update dropdown position based on viewport\n this._updateDropdownPosition();\n\n // Focus search input if searchable\n if (this.searchable) {\n requestAnimationFrame(() => {\n const searchInput = this.shadowRoot.querySelector('.search-input') as HTMLInputElement;\n if (searchInput) {\n searchInput.focus();\n }\n });\n }\n\n this.dispatchEvent(new CustomEvent('open'));\n }\n\n /**\n * Closes the dropdown\n */\n close(): void {\n this.isOpen = false;\n this.focusedIndex = -1;\n this.searchValue = '';\n\n // Reset filtered options when closing\n if (this.searchable && this.options.length > 0) {\n this.filteredOptions = [...this.options];\n }\n\n // Clear any inline positioning styles\n const dropdown = this.shadowRoot.querySelector('.dropdown') as HTMLElement;\n if (dropdown) {\n dropdown.style.top = '';\n dropdown.style.left = '';\n dropdown.style.width = '';\n dropdown.style.maxHeight = '';\n }\n\n this.render();\n this.dispatchEvent(new CustomEvent('close'));\n }\n\n /**\n * Toggles the dropdown open/closed state\n */\n toggle(): void {\n if (this.isOpen) {\n this.close();\n } else {\n this.open();\n }\n }\n\n /**\n * Selects an option by its value\n */\n selectOption(value: string): void {\n const option = this.options.find(opt => opt.value === value);\n if (!option) return;\n\n if (this.multiple) {\n if (!this.selectedOptions.find(opt => opt.value === value)) {\n this.selectedOptions.push(option);\n }\n } else {\n this.selectedOptions = [option];\n this.close();\n }\n\n this.render();\n this.dispatchEvent(new CustomEvent('change', { detail: { value: this.value } }));\n }\n\n /**\n * Deselects an option by its value\n */\n deselectOption(value: string): void {\n this.selectedOptions = this.selectedOptions.filter(opt => opt.value !== value);\n this.render();\n this.dispatchEvent(new CustomEvent('change', { detail: { value: this.value } }));\n }\n\n /**\n * Returns an array of currently selected options\n */\n getSelectedOptions(): SelectOption[] {\n return [...this.selectedOptions];\n }\n\n /**\n * Sets the options for the select component\n */\n setOptions(options: SelectOption[]): void {\n this.options = options;\n this.filteredOptions = [...options];\n this.selectedOptions = [];\n this.render();\n }\n\n /**\n * Handles search functionality\n */\n private handleSearch(query: string): void {\n this.searchValue = query;\n this.filteredOptions = this.options.filter(option =>\n option.label.toLowerCase().includes(query.toLowerCase())\n );\n this.focusedIndex = -1;\n this.render();\n this.dispatchEvent(new CustomEvent('search', { detail: { query } }));\n }\n\n /**\n * Updates the visual focus state without full re-render\n */\n private updateFocusedOption(): void {\n const options = this.shadowRoot.querySelectorAll('.option');\n\n // Remove focused class from all options\n options.forEach(option => option.classList.remove('focused'));\n\n // Add focused class to current option\n if (this.focusedIndex >= 0 && this.focusedIndex < options.length) {\n options[this.focusedIndex].classList.add('focused');\n }\n\n this.scrollToFocusedOption();\n }\n\n /**\n * Scrolls the focused option into view\n */\n private scrollToFocusedOption(): void {\n if (this.focusedIndex < 0) return;\n\n requestAnimationFrame(() => {\n const dropdown = this.shadowRoot.querySelector('.dropdown') as HTMLElement;\n const focusedOption = this.shadowRoot.querySelector('.option.focused') as HTMLElement;\n\n if (dropdown && focusedOption) {\n const dropdownRect = dropdown.getBoundingClientRect();\n const optionRect = focusedOption.getBoundingClientRect();\n\n // Check if option is above visible area\n if (optionRect.top < dropdownRect.top) {\n dropdown.scrollTop -= (dropdownRect.top - optionRect.top);\n }\n // Check if option is below visible area\n else if (optionRect.bottom > dropdownRect.bottom) {\n dropdown.scrollTop += (optionRect.bottom - dropdownRect.bottom);\n }\n }\n });\n }\n\n /**\n * Calculates the optimal dropdown position based on viewport constraints\n */\n private _calculateDropdownPosition(): { top: number; left: number; width: number; maxHeight: number } | null {\n const trigger = this.shadowRoot.querySelector('.select-trigger') as HTMLElement;\n if (!trigger) return null;\n\n const triggerRect = trigger.getBoundingClientRect();\n const viewportHeight = window.innerHeight;\n const viewportWidth = window.innerWidth;\n const dropdownMaxHeight = 200;\n const dropdownPadding = 10;\n const margin = 2;\n\n // Calculate available space\n const spaceBelow = viewportHeight - triggerRect.bottom;\n const spaceAbove = triggerRect.top;\n\n // Determine if dropdown should open upward\n const shouldOpenUpward = spaceBelow < dropdownMaxHeight + dropdownPadding && spaceAbove > spaceBelow;\n\n // Calculate dimensions\n const width = triggerRect.width;\n const left = Math.max(0, Math.min(triggerRect.left, viewportWidth - width));\n\n let top: number;\n let maxHeight: number;\n\n if (shouldOpenUpward) {\n // Position above the trigger\n maxHeight = Math.min(dropdownMaxHeight, spaceAbove - dropdownPadding);\n top = triggerRect.top - maxHeight - margin;\n } else {\n // Position below the trigger\n maxHeight = Math.min(dropdownMaxHeight, spaceBelow - dropdownPadding);\n top = triggerRect.bottom + margin;\n }\n\n return {\n top: Math.max(0, top),\n left,\n width,\n maxHeight: Math.max(100, maxHeight) // Ensure minimum height\n };\n }\n\n /**\n * Updates dropdown position using fixed positioning relative to viewport\n */\n private _updateDropdownPosition(): void {\n requestAnimationFrame(() => {\n const dropdown = this.shadowRoot.querySelector('.dropdown') as HTMLElement;\n if (!dropdown) return;\n\n const position = this._calculateDropdownPosition();\n if (!position) return;\n\n // Apply calculated position as inline styles\n dropdown.style.top = `${position.top}px`;\n dropdown.style.left = `${position.left}px`;\n dropdown.style.width = `${position.width}px`;\n dropdown.style.maxHeight = `${position.maxHeight}px`;\n });\n }\n\n /**\n * Handles keyboard navigation\n */\n private handleKeydown(event: KeyboardEvent): void {\n if (this.disabled) return;\n\n // Prevent double execution if event has already been handled\n if ((event as any)._smartSelectHandled) return;\n (event as any)._smartSelectHandled = true;\n\n switch (event.key) {\n case 'ArrowDown':\n event.preventDefault();\n this.keyboardNavigating = true;\n clearTimeout(this.keyboardTimer);\n this.keyboardTimer = window.setTimeout(() => { this.keyboardNavigating = false; }, 100);\n\n if (!this.isOpen) {\n this.open();\n } else {\n // If searchable and search input is focused, move to first option\n const searchInput = this.shadowRoot.querySelector('.search-input') as HTMLInputElement;\n const isSearchFocused = this.searchable && searchInput === this.shadowRoot.activeElement;\n\n if (isSearchFocused) {\n this.focusedIndex = 0;\n searchInput.blur(); // Blur search input to allow normal navigation\n // Focus the component to ensure it receives keyboard events\n this.focus();\n this.updateFocusedOption();\n return;\n }\n // Navigate through options\n const newIndex = Math.min(this.focusedIndex + 1, this.filteredOptions.length - 1);\n this.focusedIndex = newIndex;\n this.updateFocusedOption();\n }\n break;\n\n case 'ArrowUp':\n event.preventDefault();\n this.keyboardNavigating = true;\n clearTimeout(this.keyboardTimer);\n this.keyboardTimer = window.setTimeout(() => { this.keyboardNavigating = false; }, 100);\n\n if (this.isOpen) {\n // If at first option and searchable, focus search input\n if (this.focusedIndex === 0 && this.searchable) {\n this.focusedIndex = -1;\n this.updateFocusedOption();\n requestAnimationFrame(() => {\n const searchInput = this.shadowRoot.querySelector('.search-input') as HTMLInputElement;\n if (searchInput) {\n searchInput.focus();\n searchInput.setSelectionRange(searchInput.value.length, searchInput.value.length);\n }\n });\n return;\n }\n // If searchable and search input is focused, do nothing\n const searchInput = this.shadowRoot.querySelector('.search-input') as HTMLInputElement;\n const isSearchFocused = this.searchable && searchInput === this.shadowRoot.activeElement;\n\n if (isSearchFocused) {\n return;\n }\n // Navigate through options\n const newIndex = Math.max(this.focusedIndex - 1, -1);\n this.focusedIndex = newIndex;\n this.updateFocusedOption();\n }\n break;\n\n case 'Enter':\n event.preventDefault();\n if (this.isOpen && this.focusedIndex >= 0 && this.focusedIndex < this.filteredOptions.length) {\n this.selectOption(this.filteredOptions[this.focusedIndex].value);\n } else if (!this.isOpen) {\n this.open();\n }\n break;\n\n case 'Escape':\n event.preventDefault();\n this.close();\n break;\n\n case 'Tab':\n this.close();\n break;\n }\n }\n\n /**\n * Binds all event listeners\n */\n private bindEvents(): void {\n // Listen for keydown events on both the component and shadow root\n const keydownHandler = this.handleKeydown.bind(this);\n this.addEventListener('keydown', keydownHandler);\n this.shadowRoot.addEventListener('keydown', keydownHandler as EventListener);\n\n // Use event delegation on the shadow root\n this.shadowRoot.addEventListener('click', (e) => {\n e.stopPropagation();\n const target = e.target as HTMLElement;\n\n if (target.closest('.remove-tag')) {\n const value = (target.closest('.remove-tag') as HTMLElement).dataset.value;\n if (value) this.deselectOption(value);\n } else if (target.closest('.option')) {\n const value = (target.closest('.option') as HTMLElement).dataset.value;\n if (value) this.selectOption(value);\n } else if (target.closest('.select-trigger')) {\n this.toggle();\n }\n });\n\n // Handle mouse hover on options to update focused index\n this.shadowRoot.addEventListener('mouseover', (e) => {\n // Don't interfere with keyboard navigation\n if (this.keyboardNavigating) return;\n\n const target = e.target as HTMLElement;\n if (target.closest('.option')) {\n const option = target.closest('.option') as HTMLElement;\n const options = Array.from(this.shadowRoot.querySelectorAll('.option'));\n const newFocusedIndex = options.indexOf(option);\n\n // Only update if the focused index actually changed\n if (this.focusedIndex !== newFocusedIndex) {\n // Remove focused class from current option\n const currentFocused = this.shadowRoot.querySelector('.option.focused');\n if (currentFocused) {\n currentFocused.classList.remove('focused');\n }\n\n // Add focused class to new option\n option.classList.add('focused');\n this.focusedIndex = newFocusedIndex;\n }\n }\n });\n\n // Handle mouse leaving dropdown to clear focus\n this.shadowRoot.addEventListener('mouseleave', (e) => {\n // Don't interfere with keyboard navigation\n if (this.keyboardNavigating) return;\n\n const target = e.target as HTMLElement;\n if (target.closest('.dropdown')) {\n const currentFocused = this.shadowRoot.querySelector('.option.focused');\n if (currentFocused) {\n currentFocused.classList.remove('focused');\n }\n this.focusedIndex = -1;\n }\n });\n\n // Handle search input\n this.shadowRoot.addEventListener('input', (e) => {\n const target = e.target as HTMLInputElement;\n if (target.classList.contains('search-input')) {\n this.handleSearch(target.value);\n }\n });\n\n // Close dropdown when clicking outside\n document.addEventListener('click', (e) => {\n if (!this.contains(e.target as Node)) {\n this.close();\n }\n });\n\n // Update dropdown position on window resize or scroll\n window.addEventListener('resize', () => {\n if (this.isOpen) {\n this._updateDropdownPosition();\n }\n });\n\n window.addEventListener('scroll', () => {\n if (this.isOpen) {\n this._updateDropdownPosition();\n }\n }, true); // Use capture to catch all scroll events\n }\n\n /**\n * Renders the component\n */\n private render(): void {\n // Initialize filteredOptions if not set\n if (this.filteredOptions.length === 0 && this.options.length > 0) {\n this.filteredOptions = [...this.options];\n }\n\n // Remember if search input was focused before render\n const wasSearchFocused = this.shadowRoot.querySelector('.search-input') === this.shadowRoot.activeElement;\n\n const displayText = this.selectedOptions.length > 0\n ? (this.multiple\n ? `${this.selectedOptions.length} selected`\n : this.selectedOptions[0].label)\n : this.placeholder;\n\n this.shadowRoot.innerHTML = `\n <style>\n :host {\n display: inline-block;\n position: relative;\n min-width: 200px;\n font-family: var(--font-family, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif);\n font-size: var(--font-size, 14px);\n outline: none;\n }\n\n :host(:focus) .select-trigger {\n border-color: var(--focus-color, #007bff);\n box-shadow: 0 0 0 2px rgba(0, 123, 255, 0.25);\n }\n\n :host([disabled]) {\n opacity: 0.6;\n cursor: not-allowed;\n }\n\n .select-container {\n position: relative;\n }\n\n .select-trigger {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: var(--padding, 8px 12px);\n border: var(--border, 1px solid #ccc);\n border-radius: var(--border-radius, 4px);\n background: var(--background, white);\n cursor: pointer;\n min-height: 36px;\n box-sizing: border-box;\n color: #333;\n }\n\n .select-trigger:focus {\n outline: none;\n border-color: var(--focus-color, #007bff);\n box-shadow: 0 0 0 2px rgba(0, 123, 255, 0.25);\n }\n\n .select-trigger[disabled] {\n cursor: not-allowed;\n }\n\n .selected-content {\n display: flex;\n align-items: center;\n gap: 4px;\n flex-wrap: wrap;\n flex: 1;\n }\n\n .tag {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 2px 8px;\n background: var(--tag-background, #e9ecef);\n border-radius: var(--tag-border-radius, 12px);\n font-size: 12px;\n color: var(--tag-color, #495057);\n }\n\n .remove-tag {\n cursor: pointer;\n color: var(--remove-color, #6c757d);\n font-weight: bold;\n font-size: 14px;\n }\n\n .remove-tag:hover {\n color: var(--remove-hover-color, #dc3545);\n }\n\n .arrow {\n width: 0;\n height: 0;\n border-left: 5px solid transparent;\n border-right: 5px solid transparent;\n border-top: 5px solid var(--arrow-color, #666);\n transition: transform 0.2s;\n }\n\n .arrow.open {\n transform: rotate(180deg);\n }\n\n .dropdown {\n position: fixed;\n z-index: 99999;\n background: var(--dropdown-background, white);\n border: var(--dropdown-border, 1px solid #ccc);\n border-radius: var(--dropdown-border-radius, 4px);\n box-shadow: var(--dropdown-shadow, 0 2px 8px rgba(0, 0, 0, 0.1));\n max-height: 200px;\n overflow-y: auto;\n scroll-behavior: smooth;\n color: #333;\n }\n\n .search-input {\n width: 100%;\n padding: 8px 12px;\n border: none;\n border-bottom: 1px solid #eee;\n font-size: 14px;\n outline: none;\n box-sizing: border-box;\n }\n\n .option {\n padding: 8px 12px;\n cursor: pointer;\n color: var(--option-color, #333);\n transition: background-color 0.2s;\n }\n\n .option:hover {\n background-color: var(--option-hover-background, #f8f9fa);\n }\n\n .option.focused {\n background-color: var(--option-focused-background, #007bff);\n color: var(--option-focused-color, white);\n }\n\n .option.selected {\n background-color: var(--option-selected-background, #e3f2fd);\n color: var(--option-selected-color, #1976d2);\n }\n\n .no-options {\n padding: 8px 12px;\n color: var(--no-options-color, #6c757d);\n font-style: italic;\n }\n </style>\n\n <div class=\"select-container\">\n <div class=\"select-trigger\" tabindex=\"-1\">\n <div class=\"selected-content\">\n ${this.multiple && this.selectedOptions.length > 0\n ? this.selectedOptions.map(option => `\n <span class=\"tag\">\n ${option.label}\n <span class=\"remove-tag\" data-value=\"${option.value}\">×</span>\n </span>\n `).join('')\n : `<span>${displayText}</span>`\n }\n </div>\n <div class=\"arrow ${this.isOpen ? 'open' : ''}\"></div>\n </div>\n\n ${this.isOpen ? `\n <div class=\"dropdown\">\n ${this.searchable ? `\n <input\n type=\"text\"\n class=\"search-input\"\n placeholder=\"Search options...\"\n value=\"${this.searchValue}\"\n >\n ` : ''}\n\n ${this.filteredOptions.length > 0\n ? this.filteredOptions.map((option, index) => `\n <div\n class=\"option ${this.selectedOptions.find(selected => selected.value === option.value) ? 'selected' : ''} ${index === this.focusedIndex ? 'focused' : ''}\"\n data-value=\"${option.value}\"\n >\n ${option.label}\n </div>\n `).join('')\n : '<div class=\"no-options\">No options available</div>'\n }\n </div>\n ` : ''}\n </div>\n `;\n\n // Re-focus search input if it was previously focused\n if (wasSearchFocused && this.searchable && this.isOpen) {\n requestAnimationFrame(() => {\n const searchInput = this.shadowRoot.querySelector('.search-input') as HTMLInputElement;\n if (searchInput) {\n searchInput.focus();\n // Restore cursor position to the end\n searchInput.setSelectionRange(searchInput.value.length, searchInput.value.length);\n }\n });\n }\n }\n}\n\n/**\n * Conditionally defines the custom element if in a browser environment.\n */\nconst defineSmartSelect = (tagName: string = 'liwe3-select'): void => {\n if (typeof window !== 'undefined' && !window.customElements.get(tagName)) {\n customElements.define(tagName, SmartSelectElement);\n }\n};\n\n// Auto-register with default tag name\ndefineSmartSelect();\n\nexport { defineSmartSelect };\n"],"names":["SmartSelectElement","name","oldValue","newValue","value","opt","val","option","optionsAttr","e","opts","searchInput","dropdown","options","query","focusedOption","dropdownRect","optionRect","trigger","triggerRect","viewportHeight","viewportWidth","dropdownMaxHeight","dropdownPadding","margin","spaceBelow","spaceAbove","shouldOpenUpward","width","left","top","maxHeight","position","event","newIndex","keydownHandler","target","newFocusedIndex","currentFocused","wasSearchFocused","displayText","index","selected","defineSmartSelect","tagName"],"mappings":"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"}
package/dist/index.js ADDED
@@ -0,0 +1,13 @@
1
+ import { SmartSelectElement as i, defineSmartSelect as r } from "./SmartSelect.js";
2
+ import { AITextEditorElement as f, defineAITextEditor as m } from "./AITextEditor.js";
3
+ const t = () => {
4
+ typeof window < "u" && (import("./SmartSelect.js").then(({ defineSmartSelect: e }) => e()), import("./AITextEditor.js").then(({ defineAITextEditor: e }) => e()));
5
+ };
6
+ export {
7
+ f as AITextEditorElement,
8
+ i as SmartSelectElement,
9
+ m as defineAITextEditor,
10
+ t as defineAllComponents,
11
+ r as defineSmartSelect
12
+ };
13
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":["../src/index.ts"],"sourcesContent":["/**\n * @liwe3/webcomponents\n * A collection of reusable web components\n */\n\n// Export SmartSelect\nexport {\n SmartSelectElement,\n defineSmartSelect,\n type SelectOption\n} from './SmartSelect';\n\n// Export AITextEditor\nexport {\n AITextEditorElement,\n defineAITextEditor,\n type AITextEditorConfig\n} from './AITextEditor';\n\n// Convenience function to register all components at once\nexport const defineAllComponents = (): void => {\n if (typeof window !== 'undefined') {\n import('./SmartSelect').then(({ defineSmartSelect }) => defineSmartSelect());\n import('./AITextEditor').then(({ defineAITextEditor }) => defineAITextEditor());\n }\n};\n"],"names":["defineAllComponents","defineSmartSelect","defineAITextEditor"],"mappings":";;AAoBO,MAAMA,IAAsB,MAAY;AAC7C,EAAI,OAAO,SAAW,QACpB,OAAO,kBAAe,EAAE,KAAK,CAAC,EAAE,mBAAAC,EAAAA,MAAwBA,GAAmB,GAC3E,OAAO,mBAAgB,EAAE,KAAK,CAAC,EAAE,oBAAAC,EAAAA,MAAyBA,GAAoB;AAElF;"}
package/package.json ADDED
@@ -0,0 +1,60 @@
1
+ {
2
+ "name": "@liwe3/webcomponents",
3
+ "version": "1.0.0",
4
+ "description": "A collection of reusable web components including SmartSelect and AITextEditor",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js",
13
+ "default": "./dist/index.js"
14
+ },
15
+ "./smart-select": {
16
+ "types": "./dist/SmartSelect.d.ts",
17
+ "import": "./dist/SmartSelect.js",
18
+ "default": "./dist/SmartSelect.js"
19
+ },
20
+ "./ai-text-editor": {
21
+ "types": "./dist/AITextEditor.d.ts",
22
+ "import": "./dist/AITextEditor.js",
23
+ "default": "./dist/AITextEditor.js"
24
+ }
25
+ },
26
+ "files": [
27
+ "dist",
28
+ "src",
29
+ "README.md",
30
+ "LICENSE"
31
+ ],
32
+ "scripts": {
33
+ "dev": "vite build --watch",
34
+ "build": "tsc && vite build",
35
+ "prepublishOnly": "pnpm run build"
36
+ },
37
+ "keywords": [
38
+ "web-components",
39
+ "custom-elements",
40
+ "select",
41
+ "dropdown",
42
+ "ai-editor",
43
+ "text-editor",
44
+ "liwe3"
45
+ ],
46
+ "author": "Liwe3",
47
+ "license": "MIT",
48
+ "repository": {
49
+ "type": "git",
50
+ "url": "https://github.com/liwe3/webcomponents.git"
51
+ },
52
+ "devDependencies": {
53
+ "typescript": "^5.9.2",
54
+ "vite": "^7.1.5"
55
+ },
56
+ "publishConfig": {
57
+ "access": "public"
58
+ },
59
+ "packageManager": "pnpm@10.16.0"
60
+ }