@smilodon/core 1.3.1 → 1.3.3
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/dist/index.cjs +57 -150
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +57 -150
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +1 -1
- package/dist/index.min.js.map +1 -1
- package/dist/index.umd.js +57 -150
- package/dist/index.umd.js.map +1 -1
- package/dist/index.umd.min.js +1 -1
- package/dist/index.umd.min.js.map +1 -1
- package/dist/types/src/components/enhanced-select.d.ts +0 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -544,13 +544,11 @@ class CustomOptionPool {
|
|
|
544
544
|
component = pooled.instance;
|
|
545
545
|
pooled.inUse = true;
|
|
546
546
|
pooled.lastUsedIndex = index;
|
|
547
|
-
console.log(`[CustomOptionPool] Reusing component for index ${index}`);
|
|
548
547
|
}
|
|
549
548
|
else {
|
|
550
549
|
// Create new component
|
|
551
550
|
try {
|
|
552
551
|
component = factory(item, index);
|
|
553
|
-
console.log(`[CustomOptionPool] Created new component for index ${index}`);
|
|
554
552
|
// Add to pool if under limit
|
|
555
553
|
const pool = this._pool.get(factoryKey) || [];
|
|
556
554
|
if (pool.length < this._maxPoolSize) {
|
|
@@ -599,7 +597,6 @@ class CustomOptionPool {
|
|
|
599
597
|
const pooled = pool.find(p => p.instance === component);
|
|
600
598
|
if (pooled) {
|
|
601
599
|
pooled.inUse = false;
|
|
602
|
-
console.log(`[CustomOptionPool] Released component from index ${index}`);
|
|
603
600
|
break;
|
|
604
601
|
}
|
|
605
602
|
}
|
|
@@ -608,7 +605,6 @@ class CustomOptionPool {
|
|
|
608
605
|
* Release all active components
|
|
609
606
|
*/
|
|
610
607
|
releaseAll() {
|
|
611
|
-
console.log(`[CustomOptionPool] Releasing ${this._activeComponents.size} active components`);
|
|
612
608
|
const indices = Array.from(this._activeComponents.keys());
|
|
613
609
|
indices.forEach(index => this.release(index));
|
|
614
610
|
}
|
|
@@ -651,7 +647,6 @@ class CustomOptionPool {
|
|
|
651
647
|
clear() {
|
|
652
648
|
this.releaseAll();
|
|
653
649
|
this._pool.clear();
|
|
654
|
-
console.log('[CustomOptionPool] Pool cleared');
|
|
655
650
|
}
|
|
656
651
|
/**
|
|
657
652
|
* Get pool statistics for debugging
|
|
@@ -830,7 +825,6 @@ class OptionRenderer {
|
|
|
830
825
|
});
|
|
831
826
|
}
|
|
832
827
|
this._mountedElements.set(index, option);
|
|
833
|
-
console.log(`[OptionRenderer] Rendered lightweight option ${index}: ${label}`);
|
|
834
828
|
return option;
|
|
835
829
|
}
|
|
836
830
|
/**
|
|
@@ -890,7 +884,6 @@ class OptionRenderer {
|
|
|
890
884
|
}
|
|
891
885
|
});
|
|
892
886
|
}
|
|
893
|
-
console.log(`[OptionRenderer] Rendered custom component option ${index}: ${label}`);
|
|
894
887
|
}
|
|
895
888
|
catch (error) {
|
|
896
889
|
console.error(`[OptionRenderer] Failed to render custom component at index ${index}:`, error);
|
|
@@ -1488,13 +1481,10 @@ class EnhancedSelect extends HTMLElement {
|
|
|
1488
1481
|
this._hasError = false;
|
|
1489
1482
|
this._errorMessage = '';
|
|
1490
1483
|
this._boundArrowClick = null;
|
|
1491
|
-
console.log('[EnhancedSelect] Constructor called');
|
|
1492
1484
|
this._shadow = this.attachShadow({ mode: 'open' });
|
|
1493
|
-
console.log('[EnhancedSelect] Shadow root attached:', this._shadow);
|
|
1494
1485
|
this._uniqueId = `enhanced-select-${Math.random().toString(36).substr(2, 9)}`;
|
|
1495
1486
|
// Merge global config with component-level config
|
|
1496
1487
|
this._config = selectConfig.getConfig();
|
|
1497
|
-
console.log('[EnhancedSelect] Config loaded');
|
|
1498
1488
|
// Initialize state
|
|
1499
1489
|
this._state = {
|
|
1500
1490
|
isOpen: false,
|
|
@@ -1514,44 +1504,26 @@ class EnhancedSelect extends HTMLElement {
|
|
|
1514
1504
|
lastNotifiedResultCount: 0,
|
|
1515
1505
|
isExpanded: false,
|
|
1516
1506
|
};
|
|
1517
|
-
console.log('[EnhancedSelect] State initialized');
|
|
1518
1507
|
// Create DOM structure
|
|
1519
1508
|
this._container = this._createContainer();
|
|
1520
|
-
console.log('[EnhancedSelect] Container created:', this._container);
|
|
1521
1509
|
this._inputContainer = this._createInputContainer();
|
|
1522
|
-
console.log('[EnhancedSelect] Input container created');
|
|
1523
1510
|
this._input = this._createInput();
|
|
1524
|
-
console.log('[EnhancedSelect] Input created:', this._input);
|
|
1525
1511
|
this._arrowContainer = this._createArrowContainer();
|
|
1526
|
-
console.log('[EnhancedSelect] Arrow container created');
|
|
1527
1512
|
this._dropdown = this._createDropdown();
|
|
1528
|
-
console.log('[EnhancedSelect] Dropdown created');
|
|
1529
1513
|
this._optionsContainer = this._createOptionsContainer();
|
|
1530
|
-
console.log('[EnhancedSelect] Options container created');
|
|
1531
1514
|
this._liveRegion = this._createLiveRegion();
|
|
1532
|
-
console.log('[EnhancedSelect] Live region created');
|
|
1533
1515
|
// Initialize styles BEFORE assembling DOM (order matters in shadow DOM)
|
|
1534
1516
|
this._initializeStyles();
|
|
1535
|
-
console.log('[EnhancedSelect] Styles initialized');
|
|
1536
|
-
// Initialize option renderer
|
|
1537
|
-
this._initializeOptionRenderer();
|
|
1538
|
-
console.log('[EnhancedSelect] Option renderer initialized');
|
|
1539
1517
|
this._assembleDOM();
|
|
1540
|
-
console.log('[EnhancedSelect] DOM assembled');
|
|
1541
1518
|
this._attachEventListeners();
|
|
1542
|
-
console.log('[EnhancedSelect] Event listeners attached');
|
|
1543
1519
|
this._initializeObservers();
|
|
1544
|
-
console.log('[EnhancedSelect] Observers initialized');
|
|
1545
|
-
console.log('[EnhancedSelect] Constructor complete, shadow DOM children:', this._shadow.children.length);
|
|
1546
1520
|
}
|
|
1547
1521
|
connectedCallback() {
|
|
1548
|
-
console.log('[EnhancedSelect] connectedCallback called');
|
|
1549
1522
|
// WORKAROUND: Force display style on host element for Angular compatibility
|
|
1550
1523
|
// Angular's rendering seems to not apply :host styles correctly in some cases
|
|
1551
1524
|
// Must be done in connectedCallback when element is attached to DOM
|
|
1552
1525
|
this.style.display = 'block';
|
|
1553
1526
|
this.style.width = '100%';
|
|
1554
|
-
console.log('[EnhancedSelect] Forced host display styles');
|
|
1555
1527
|
// Load initial data if server-side is enabled
|
|
1556
1528
|
if (this._config.serverSide.enabled && this._config.serverSide.initialSelectedValues) {
|
|
1557
1529
|
this._loadInitialSelectedItems();
|
|
@@ -1560,7 +1532,6 @@ class EnhancedSelect extends HTMLElement {
|
|
|
1560
1532
|
if (this._config.callbacks.onOpen) {
|
|
1561
1533
|
this._config.callbacks.onOpen();
|
|
1562
1534
|
}
|
|
1563
|
-
console.log('[EnhancedSelect] connectedCallback complete');
|
|
1564
1535
|
}
|
|
1565
1536
|
disconnectedCallback() {
|
|
1566
1537
|
// Cleanup observers
|
|
@@ -1572,11 +1543,6 @@ class EnhancedSelect extends HTMLElement {
|
|
|
1572
1543
|
clearTimeout(this._typeTimeout);
|
|
1573
1544
|
if (this._searchTimeout)
|
|
1574
1545
|
clearTimeout(this._searchTimeout);
|
|
1575
|
-
// Cleanup option renderer
|
|
1576
|
-
if (this._optionRenderer) {
|
|
1577
|
-
this._optionRenderer.unmountAll();
|
|
1578
|
-
console.log('[EnhancedSelect] Option renderer cleaned up');
|
|
1579
|
-
}
|
|
1580
1546
|
// Cleanup arrow click listener
|
|
1581
1547
|
if (this._boundArrowClick && this._arrowContainer) {
|
|
1582
1548
|
this._arrowContainer.removeEventListener('click', this._boundArrowClick);
|
|
@@ -1663,43 +1629,22 @@ class EnhancedSelect extends HTMLElement {
|
|
|
1663
1629
|
return container;
|
|
1664
1630
|
}
|
|
1665
1631
|
_assembleDOM() {
|
|
1666
|
-
console.log('[EnhancedSelect] _assembleDOM: Starting DOM assembly');
|
|
1667
|
-
console.log('[EnhancedSelect] _assembleDOM: Elements to assemble:', {
|
|
1668
|
-
inputContainer: !!this._inputContainer,
|
|
1669
|
-
input: !!this._input,
|
|
1670
|
-
arrowContainer: !!this._arrowContainer,
|
|
1671
|
-
container: !!this._container,
|
|
1672
|
-
dropdown: !!this._dropdown,
|
|
1673
|
-
optionsContainer: !!this._optionsContainer,
|
|
1674
|
-
shadow: !!this._shadow,
|
|
1675
|
-
liveRegion: !!this._liveRegion
|
|
1676
|
-
});
|
|
1677
1632
|
this._inputContainer.appendChild(this._input);
|
|
1678
|
-
console.log('[EnhancedSelect] _assembleDOM: Appended input to inputContainer');
|
|
1679
1633
|
if (this._arrowContainer) {
|
|
1680
1634
|
this._inputContainer.appendChild(this._arrowContainer);
|
|
1681
|
-
console.log('[EnhancedSelect] _assembleDOM: Appended arrowContainer to inputContainer');
|
|
1682
1635
|
}
|
|
1683
1636
|
this._container.appendChild(this._inputContainer);
|
|
1684
|
-
console.log('[EnhancedSelect] _assembleDOM: Appended inputContainer to container');
|
|
1685
1637
|
this._dropdown.appendChild(this._optionsContainer);
|
|
1686
|
-
console.log('[EnhancedSelect] _assembleDOM: Appended optionsContainer to dropdown');
|
|
1687
1638
|
this._container.appendChild(this._dropdown);
|
|
1688
|
-
console.log('[EnhancedSelect] _assembleDOM: Appended dropdown to container');
|
|
1689
1639
|
this._shadow.appendChild(this._container);
|
|
1690
|
-
console.log('[EnhancedSelect] _assembleDOM: Appended container to shadow root');
|
|
1691
1640
|
if (this._liveRegion) {
|
|
1692
1641
|
this._shadow.appendChild(this._liveRegion);
|
|
1693
|
-
console.log('[EnhancedSelect] _assembleDOM: Appended liveRegion to shadow root');
|
|
1694
1642
|
}
|
|
1695
|
-
console.log('[EnhancedSelect] _assembleDOM: Shadow root children count:', this._shadow.children.length);
|
|
1696
|
-
console.log('[EnhancedSelect] _assembleDOM: Shadow root HTML length:', this._shadow.innerHTML.length);
|
|
1697
1643
|
// Set ARIA relationships
|
|
1698
1644
|
const listboxId = `${this._uniqueId}-listbox`;
|
|
1699
1645
|
this._dropdown.id = listboxId;
|
|
1700
1646
|
this._input.setAttribute('aria-controls', listboxId);
|
|
1701
1647
|
this._input.setAttribute('aria-owns', listboxId);
|
|
1702
|
-
console.log('[EnhancedSelect] _assembleDOM: Set ARIA relationships with listboxId:', listboxId);
|
|
1703
1648
|
}
|
|
1704
1649
|
_initializeStyles() {
|
|
1705
1650
|
const style = document.createElement('style');
|
|
@@ -2029,8 +1974,6 @@ class EnhancedSelect extends HTMLElement {
|
|
|
2029
1974
|
min-height: 44px;
|
|
2030
1975
|
}
|
|
2031
1976
|
`;
|
|
2032
|
-
console.log('[EnhancedSelect] _initializeStyles: Created style element, content length:', style.textContent?.length || 0);
|
|
2033
|
-
console.log('[EnhancedSelect] _initializeStyles: Shadow root children BEFORE:', this._shadow.children.length);
|
|
2034
1977
|
// Insert as first child to ensure styles are processed first
|
|
2035
1978
|
if (this._shadow.firstChild) {
|
|
2036
1979
|
this._shadow.insertBefore(style, this._shadow.firstChild);
|
|
@@ -2038,9 +1981,6 @@ class EnhancedSelect extends HTMLElement {
|
|
|
2038
1981
|
else {
|
|
2039
1982
|
this._shadow.appendChild(style);
|
|
2040
1983
|
}
|
|
2041
|
-
console.log('[EnhancedSelect] _initializeStyles: Style inserted, shadow root children AFTER:', this._shadow.children.length);
|
|
2042
|
-
console.log('[EnhancedSelect] _initializeStyles: Shadow root has style element:', !!this._shadow.querySelector('style'));
|
|
2043
|
-
console.log('[EnhancedSelect] _initializeStyles: Style sheet rules:', style.sheet?.cssRules?.length || 'NOT PARSED');
|
|
2044
1984
|
}
|
|
2045
1985
|
_attachEventListeners() {
|
|
2046
1986
|
// Arrow click handler
|
|
@@ -2116,40 +2056,6 @@ class EnhancedSelect extends HTMLElement {
|
|
|
2116
2056
|
}, { threshold: 0.1 });
|
|
2117
2057
|
}
|
|
2118
2058
|
}
|
|
2119
|
-
_initializeOptionRenderer() {
|
|
2120
|
-
const getValue = this._config.serverSide.getValueFromItem || ((item) => item?.value ?? item);
|
|
2121
|
-
const getLabel = this._config.serverSide.getLabelFromItem || ((item) => item?.label ?? String(item));
|
|
2122
|
-
const getDisabled = (item) => item?.disabled ?? false;
|
|
2123
|
-
const rendererConfig = {
|
|
2124
|
-
enableRecycling: true,
|
|
2125
|
-
maxPoolSize: 100,
|
|
2126
|
-
getValue,
|
|
2127
|
-
getLabel,
|
|
2128
|
-
getDisabled,
|
|
2129
|
-
onSelect: (index) => {
|
|
2130
|
-
this._selectOption(index);
|
|
2131
|
-
},
|
|
2132
|
-
onCustomEvent: (index, eventName, data) => {
|
|
2133
|
-
console.log(`[EnhancedSelect] Custom event from option ${index}: ${eventName}`, data);
|
|
2134
|
-
// Emit as a generic event since these aren't in the standard event map
|
|
2135
|
-
this.dispatchEvent(new CustomEvent('option:custom-event', {
|
|
2136
|
-
detail: { index, eventName, data },
|
|
2137
|
-
bubbles: true,
|
|
2138
|
-
composed: true
|
|
2139
|
-
}));
|
|
2140
|
-
},
|
|
2141
|
-
onError: (index, error) => {
|
|
2142
|
-
console.error(`[EnhancedSelect] Error in option ${index}:`, error);
|
|
2143
|
-
this.dispatchEvent(new CustomEvent('option:mount-error', {
|
|
2144
|
-
detail: { index, error },
|
|
2145
|
-
bubbles: true,
|
|
2146
|
-
composed: true
|
|
2147
|
-
}));
|
|
2148
|
-
}
|
|
2149
|
-
};
|
|
2150
|
-
this._optionRenderer = new OptionRenderer(rendererConfig);
|
|
2151
|
-
console.log('[EnhancedSelect] Option renderer initialized with config:', rendererConfig);
|
|
2152
|
-
}
|
|
2153
2059
|
async _loadInitialSelectedItems() {
|
|
2154
2060
|
if (!this._config.serverSide.fetchSelectedItems || !this._config.serverSide.initialSelectedValues) {
|
|
2155
2061
|
return;
|
|
@@ -2365,13 +2271,31 @@ class EnhancedSelect extends HTMLElement {
|
|
|
2365
2271
|
const options = Array.from(this._optionsContainer.children);
|
|
2366
2272
|
// Clear previous active state
|
|
2367
2273
|
if (this._state.activeIndex >= 0 && options[this._state.activeIndex]) {
|
|
2368
|
-
options[this._state.activeIndex]
|
|
2274
|
+
const prevOption = options[this._state.activeIndex];
|
|
2275
|
+
// Check if it's a custom SelectOption or a lightweight DOM element
|
|
2276
|
+
if ('setActive' in prevOption && typeof prevOption.setActive === 'function') {
|
|
2277
|
+
prevOption.setActive(false);
|
|
2278
|
+
}
|
|
2279
|
+
else {
|
|
2280
|
+
// Lightweight option - remove active class
|
|
2281
|
+
prevOption.classList.remove('smilodon-option--active');
|
|
2282
|
+
prevOption.setAttribute('aria-selected', 'false');
|
|
2283
|
+
}
|
|
2369
2284
|
}
|
|
2370
2285
|
this._state.activeIndex = index;
|
|
2371
2286
|
// Set new active state
|
|
2372
2287
|
if (options[index]) {
|
|
2373
|
-
options[index]
|
|
2374
|
-
|
|
2288
|
+
const option = options[index];
|
|
2289
|
+
// Check if it's a custom SelectOption or a lightweight DOM element
|
|
2290
|
+
if ('setActive' in option && typeof option.setActive === 'function') {
|
|
2291
|
+
option.setActive(true);
|
|
2292
|
+
}
|
|
2293
|
+
else {
|
|
2294
|
+
// Lightweight option - add active class
|
|
2295
|
+
option.classList.add('smilodon-option--active');
|
|
2296
|
+
option.setAttribute('aria-selected', 'true');
|
|
2297
|
+
}
|
|
2298
|
+
option.scrollIntoView({ block: 'nearest', behavior: 'smooth' });
|
|
2375
2299
|
// Announce position for screen readers
|
|
2376
2300
|
const total = options.length;
|
|
2377
2301
|
this._announce(`Item ${index + 1} of ${total}`);
|
|
@@ -2404,10 +2328,23 @@ class EnhancedSelect extends HTMLElement {
|
|
|
2404
2328
|
return;
|
|
2405
2329
|
}
|
|
2406
2330
|
if (!this._state.selectedIndices.has(index)) {
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2331
|
+
// Check if it's a custom SelectOption or a lightweight DOM element
|
|
2332
|
+
if ('getConfig' in option && typeof option.getConfig === 'function') {
|
|
2333
|
+
const config = option.getConfig();
|
|
2334
|
+
this._state.selectedIndices.add(index);
|
|
2335
|
+
this._state.selectedItems.set(index, config.item);
|
|
2336
|
+
option.setSelected(true);
|
|
2337
|
+
}
|
|
2338
|
+
else {
|
|
2339
|
+
// Lightweight option - get item from data attribute or state
|
|
2340
|
+
const item = this._state.loadedItems[index];
|
|
2341
|
+
if (item) {
|
|
2342
|
+
this._state.selectedIndices.add(index);
|
|
2343
|
+
this._state.selectedItems.set(index, item);
|
|
2344
|
+
option.classList.add('smilodon-option--selected');
|
|
2345
|
+
option.setAttribute('aria-selected', 'true');
|
|
2346
|
+
}
|
|
2347
|
+
}
|
|
2411
2348
|
}
|
|
2412
2349
|
});
|
|
2413
2350
|
this._updateInputDisplay();
|
|
@@ -2650,27 +2587,21 @@ class EnhancedSelect extends HTMLElement {
|
|
|
2650
2587
|
* Set items to display in the select
|
|
2651
2588
|
*/
|
|
2652
2589
|
setItems(items) {
|
|
2653
|
-
console.log('[EnhancedSelect] setItems called with', items?.length || 0, 'items');
|
|
2654
|
-
console.log('[EnhancedSelect] Items:', items);
|
|
2655
2590
|
const previousLength = this._state.loadedItems.length;
|
|
2656
2591
|
this._state.loadedItems = items;
|
|
2657
2592
|
// If grouped items exist, flatten them to items
|
|
2658
2593
|
if (this._state.groupedItems.length > 0) {
|
|
2659
2594
|
this._state.loadedItems = this._state.groupedItems.flatMap(group => group.options);
|
|
2660
|
-
console.log('[EnhancedSelect] Flattened grouped items to', this._state.loadedItems.length, 'items');
|
|
2661
2595
|
}
|
|
2662
2596
|
const newLength = this._state.loadedItems.length;
|
|
2663
|
-
console.log('[EnhancedSelect] State.loadedItems updated:', previousLength, '→', newLength);
|
|
2664
2597
|
// When infinite scroll is active (preserveScrollPosition = true),
|
|
2665
2598
|
// we need to maintain scroll position during the update
|
|
2666
2599
|
if (this._state.preserveScrollPosition && this._dropdown) {
|
|
2667
2600
|
const targetScrollTop = this._state.lastScrollPosition;
|
|
2668
|
-
console.log('[EnhancedSelect] Preserving scroll position:', targetScrollTop);
|
|
2669
2601
|
// Only clear loading if we actually got more items
|
|
2670
2602
|
if (newLength > previousLength) {
|
|
2671
2603
|
this._state.isBusy = false;
|
|
2672
2604
|
}
|
|
2673
|
-
console.log('[EnhancedSelect] Calling _renderOptions (with scroll preservation)...');
|
|
2674
2605
|
this._renderOptions();
|
|
2675
2606
|
// Restore the exact scrollTop we had before loading
|
|
2676
2607
|
// so the previously visible items stay in place and
|
|
@@ -2690,10 +2621,8 @@ class EnhancedSelect extends HTMLElement {
|
|
|
2690
2621
|
else {
|
|
2691
2622
|
// Normal update - just render normally
|
|
2692
2623
|
this._state.isBusy = false;
|
|
2693
|
-
console.log('[EnhancedSelect] Calling _renderOptions (normal)...');
|
|
2694
2624
|
this._renderOptions();
|
|
2695
2625
|
}
|
|
2696
|
-
console.log('[EnhancedSelect] setItems complete');
|
|
2697
2626
|
}
|
|
2698
2627
|
/**
|
|
2699
2628
|
* Set grouped items
|
|
@@ -2857,26 +2786,11 @@ class EnhancedSelect extends HTMLElement {
|
|
|
2857
2786
|
* Render options based on current state
|
|
2858
2787
|
*/
|
|
2859
2788
|
_renderOptions() {
|
|
2860
|
-
console.log('[EnhancedSelect] _renderOptions called');
|
|
2861
|
-
console.log('[EnhancedSelect] State:', {
|
|
2862
|
-
loadedItems: this._state.loadedItems.length,
|
|
2863
|
-
groupedItems: this._state.groupedItems.length,
|
|
2864
|
-
isOpen: this._state.isOpen,
|
|
2865
|
-
isSearching: this._state.isSearching,
|
|
2866
|
-
searchQuery: this._state.searchQuery,
|
|
2867
|
-
isBusy: this._state.isBusy
|
|
2868
|
-
});
|
|
2869
2789
|
// Cleanup observer
|
|
2870
2790
|
if (this._loadMoreTrigger && this._intersectionObserver) {
|
|
2871
2791
|
this._intersectionObserver.unobserve(this._loadMoreTrigger);
|
|
2872
2792
|
}
|
|
2873
|
-
// Cleanup all rendered options (including custom components)
|
|
2874
|
-
if (this._optionRenderer) {
|
|
2875
|
-
this._optionRenderer.unmountAll();
|
|
2876
|
-
console.log('[EnhancedSelect] Unmounted all option components');
|
|
2877
|
-
}
|
|
2878
2793
|
// Clear options container
|
|
2879
|
-
console.log('[EnhancedSelect] Clearing options container, previous children:', this._optionsContainer.children.length);
|
|
2880
2794
|
this._optionsContainer.innerHTML = '';
|
|
2881
2795
|
// Ensure dropdown only contains options container (cleanup legacy direct children)
|
|
2882
2796
|
// We need to preserve optionsContainer, so we can't just clear dropdown.innerHTML
|
|
@@ -2889,7 +2803,6 @@ class EnhancedSelect extends HTMLElement {
|
|
|
2889
2803
|
// Ensure dropdown is visible if we are rendering options
|
|
2890
2804
|
if (this._state.isOpen && this._dropdown.style.display === 'none') {
|
|
2891
2805
|
this._dropdown.style.display = 'block';
|
|
2892
|
-
console.log('[EnhancedSelect] Dropdown display set to block');
|
|
2893
2806
|
}
|
|
2894
2807
|
// Show searching state (exclusive state)
|
|
2895
2808
|
if (this._state.isSearching) {
|
|
@@ -2897,7 +2810,6 @@ class EnhancedSelect extends HTMLElement {
|
|
|
2897
2810
|
searching.className = 'searching-state';
|
|
2898
2811
|
searching.textContent = 'Searching...';
|
|
2899
2812
|
this._optionsContainer.appendChild(searching);
|
|
2900
|
-
console.log('[EnhancedSelect] Added searching state');
|
|
2901
2813
|
return;
|
|
2902
2814
|
}
|
|
2903
2815
|
const getValue = this._config.serverSide.getValueFromItem || ((item) => item?.value ?? item);
|
|
@@ -2906,7 +2818,6 @@ class EnhancedSelect extends HTMLElement {
|
|
|
2906
2818
|
const query = this._state.searchQuery.toLowerCase();
|
|
2907
2819
|
// Handle Grouped Items Rendering (when no search query)
|
|
2908
2820
|
if (this._state.groupedItems.length > 0 && !query) {
|
|
2909
|
-
console.log('[EnhancedSelect] Rendering grouped items:', this._state.groupedItems.length, 'groups');
|
|
2910
2821
|
this._state.groupedItems.forEach(group => {
|
|
2911
2822
|
const header = document.createElement('div');
|
|
2912
2823
|
header.className = 'group-header';
|
|
@@ -2936,7 +2847,6 @@ class EnhancedSelect extends HTMLElement {
|
|
|
2936
2847
|
}
|
|
2937
2848
|
else {
|
|
2938
2849
|
// Normal rendering (flat list or filtered)
|
|
2939
|
-
console.log('[EnhancedSelect] Rendering flat list:', this._state.loadedItems.length, 'items');
|
|
2940
2850
|
let hasRenderedItems = false;
|
|
2941
2851
|
this._state.loadedItems.forEach((item, index) => {
|
|
2942
2852
|
// Apply filter if query exists
|
|
@@ -2953,7 +2863,6 @@ class EnhancedSelect extends HTMLElement {
|
|
|
2953
2863
|
hasRenderedItems = true;
|
|
2954
2864
|
this._renderSingleOption(item, index, getValue, getLabel);
|
|
2955
2865
|
});
|
|
2956
|
-
console.log('[EnhancedSelect] Rendered', hasRenderedItems ? 'items' : 'no items');
|
|
2957
2866
|
if (!hasRenderedItems && !this._state.isBusy) {
|
|
2958
2867
|
const empty = document.createElement('div');
|
|
2959
2868
|
empty.className = 'empty-state';
|
|
@@ -2964,7 +2873,6 @@ class EnhancedSelect extends HTMLElement {
|
|
|
2964
2873
|
empty.textContent = 'No options available';
|
|
2965
2874
|
}
|
|
2966
2875
|
this._optionsContainer.appendChild(empty);
|
|
2967
|
-
console.log('[EnhancedSelect] Added empty state');
|
|
2968
2876
|
}
|
|
2969
2877
|
}
|
|
2970
2878
|
// Append Busy Indicator if busy
|
|
@@ -2982,33 +2890,34 @@ class EnhancedSelect extends HTMLElement {
|
|
|
2982
2890
|
busyBucket.appendChild(message);
|
|
2983
2891
|
}
|
|
2984
2892
|
this._optionsContainer.appendChild(busyBucket);
|
|
2985
|
-
console.log('[EnhancedSelect] Added busy bucket');
|
|
2986
2893
|
}
|
|
2987
2894
|
// Append Load More Trigger (Button or Sentinel) if enabled and not busy
|
|
2988
2895
|
else if ((this._config.loadMore.enabled || this._config.infiniteScroll.enabled) && this._state.loadedItems.length > 0) {
|
|
2989
2896
|
this._addLoadMoreTrigger();
|
|
2990
2897
|
}
|
|
2991
|
-
console.log('[EnhancedSelect] _renderOptions complete, optionsContainer children:', this._optionsContainer.children.length);
|
|
2992
2898
|
}
|
|
2993
2899
|
_renderSingleOption(item, index, getValue, getLabel) {
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
|
|
2900
|
+
const option = document.createElement('div');
|
|
2901
|
+
option.className = 'option';
|
|
2902
|
+
option.id = `${this._uniqueId}-option-${index}`;
|
|
2903
|
+
const value = getValue(item);
|
|
2904
|
+
const label = getLabel(item);
|
|
2905
|
+
option.textContent = label;
|
|
2906
|
+
option.dataset.value = String(value);
|
|
2907
|
+
option.dataset.index = String(index); // Also useful for debugging/selectors
|
|
2908
|
+
// Check if selected using selectedItems map
|
|
2999
2909
|
const isSelected = this._state.selectedIndices.has(index);
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
2910
|
+
if (isSelected) {
|
|
2911
|
+
option.classList.add('selected');
|
|
2912
|
+
option.setAttribute('aria-selected', 'true');
|
|
2913
|
+
}
|
|
2914
|
+
else {
|
|
2915
|
+
option.setAttribute('aria-selected', 'false');
|
|
2916
|
+
}
|
|
2917
|
+
option.addEventListener('click', () => {
|
|
2918
|
+
this._selectOption(index);
|
|
3007
2919
|
});
|
|
3008
|
-
|
|
3009
|
-
const optionElement = this._optionRenderer.render(item, index, isSelected, isFocused, this._uniqueId);
|
|
3010
|
-
this._optionsContainer.appendChild(optionElement);
|
|
3011
|
-
console.log('[EnhancedSelect] Option', index, 'appended to optionsContainer');
|
|
2920
|
+
this._optionsContainer.appendChild(option);
|
|
3012
2921
|
}
|
|
3013
2922
|
_addLoadMoreTrigger() {
|
|
3014
2923
|
const container = document.createElement('div');
|
|
@@ -3841,7 +3750,6 @@ async function measureAsync(label, fn) {
|
|
|
3841
3750
|
const start = performance.now();
|
|
3842
3751
|
const result = await fn();
|
|
3843
3752
|
const duration = performance.now() - start;
|
|
3844
|
-
console.log(`[Perf] ${label}: ${duration.toFixed(2)}ms`);
|
|
3845
3753
|
return { result, duration };
|
|
3846
3754
|
}
|
|
3847
3755
|
/**
|
|
@@ -3851,7 +3759,6 @@ function measureSync(label, fn) {
|
|
|
3851
3759
|
const start = performance.now();
|
|
3852
3760
|
const result = fn();
|
|
3853
3761
|
const duration = performance.now() - start;
|
|
3854
|
-
console.log(`[Perf] ${label}: ${duration.toFixed(2)}ms`);
|
|
3855
3762
|
return { result, duration };
|
|
3856
3763
|
}
|
|
3857
3764
|
|