@smilodon/core 1.0.5 → 1.0.7

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
@@ -1485,7 +1485,6 @@
1485
1485
  this._input.addEventListener('input', (e) => {
1486
1486
  if (!this._config.searchable)
1487
1487
  return;
1488
- console.log('[EnhancedSelect] Input event fired', e.target.value);
1489
1488
  const query = e.target.value;
1490
1489
  this._handleSearch(query);
1491
1490
  });
@@ -1511,7 +1510,6 @@
1511
1510
  this._intersectionObserver = new IntersectionObserver((entries) => {
1512
1511
  entries.forEach((entry) => {
1513
1512
  if (entry.isIntersecting) {
1514
- console.log('[InfiniteScroll] Sentinel intersected. isBusy:', this._state.isBusy);
1515
1513
  if (!this._state.isBusy) {
1516
1514
  this._loadMoreItems();
1517
1515
  }
@@ -1603,7 +1601,6 @@
1603
1601
  }
1604
1602
  }
1605
1603
  _handleSearch(query) {
1606
- console.log('[EnhancedSelect] _handleSearch called with:', JSON.stringify(query));
1607
1604
  this._state.searchQuery = query;
1608
1605
  // Clear previous search timeout
1609
1606
  if (this._searchTimeout) {
@@ -1614,12 +1611,10 @@
1614
1611
  this._state.isSearching = false;
1615
1612
  // Ensure dropdown is open when searching
1616
1613
  if (!this._state.isOpen) {
1617
- console.log('[EnhancedSelect] Opening dropdown for search');
1618
1614
  this._handleOpen();
1619
1615
  }
1620
1616
  else {
1621
1617
  // Filter and render options immediately
1622
- console.log('[EnhancedSelect] Dropdown already open, re-rendering options');
1623
1618
  this._renderOptions();
1624
1619
  }
1625
1620
  // Get filtered items based on search query - searches ENTIRE phrase
@@ -1639,7 +1634,6 @@
1639
1634
  })
1640
1635
  : this._state.loadedItems;
1641
1636
  const count = filteredItems.length;
1642
- console.log(`[EnhancedSelect] Search results: ${count} items found for query "${searchQuery}"`);
1643
1637
  // Announce search results for accessibility
1644
1638
  if (searchQuery) {
1645
1639
  this._announce(`${count} result${count !== 1 ? 's' : ''} found for "${query}"`);
@@ -1920,32 +1914,49 @@
1920
1914
  return;
1921
1915
  const target = this._config.scrollToSelected.multiSelectTarget;
1922
1916
  const indices = Array.from(this._state.selectedIndices).sort((a, b) => a - b);
1923
- const targetIndex = target === 'first' ? indices[0] : indices[indices.length - 1];
1924
- // FIX: Find the option element by ID instead of index in children
1925
- // because children list might be filtered or reordered
1917
+ // For multi-select, find the closest selected item to the current scroll position
1918
+ let targetIndex;
1919
+ if (this._config.selection.mode === 'multi' && indices.length > 1) {
1920
+ // Calculate which selected item is closest to the center of the viewport
1921
+ const dropdownRect = this._dropdown.getBoundingClientRect();
1922
+ const viewportCenter = this._dropdown.scrollTop + (dropdownRect.height / 2);
1923
+ // Find the selected item closest to viewport center
1924
+ let closestIndex = indices[0];
1925
+ let closestDistance = Infinity;
1926
+ for (const index of indices) {
1927
+ const optionId = `${this._uniqueId}-option-${index}`;
1928
+ const option = this._optionsContainer.querySelector(`[id="${optionId}"]`);
1929
+ if (option) {
1930
+ const optionTop = option.offsetTop;
1931
+ const distance = Math.abs(optionTop - viewportCenter);
1932
+ if (distance < closestDistance) {
1933
+ closestDistance = distance;
1934
+ closestIndex = index;
1935
+ }
1936
+ }
1937
+ }
1938
+ targetIndex = closestIndex;
1939
+ }
1940
+ else {
1941
+ // For single select or only one selected item, use the configured target
1942
+ targetIndex = target === 'first' ? indices[0] : indices[indices.length - 1];
1943
+ }
1944
+ // Find and scroll to the target option
1926
1945
  const optionId = `${this._uniqueId}-option-${targetIndex}`;
1927
- // We need to search in shadow root or options container
1928
- // Since options are custom elements, we can find them by ID if we set it (we do)
1929
- // But wait, we set ID on the element instance, but is it in the DOM?
1930
- // If filtered out, it won't be in the DOM.
1931
- // If we are searching, we might not want to scroll to selected if it's not visible
1932
- // But if we just opened the dropdown, we usually want to see the selected item.
1933
- // If the selected item is filtered out, we can't scroll to it.
1934
- // Try to find the element in the options container
1935
- // Note: querySelector on shadowRoot works if we set the ID attribute
1936
- // In _renderOptions we set: option.id = ...
1937
1946
  const option = this._optionsContainer.querySelector(`[id="${optionId}"]`);
1938
1947
  if (option) {
1948
+ // Use smooth scrolling with center alignment for better UX
1939
1949
  option.scrollIntoView({
1940
1950
  block: this._config.scrollToSelected.block || 'center',
1941
1951
  behavior: 'smooth',
1942
1952
  });
1953
+ // Also set it as active for keyboard navigation
1954
+ this._setActive(targetIndex);
1943
1955
  }
1944
1956
  }
1945
1957
  async _loadMoreItems() {
1946
1958
  if (this._state.isBusy)
1947
1959
  return;
1948
- console.log('[InfiniteScroll] _loadMoreItems triggered');
1949
1960
  this._setBusy(true);
1950
1961
  // Save scroll position before loading
1951
1962
  if (this._dropdown) {
@@ -1959,7 +1970,6 @@
1959
1970
  try {
1960
1971
  // Emit event for parent to handle
1961
1972
  this._state.currentPage++;
1962
- console.log(`[InfiniteScroll] Emitting loadMore event for page ${this._state.currentPage}`);
1963
1973
  this._emit('loadMore', { page: this._state.currentPage, items: [] });
1964
1974
  this._config.callbacks.onLoadMore?.(this._state.currentPage);
1965
1975
  // NOTE: We do NOT set isBusy = false here.
@@ -2014,14 +2024,6 @@
2014
2024
  // we need to maintain scroll position during the update
2015
2025
  if (this._state.preserveScrollPosition && this._dropdown) {
2016
2026
  const targetScrollTop = this._state.lastScrollPosition;
2017
- console.log('[InfiniteScroll] setItems: before render', {
2018
- previousLength,
2019
- newLength,
2020
- lastScrollPosition: this._state.lastScrollPosition,
2021
- scrollTop: this._dropdown.scrollTop,
2022
- scrollHeight: this._dropdown.scrollHeight,
2023
- clientHeight: this._dropdown.clientHeight
2024
- });
2025
2027
  // Only clear loading if we actually got more items
2026
2028
  if (newLength > previousLength) {
2027
2029
  this._state.isBusy = false;
@@ -2035,13 +2037,6 @@
2035
2037
  requestAnimationFrame(() => {
2036
2038
  if (this._dropdown) {
2037
2039
  this._dropdown.scrollTop = targetScrollTop;
2038
- console.log('[InfiniteScroll] setItems: after render', {
2039
- newLength,
2040
- lastScrollPosition: this._state.lastScrollPosition,
2041
- scrollTop: this._dropdown.scrollTop,
2042
- scrollHeight: this._dropdown.scrollHeight,
2043
- clientHeight: this._dropdown.clientHeight
2044
- });
2045
2040
  }
2046
2041
  });
2047
2042
  // Only clear preserveScrollPosition if we got new items
@@ -2217,7 +2212,6 @@
2217
2212
  * Render options based on current state
2218
2213
  */
2219
2214
  _renderOptions() {
2220
- console.log('[EnhancedSelect] _renderOptions called');
2221
2215
  // Cleanup observer
2222
2216
  if (this._loadMoreTrigger && this._intersectionObserver) {
2223
2217
  this._intersectionObserver.unobserve(this._loadMoreTrigger);
@@ -2373,7 +2367,6 @@
2373
2367
  this._optionsContainer.appendChild(container);
2374
2368
  // Setup intersection observer for auto-load
2375
2369
  if (this._intersectionObserver && this._loadMoreTrigger) {
2376
- console.log('[InfiniteScroll] Observing sentinel');
2377
2370
  this._intersectionObserver.observe(this._loadMoreTrigger);
2378
2371
  }
2379
2372
  }