@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.umd.js CHANGED
@@ -550,13 +550,11 @@
550
550
  component = pooled.instance;
551
551
  pooled.inUse = true;
552
552
  pooled.lastUsedIndex = index;
553
- console.log(`[CustomOptionPool] Reusing component for index ${index}`);
554
553
  }
555
554
  else {
556
555
  // Create new component
557
556
  try {
558
557
  component = factory(item, index);
559
- console.log(`[CustomOptionPool] Created new component for index ${index}`);
560
558
  // Add to pool if under limit
561
559
  const pool = this._pool.get(factoryKey) || [];
562
560
  if (pool.length < this._maxPoolSize) {
@@ -605,7 +603,6 @@
605
603
  const pooled = pool.find(p => p.instance === component);
606
604
  if (pooled) {
607
605
  pooled.inUse = false;
608
- console.log(`[CustomOptionPool] Released component from index ${index}`);
609
606
  break;
610
607
  }
611
608
  }
@@ -614,7 +611,6 @@
614
611
  * Release all active components
615
612
  */
616
613
  releaseAll() {
617
- console.log(`[CustomOptionPool] Releasing ${this._activeComponents.size} active components`);
618
614
  const indices = Array.from(this._activeComponents.keys());
619
615
  indices.forEach(index => this.release(index));
620
616
  }
@@ -657,7 +653,6 @@
657
653
  clear() {
658
654
  this.releaseAll();
659
655
  this._pool.clear();
660
- console.log('[CustomOptionPool] Pool cleared');
661
656
  }
662
657
  /**
663
658
  * Get pool statistics for debugging
@@ -836,7 +831,6 @@
836
831
  });
837
832
  }
838
833
  this._mountedElements.set(index, option);
839
- console.log(`[OptionRenderer] Rendered lightweight option ${index}: ${label}`);
840
834
  return option;
841
835
  }
842
836
  /**
@@ -896,7 +890,6 @@
896
890
  }
897
891
  });
898
892
  }
899
- console.log(`[OptionRenderer] Rendered custom component option ${index}: ${label}`);
900
893
  }
901
894
  catch (error) {
902
895
  console.error(`[OptionRenderer] Failed to render custom component at index ${index}:`, error);
@@ -1494,13 +1487,10 @@
1494
1487
  this._hasError = false;
1495
1488
  this._errorMessage = '';
1496
1489
  this._boundArrowClick = null;
1497
- console.log('[EnhancedSelect] Constructor called');
1498
1490
  this._shadow = this.attachShadow({ mode: 'open' });
1499
- console.log('[EnhancedSelect] Shadow root attached:', this._shadow);
1500
1491
  this._uniqueId = `enhanced-select-${Math.random().toString(36).substr(2, 9)}`;
1501
1492
  // Merge global config with component-level config
1502
1493
  this._config = selectConfig.getConfig();
1503
- console.log('[EnhancedSelect] Config loaded');
1504
1494
  // Initialize state
1505
1495
  this._state = {
1506
1496
  isOpen: false,
@@ -1520,44 +1510,26 @@
1520
1510
  lastNotifiedResultCount: 0,
1521
1511
  isExpanded: false,
1522
1512
  };
1523
- console.log('[EnhancedSelect] State initialized');
1524
1513
  // Create DOM structure
1525
1514
  this._container = this._createContainer();
1526
- console.log('[EnhancedSelect] Container created:', this._container);
1527
1515
  this._inputContainer = this._createInputContainer();
1528
- console.log('[EnhancedSelect] Input container created');
1529
1516
  this._input = this._createInput();
1530
- console.log('[EnhancedSelect] Input created:', this._input);
1531
1517
  this._arrowContainer = this._createArrowContainer();
1532
- console.log('[EnhancedSelect] Arrow container created');
1533
1518
  this._dropdown = this._createDropdown();
1534
- console.log('[EnhancedSelect] Dropdown created');
1535
1519
  this._optionsContainer = this._createOptionsContainer();
1536
- console.log('[EnhancedSelect] Options container created');
1537
1520
  this._liveRegion = this._createLiveRegion();
1538
- console.log('[EnhancedSelect] Live region created');
1539
1521
  // Initialize styles BEFORE assembling DOM (order matters in shadow DOM)
1540
1522
  this._initializeStyles();
1541
- console.log('[EnhancedSelect] Styles initialized');
1542
- // Initialize option renderer
1543
- this._initializeOptionRenderer();
1544
- console.log('[EnhancedSelect] Option renderer initialized');
1545
1523
  this._assembleDOM();
1546
- console.log('[EnhancedSelect] DOM assembled');
1547
1524
  this._attachEventListeners();
1548
- console.log('[EnhancedSelect] Event listeners attached');
1549
1525
  this._initializeObservers();
1550
- console.log('[EnhancedSelect] Observers initialized');
1551
- console.log('[EnhancedSelect] Constructor complete, shadow DOM children:', this._shadow.children.length);
1552
1526
  }
1553
1527
  connectedCallback() {
1554
- console.log('[EnhancedSelect] connectedCallback called');
1555
1528
  // WORKAROUND: Force display style on host element for Angular compatibility
1556
1529
  // Angular's rendering seems to not apply :host styles correctly in some cases
1557
1530
  // Must be done in connectedCallback when element is attached to DOM
1558
1531
  this.style.display = 'block';
1559
1532
  this.style.width = '100%';
1560
- console.log('[EnhancedSelect] Forced host display styles');
1561
1533
  // Load initial data if server-side is enabled
1562
1534
  if (this._config.serverSide.enabled && this._config.serverSide.initialSelectedValues) {
1563
1535
  this._loadInitialSelectedItems();
@@ -1566,7 +1538,6 @@
1566
1538
  if (this._config.callbacks.onOpen) {
1567
1539
  this._config.callbacks.onOpen();
1568
1540
  }
1569
- console.log('[EnhancedSelect] connectedCallback complete');
1570
1541
  }
1571
1542
  disconnectedCallback() {
1572
1543
  // Cleanup observers
@@ -1578,11 +1549,6 @@
1578
1549
  clearTimeout(this._typeTimeout);
1579
1550
  if (this._searchTimeout)
1580
1551
  clearTimeout(this._searchTimeout);
1581
- // Cleanup option renderer
1582
- if (this._optionRenderer) {
1583
- this._optionRenderer.unmountAll();
1584
- console.log('[EnhancedSelect] Option renderer cleaned up');
1585
- }
1586
1552
  // Cleanup arrow click listener
1587
1553
  if (this._boundArrowClick && this._arrowContainer) {
1588
1554
  this._arrowContainer.removeEventListener('click', this._boundArrowClick);
@@ -1669,43 +1635,22 @@
1669
1635
  return container;
1670
1636
  }
1671
1637
  _assembleDOM() {
1672
- console.log('[EnhancedSelect] _assembleDOM: Starting DOM assembly');
1673
- console.log('[EnhancedSelect] _assembleDOM: Elements to assemble:', {
1674
- inputContainer: !!this._inputContainer,
1675
- input: !!this._input,
1676
- arrowContainer: !!this._arrowContainer,
1677
- container: !!this._container,
1678
- dropdown: !!this._dropdown,
1679
- optionsContainer: !!this._optionsContainer,
1680
- shadow: !!this._shadow,
1681
- liveRegion: !!this._liveRegion
1682
- });
1683
1638
  this._inputContainer.appendChild(this._input);
1684
- console.log('[EnhancedSelect] _assembleDOM: Appended input to inputContainer');
1685
1639
  if (this._arrowContainer) {
1686
1640
  this._inputContainer.appendChild(this._arrowContainer);
1687
- console.log('[EnhancedSelect] _assembleDOM: Appended arrowContainer to inputContainer');
1688
1641
  }
1689
1642
  this._container.appendChild(this._inputContainer);
1690
- console.log('[EnhancedSelect] _assembleDOM: Appended inputContainer to container');
1691
1643
  this._dropdown.appendChild(this._optionsContainer);
1692
- console.log('[EnhancedSelect] _assembleDOM: Appended optionsContainer to dropdown');
1693
1644
  this._container.appendChild(this._dropdown);
1694
- console.log('[EnhancedSelect] _assembleDOM: Appended dropdown to container');
1695
1645
  this._shadow.appendChild(this._container);
1696
- console.log('[EnhancedSelect] _assembleDOM: Appended container to shadow root');
1697
1646
  if (this._liveRegion) {
1698
1647
  this._shadow.appendChild(this._liveRegion);
1699
- console.log('[EnhancedSelect] _assembleDOM: Appended liveRegion to shadow root');
1700
1648
  }
1701
- console.log('[EnhancedSelect] _assembleDOM: Shadow root children count:', this._shadow.children.length);
1702
- console.log('[EnhancedSelect] _assembleDOM: Shadow root HTML length:', this._shadow.innerHTML.length);
1703
1649
  // Set ARIA relationships
1704
1650
  const listboxId = `${this._uniqueId}-listbox`;
1705
1651
  this._dropdown.id = listboxId;
1706
1652
  this._input.setAttribute('aria-controls', listboxId);
1707
1653
  this._input.setAttribute('aria-owns', listboxId);
1708
- console.log('[EnhancedSelect] _assembleDOM: Set ARIA relationships with listboxId:', listboxId);
1709
1654
  }
1710
1655
  _initializeStyles() {
1711
1656
  const style = document.createElement('style');
@@ -2035,8 +1980,6 @@
2035
1980
  min-height: 44px;
2036
1981
  }
2037
1982
  `;
2038
- console.log('[EnhancedSelect] _initializeStyles: Created style element, content length:', style.textContent?.length || 0);
2039
- console.log('[EnhancedSelect] _initializeStyles: Shadow root children BEFORE:', this._shadow.children.length);
2040
1983
  // Insert as first child to ensure styles are processed first
2041
1984
  if (this._shadow.firstChild) {
2042
1985
  this._shadow.insertBefore(style, this._shadow.firstChild);
@@ -2044,9 +1987,6 @@
2044
1987
  else {
2045
1988
  this._shadow.appendChild(style);
2046
1989
  }
2047
- console.log('[EnhancedSelect] _initializeStyles: Style inserted, shadow root children AFTER:', this._shadow.children.length);
2048
- console.log('[EnhancedSelect] _initializeStyles: Shadow root has style element:', !!this._shadow.querySelector('style'));
2049
- console.log('[EnhancedSelect] _initializeStyles: Style sheet rules:', style.sheet?.cssRules?.length || 'NOT PARSED');
2050
1990
  }
2051
1991
  _attachEventListeners() {
2052
1992
  // Arrow click handler
@@ -2122,40 +2062,6 @@
2122
2062
  }, { threshold: 0.1 });
2123
2063
  }
2124
2064
  }
2125
- _initializeOptionRenderer() {
2126
- const getValue = this._config.serverSide.getValueFromItem || ((item) => item?.value ?? item);
2127
- const getLabel = this._config.serverSide.getLabelFromItem || ((item) => item?.label ?? String(item));
2128
- const getDisabled = (item) => item?.disabled ?? false;
2129
- const rendererConfig = {
2130
- enableRecycling: true,
2131
- maxPoolSize: 100,
2132
- getValue,
2133
- getLabel,
2134
- getDisabled,
2135
- onSelect: (index) => {
2136
- this._selectOption(index);
2137
- },
2138
- onCustomEvent: (index, eventName, data) => {
2139
- console.log(`[EnhancedSelect] Custom event from option ${index}: ${eventName}`, data);
2140
- // Emit as a generic event since these aren't in the standard event map
2141
- this.dispatchEvent(new CustomEvent('option:custom-event', {
2142
- detail: { index, eventName, data },
2143
- bubbles: true,
2144
- composed: true
2145
- }));
2146
- },
2147
- onError: (index, error) => {
2148
- console.error(`[EnhancedSelect] Error in option ${index}:`, error);
2149
- this.dispatchEvent(new CustomEvent('option:mount-error', {
2150
- detail: { index, error },
2151
- bubbles: true,
2152
- composed: true
2153
- }));
2154
- }
2155
- };
2156
- this._optionRenderer = new OptionRenderer(rendererConfig);
2157
- console.log('[EnhancedSelect] Option renderer initialized with config:', rendererConfig);
2158
- }
2159
2065
  async _loadInitialSelectedItems() {
2160
2066
  if (!this._config.serverSide.fetchSelectedItems || !this._config.serverSide.initialSelectedValues) {
2161
2067
  return;
@@ -2371,13 +2277,31 @@
2371
2277
  const options = Array.from(this._optionsContainer.children);
2372
2278
  // Clear previous active state
2373
2279
  if (this._state.activeIndex >= 0 && options[this._state.activeIndex]) {
2374
- options[this._state.activeIndex].setActive(false);
2280
+ const prevOption = options[this._state.activeIndex];
2281
+ // Check if it's a custom SelectOption or a lightweight DOM element
2282
+ if ('setActive' in prevOption && typeof prevOption.setActive === 'function') {
2283
+ prevOption.setActive(false);
2284
+ }
2285
+ else {
2286
+ // Lightweight option - remove active class
2287
+ prevOption.classList.remove('smilodon-option--active');
2288
+ prevOption.setAttribute('aria-selected', 'false');
2289
+ }
2375
2290
  }
2376
2291
  this._state.activeIndex = index;
2377
2292
  // Set new active state
2378
2293
  if (options[index]) {
2379
- options[index].setActive(true);
2380
- options[index].scrollIntoView({ block: 'nearest', behavior: 'smooth' });
2294
+ const option = options[index];
2295
+ // Check if it's a custom SelectOption or a lightweight DOM element
2296
+ if ('setActive' in option && typeof option.setActive === 'function') {
2297
+ option.setActive(true);
2298
+ }
2299
+ else {
2300
+ // Lightweight option - add active class
2301
+ option.classList.add('smilodon-option--active');
2302
+ option.setAttribute('aria-selected', 'true');
2303
+ }
2304
+ option.scrollIntoView({ block: 'nearest', behavior: 'smooth' });
2381
2305
  // Announce position for screen readers
2382
2306
  const total = options.length;
2383
2307
  this._announce(`Item ${index + 1} of ${total}`);
@@ -2410,10 +2334,23 @@
2410
2334
  return;
2411
2335
  }
2412
2336
  if (!this._state.selectedIndices.has(index)) {
2413
- const config = option.getConfig();
2414
- this._state.selectedIndices.add(index);
2415
- this._state.selectedItems.set(index, config.item);
2416
- option.setSelected(true);
2337
+ // Check if it's a custom SelectOption or a lightweight DOM element
2338
+ if ('getConfig' in option && typeof option.getConfig === 'function') {
2339
+ const config = option.getConfig();
2340
+ this._state.selectedIndices.add(index);
2341
+ this._state.selectedItems.set(index, config.item);
2342
+ option.setSelected(true);
2343
+ }
2344
+ else {
2345
+ // Lightweight option - get item from data attribute or state
2346
+ const item = this._state.loadedItems[index];
2347
+ if (item) {
2348
+ this._state.selectedIndices.add(index);
2349
+ this._state.selectedItems.set(index, item);
2350
+ option.classList.add('smilodon-option--selected');
2351
+ option.setAttribute('aria-selected', 'true');
2352
+ }
2353
+ }
2417
2354
  }
2418
2355
  });
2419
2356
  this._updateInputDisplay();
@@ -2656,27 +2593,21 @@
2656
2593
  * Set items to display in the select
2657
2594
  */
2658
2595
  setItems(items) {
2659
- console.log('[EnhancedSelect] setItems called with', items?.length || 0, 'items');
2660
- console.log('[EnhancedSelect] Items:', items);
2661
2596
  const previousLength = this._state.loadedItems.length;
2662
2597
  this._state.loadedItems = items;
2663
2598
  // If grouped items exist, flatten them to items
2664
2599
  if (this._state.groupedItems.length > 0) {
2665
2600
  this._state.loadedItems = this._state.groupedItems.flatMap(group => group.options);
2666
- console.log('[EnhancedSelect] Flattened grouped items to', this._state.loadedItems.length, 'items');
2667
2601
  }
2668
2602
  const newLength = this._state.loadedItems.length;
2669
- console.log('[EnhancedSelect] State.loadedItems updated:', previousLength, '→', newLength);
2670
2603
  // When infinite scroll is active (preserveScrollPosition = true),
2671
2604
  // we need to maintain scroll position during the update
2672
2605
  if (this._state.preserveScrollPosition && this._dropdown) {
2673
2606
  const targetScrollTop = this._state.lastScrollPosition;
2674
- console.log('[EnhancedSelect] Preserving scroll position:', targetScrollTop);
2675
2607
  // Only clear loading if we actually got more items
2676
2608
  if (newLength > previousLength) {
2677
2609
  this._state.isBusy = false;
2678
2610
  }
2679
- console.log('[EnhancedSelect] Calling _renderOptions (with scroll preservation)...');
2680
2611
  this._renderOptions();
2681
2612
  // Restore the exact scrollTop we had before loading
2682
2613
  // so the previously visible items stay in place and
@@ -2696,10 +2627,8 @@
2696
2627
  else {
2697
2628
  // Normal update - just render normally
2698
2629
  this._state.isBusy = false;
2699
- console.log('[EnhancedSelect] Calling _renderOptions (normal)...');
2700
2630
  this._renderOptions();
2701
2631
  }
2702
- console.log('[EnhancedSelect] setItems complete');
2703
2632
  }
2704
2633
  /**
2705
2634
  * Set grouped items
@@ -2863,26 +2792,11 @@
2863
2792
  * Render options based on current state
2864
2793
  */
2865
2794
  _renderOptions() {
2866
- console.log('[EnhancedSelect] _renderOptions called');
2867
- console.log('[EnhancedSelect] State:', {
2868
- loadedItems: this._state.loadedItems.length,
2869
- groupedItems: this._state.groupedItems.length,
2870
- isOpen: this._state.isOpen,
2871
- isSearching: this._state.isSearching,
2872
- searchQuery: this._state.searchQuery,
2873
- isBusy: this._state.isBusy
2874
- });
2875
2795
  // Cleanup observer
2876
2796
  if (this._loadMoreTrigger && this._intersectionObserver) {
2877
2797
  this._intersectionObserver.unobserve(this._loadMoreTrigger);
2878
2798
  }
2879
- // Cleanup all rendered options (including custom components)
2880
- if (this._optionRenderer) {
2881
- this._optionRenderer.unmountAll();
2882
- console.log('[EnhancedSelect] Unmounted all option components');
2883
- }
2884
2799
  // Clear options container
2885
- console.log('[EnhancedSelect] Clearing options container, previous children:', this._optionsContainer.children.length);
2886
2800
  this._optionsContainer.innerHTML = '';
2887
2801
  // Ensure dropdown only contains options container (cleanup legacy direct children)
2888
2802
  // We need to preserve optionsContainer, so we can't just clear dropdown.innerHTML
@@ -2895,7 +2809,6 @@
2895
2809
  // Ensure dropdown is visible if we are rendering options
2896
2810
  if (this._state.isOpen && this._dropdown.style.display === 'none') {
2897
2811
  this._dropdown.style.display = 'block';
2898
- console.log('[EnhancedSelect] Dropdown display set to block');
2899
2812
  }
2900
2813
  // Show searching state (exclusive state)
2901
2814
  if (this._state.isSearching) {
@@ -2903,7 +2816,6 @@
2903
2816
  searching.className = 'searching-state';
2904
2817
  searching.textContent = 'Searching...';
2905
2818
  this._optionsContainer.appendChild(searching);
2906
- console.log('[EnhancedSelect] Added searching state');
2907
2819
  return;
2908
2820
  }
2909
2821
  const getValue = this._config.serverSide.getValueFromItem || ((item) => item?.value ?? item);
@@ -2912,7 +2824,6 @@
2912
2824
  const query = this._state.searchQuery.toLowerCase();
2913
2825
  // Handle Grouped Items Rendering (when no search query)
2914
2826
  if (this._state.groupedItems.length > 0 && !query) {
2915
- console.log('[EnhancedSelect] Rendering grouped items:', this._state.groupedItems.length, 'groups');
2916
2827
  this._state.groupedItems.forEach(group => {
2917
2828
  const header = document.createElement('div');
2918
2829
  header.className = 'group-header';
@@ -2942,7 +2853,6 @@
2942
2853
  }
2943
2854
  else {
2944
2855
  // Normal rendering (flat list or filtered)
2945
- console.log('[EnhancedSelect] Rendering flat list:', this._state.loadedItems.length, 'items');
2946
2856
  let hasRenderedItems = false;
2947
2857
  this._state.loadedItems.forEach((item, index) => {
2948
2858
  // Apply filter if query exists
@@ -2959,7 +2869,6 @@
2959
2869
  hasRenderedItems = true;
2960
2870
  this._renderSingleOption(item, index, getValue, getLabel);
2961
2871
  });
2962
- console.log('[EnhancedSelect] Rendered', hasRenderedItems ? 'items' : 'no items');
2963
2872
  if (!hasRenderedItems && !this._state.isBusy) {
2964
2873
  const empty = document.createElement('div');
2965
2874
  empty.className = 'empty-state';
@@ -2970,7 +2879,6 @@
2970
2879
  empty.textContent = 'No options available';
2971
2880
  }
2972
2881
  this._optionsContainer.appendChild(empty);
2973
- console.log('[EnhancedSelect] Added empty state');
2974
2882
  }
2975
2883
  }
2976
2884
  // Append Busy Indicator if busy
@@ -2988,33 +2896,34 @@
2988
2896
  busyBucket.appendChild(message);
2989
2897
  }
2990
2898
  this._optionsContainer.appendChild(busyBucket);
2991
- console.log('[EnhancedSelect] Added busy bucket');
2992
2899
  }
2993
2900
  // Append Load More Trigger (Button or Sentinel) if enabled and not busy
2994
2901
  else if ((this._config.loadMore.enabled || this._config.infiniteScroll.enabled) && this._state.loadedItems.length > 0) {
2995
2902
  this._addLoadMoreTrigger();
2996
2903
  }
2997
- console.log('[EnhancedSelect] _renderOptions complete, optionsContainer children:', this._optionsContainer.children.length);
2998
2904
  }
2999
2905
  _renderSingleOption(item, index, getValue, getLabel) {
3000
- if (!this._optionRenderer) {
3001
- console.error('[EnhancedSelect] Option renderer not initialized');
3002
- return;
3003
- }
3004
- // Check if selected
2906
+ const option = document.createElement('div');
2907
+ option.className = 'option';
2908
+ option.id = `${this._uniqueId}-option-${index}`;
2909
+ const value = getValue(item);
2910
+ const label = getLabel(item);
2911
+ option.textContent = label;
2912
+ option.dataset.value = String(value);
2913
+ option.dataset.index = String(index); // Also useful for debugging/selectors
2914
+ // Check if selected using selectedItems map
3005
2915
  const isSelected = this._state.selectedIndices.has(index);
3006
- const isFocused = this._state.activeIndex === index;
3007
- console.log('[EnhancedSelect] Rendering option', index, ':', {
3008
- value: getValue(item),
3009
- label: getLabel(item),
3010
- isSelected,
3011
- isFocused,
3012
- hasCustomComponent: !!item.optionComponent
2916
+ if (isSelected) {
2917
+ option.classList.add('selected');
2918
+ option.setAttribute('aria-selected', 'true');
2919
+ }
2920
+ else {
2921
+ option.setAttribute('aria-selected', 'false');
2922
+ }
2923
+ option.addEventListener('click', () => {
2924
+ this._selectOption(index);
3013
2925
  });
3014
- // Use the OptionRenderer to render both lightweight and custom component options
3015
- const optionElement = this._optionRenderer.render(item, index, isSelected, isFocused, this._uniqueId);
3016
- this._optionsContainer.appendChild(optionElement);
3017
- console.log('[EnhancedSelect] Option', index, 'appended to optionsContainer');
2926
+ this._optionsContainer.appendChild(option);
3018
2927
  }
3019
2928
  _addLoadMoreTrigger() {
3020
2929
  const container = document.createElement('div');
@@ -3847,7 +3756,6 @@
3847
3756
  const start = performance.now();
3848
3757
  const result = await fn();
3849
3758
  const duration = performance.now() - start;
3850
- console.log(`[Perf] ${label}: ${duration.toFixed(2)}ms`);
3851
3759
  return { result, duration };
3852
3760
  }
3853
3761
  /**
@@ -3857,7 +3765,6 @@
3857
3765
  const start = performance.now();
3858
3766
  const result = fn();
3859
3767
  const duration = performance.now() - start;
3860
- console.log(`[Perf] ${label}: ${duration.toFixed(2)}ms`);
3861
3768
  return { result, duration };
3862
3769
  }
3863
3770