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