@smilodon/core 1.4.13 → 1.5.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.
package/dist/index.cjs CHANGED
@@ -1350,9 +1350,21 @@ const defaultConfig = {
1350
1350
  allowDeselect: false,
1351
1351
  maxSelections: 0,
1352
1352
  showRemoveButton: true,
1353
+ removeButtonIcon: '×',
1353
1354
  closeOnSelect: true,
1354
1355
  toggleOnTriggerClick: true,
1355
1356
  },
1357
+ direction: 'ltr',
1358
+ dropdownPlacement: {
1359
+ mode: 'bottom',
1360
+ },
1361
+ multiSelectDisplay: {
1362
+ mode: 'wrap',
1363
+ maxHeight: '160px',
1364
+ overflowX: 'hidden',
1365
+ overflowY: 'auto',
1366
+ dragScroll: true,
1367
+ },
1356
1368
  scrollToSelected: {
1357
1369
  enabled: true,
1358
1370
  multiSelectTarget: 'first',
@@ -1513,6 +1525,8 @@ class SelectOption extends HTMLElement {
1513
1525
  :host {
1514
1526
  display: block;
1515
1527
  position: relative;
1528
+ font: inherit;
1529
+ color: inherit;
1516
1530
  }
1517
1531
 
1518
1532
  /* Allow authors to style selected state from outside the shadow root
@@ -1544,7 +1558,7 @@ class SelectOption extends HTMLElement {
1544
1558
  display: flex;
1545
1559
  align-items: center;
1546
1560
  justify-content: space-between;
1547
- padding: var(--select-option-padding, 8px 12px);
1561
+ padding: var(--select-option-padding, 10px 14px);
1548
1562
  cursor: pointer;
1549
1563
  user-select: none;
1550
1564
  color: var(--select-option-color, var(--select-text-color, #1f2937));
@@ -1552,13 +1566,19 @@ class SelectOption extends HTMLElement {
1552
1566
  transition: var(--select-option-transition, background-color 0.2s ease);
1553
1567
  border: var(--select-option-border, none);
1554
1568
  border-bottom: var(--select-option-border-bottom, none);
1555
- border-radius: var(--select-option-border-radius, 0);
1569
+ border-radius: var(--select-option-border-radius, var(--select-radius-sm, 6px));
1556
1570
  box-shadow: var(--select-option-shadow, none);
1557
1571
  transform: var(--select-option-transform, none);
1572
+ font: inherit;
1558
1573
  }
1559
1574
 
1560
1575
  .option-container:hover {
1561
1576
  background: var(--select-option-hover-bg, #f0f0f0);
1577
+ color: var(--select-option-hover-color, var(--select-option-color, var(--select-text-color, #1f2937)));
1578
+ border: var(--select-option-hover-border, var(--select-option-border, none));
1579
+ border-bottom: var(--select-option-hover-border-bottom, var(--select-option-border-bottom, none));
1580
+ box-shadow: var(--select-option-hover-shadow, var(--select-option-shadow, none));
1581
+ transform: var(--select-option-hover-transform, var(--select-option-transform, none));
1562
1582
  }
1563
1583
 
1564
1584
  .option-container.selected {
@@ -1581,13 +1601,22 @@ class SelectOption extends HTMLElement {
1581
1601
  }
1582
1602
 
1583
1603
  .option-container.active {
1584
- outline: 2px solid var(--select-option-active-outline, #1976d2);
1585
- outline-offset: -2px;
1604
+ background: var(--select-option-active-bg, var(--select-option-hover-bg, #f0f0f0));
1605
+ color: var(--select-option-active-color, var(--select-option-hover-color, var(--select-option-color, var(--select-text-color, #1f2937))));
1606
+ border: var(--select-option-active-border, var(--select-option-hover-border, var(--select-option-border, none)));
1607
+ box-shadow: var(--select-option-active-shadow, var(--select-option-shadow, none));
1608
+ transform: var(--select-option-active-transform, var(--select-option-transform, none));
1609
+ outline: var(--select-option-active-outline, 2px solid #1976d2);
1610
+ outline-offset: var(--select-option-active-outline-offset, -2px);
1586
1611
  }
1587
1612
 
1588
1613
  .option-container.disabled {
1589
- opacity: 0.5;
1590
- cursor: not-allowed;
1614
+ background: var(--select-option-disabled-bg, var(--select-option-bg, var(--select-dropdown-bg, var(--select-bg, white))));
1615
+ color: var(--select-option-disabled-color, var(--select-option-color, var(--select-text-color, #1f2937)));
1616
+ border: var(--select-option-disabled-border, var(--select-option-border, none));
1617
+ border-bottom: var(--select-option-disabled-border-bottom, var(--select-option-border-bottom, none));
1618
+ opacity: var(--select-option-disabled-opacity, 0.5);
1619
+ cursor: var(--select-option-disabled-cursor, not-allowed);
1591
1620
  pointer-events: none;
1592
1621
  }
1593
1622
 
@@ -1604,6 +1633,12 @@ class SelectOption extends HTMLElement {
1604
1633
  color: var(--select-checkmark-color, currentColor);
1605
1634
  }
1606
1635
 
1636
+ :host([dir="rtl"]) .checkmark-icon,
1637
+ :host-context([dir="rtl"]) .checkmark-icon {
1638
+ margin-left: 0;
1639
+ margin-right: var(--select-checkmark-margin-left, 8px);
1640
+ }
1641
+
1607
1642
  :host([aria-selected="true"]) .checkmark-icon,
1608
1643
  .option-container.selected .checkmark-icon {
1609
1644
  display: inline-flex;
@@ -1611,20 +1646,49 @@ class SelectOption extends HTMLElement {
1611
1646
 
1612
1647
  .remove-button {
1613
1648
  margin-left: 8px;
1614
- padding: 2px 6px;
1649
+ width: var(--select-badge-remove-size, 18px);
1650
+ height: var(--select-badge-remove-size, 18px);
1651
+ min-width: var(--select-badge-remove-min-width, var(--select-badge-remove-size, 18px));
1652
+ min-height: var(--select-badge-remove-min-height, var(--select-badge-remove-size, 18px));
1653
+ padding: 0;
1615
1654
  border: none;
1616
- background-color: var(--select-remove-btn-bg, transparent);
1617
- color: var(--select-remove-btn-color, #666);
1655
+ background-color: var(--select-badge-remove-bg, rgba(255, 255, 255, 0.2));
1656
+ color: var(--select-badge-remove-color, currentColor);
1618
1657
  cursor: pointer;
1619
- border-radius: 3px;
1620
- font-size: 16px;
1658
+ border-radius: var(--select-badge-remove-radius, 50%);
1659
+ font-size: var(--select-badge-remove-font-size, 0.7333em);
1660
+ font-weight: var(--select-badge-remove-font-weight, 600);
1621
1661
  line-height: 1;
1662
+ display: inline-flex;
1663
+ align-items: center;
1664
+ justify-content: center;
1622
1665
  transition: all 0.2s ease;
1623
1666
  }
1667
+
1668
+ :host([dir="rtl"]) .remove-button,
1669
+ :host-context([dir="rtl"]) .remove-button {
1670
+ margin-left: 0;
1671
+ margin-right: 8px;
1672
+ }
1673
+
1674
+ .remove-button-icon {
1675
+ display: inline-flex;
1676
+ align-items: center;
1677
+ justify-content: center;
1678
+ width: var(--select-badge-remove-icon-size, 10px);
1679
+ height: var(--select-badge-remove-icon-size, 10px);
1680
+ pointer-events: none;
1681
+ }
1682
+
1683
+ .remove-button-icon svg {
1684
+ width: 100%;
1685
+ height: 100%;
1686
+ display: block;
1687
+ }
1624
1688
 
1625
1689
  .remove-button:hover {
1626
- background-color: var(--select-remove-btn-hover-bg, #ffebee);
1627
- color: var(--select-remove-btn-hover-color, #c62828);
1690
+ background-color: var(--select-badge-remove-hover-bg, #ffebee);
1691
+ color: var(--select-badge-remove-hover-color, #c62828);
1628
1692
  }
1629
1693
 
1630
1694
  .remove-button:focus {
@@ -1711,10 +1775,22 @@ class SelectOption extends HTMLElement {
1711
1775
  if (showRemoveButton && selected) {
1712
1776
  this._removeButton = document.createElement('button');
1713
1777
  this._removeButton.className = 'remove-button';
1714
- this._removeButton.innerHTML = '×';
1715
1778
  this._removeButton.setAttribute('part', 'chip-remove');
1716
1779
  this._removeButton.setAttribute('aria-label', 'Remove option');
1717
1780
  this._removeButton.setAttribute('type', 'button');
1781
+ const removeIcon = document.createElement('span');
1782
+ removeIcon.className = 'remove-button-icon';
1783
+ removeIcon.setAttribute('part', 'chip-remove-icon');
1784
+ const iconMarkup = this._config.removeButtonIcon && this._config.removeButtonIcon.trim()
1785
+ ? this._config.removeButtonIcon
1786
+ : '×';
1787
+ if (iconMarkup.trim().startsWith('<')) {
1788
+ removeIcon.innerHTML = iconMarkup;
1789
+ }
1790
+ else {
1791
+ removeIcon.textContent = iconMarkup;
1792
+ }
1793
+ this._removeButton.appendChild(removeIcon);
1718
1794
  this._container.appendChild(this._removeButton);
1719
1795
  }
1720
1796
  // Set ARIA attributes and State attributes on Host
@@ -1935,6 +2011,16 @@ class EnhancedSelect extends HTMLElement {
1935
2011
  this._tracking = { events: [], styles: [], limitations: [] };
1936
2012
  this._suppressBlurClose = false;
1937
2013
  this._renderCycleId = 0;
2014
+ this._suppressNextOpenClick = false;
2015
+ this._resolvedDropdownPlacement = 'bottom';
2016
+ this._multiScrollDrag = {
2017
+ active: false,
2018
+ moved: false,
2019
+ pointerId: -1,
2020
+ startX: 0,
2021
+ startScrollLeft: 0,
2022
+ };
2023
+ this._liftedAncestors = [];
1938
2024
  this._shadow = this.attachShadow({ mode: 'open' });
1939
2025
  this._uniqueId = `enhanced-select-${Math.random().toString(36).substr(2, 9)}`;
1940
2026
  this._rendererHelpers = this._buildRendererHelpers();
@@ -1962,6 +2048,7 @@ class EnhancedSelect extends HTMLElement {
1962
2048
  // Create DOM structure
1963
2049
  this._container = this._createContainer();
1964
2050
  this._inputContainer = this._createInputContainer();
2051
+ this._inputContent = this._createInputContent();
1965
2052
  this._input = this._createInput();
1966
2053
  this._arrowContainer = this._createArrowContainer();
1967
2054
  this._clearControl = this._createClearControl();
@@ -1970,6 +2057,8 @@ class EnhancedSelect extends HTMLElement {
1970
2057
  this._liveRegion = this._createLiveRegion();
1971
2058
  // Initialize styles BEFORE assembling DOM (order matters in shadow DOM)
1972
2059
  this._initializeStyles();
2060
+ this._syncStyleConfigVariables();
2061
+ this._syncDirectionConfig();
1973
2062
  this._assembleDOM();
1974
2063
  this._attachEventListeners();
1975
2064
  this._initializeObservers();
@@ -2005,6 +2094,7 @@ class EnhancedSelect extends HTMLElement {
2005
2094
  clearTimeout(this._typeTimeout);
2006
2095
  if (this._searchTimeout)
2007
2096
  clearTimeout(this._searchTimeout);
2097
+ this._endMultiScrollDrag();
2008
2098
  // Cleanup arrow click listener
2009
2099
  if (this._boundArrowClick && this._arrowContainer) {
2010
2100
  this._arrowContainer.removeEventListener('click', this._boundArrowClick);
@@ -2138,6 +2228,203 @@ class EnhancedSelect extends HTMLElement {
2138
2228
  }
2139
2229
  return container;
2140
2230
  }
2231
+ _createInputContent() {
2232
+ const content = document.createElement('div');
2233
+ content.className = 'input-content';
2234
+ return content;
2235
+ }
2236
+ _setCssVariable(name, value) {
2237
+ if (value == null || value === '') {
2238
+ this.style.removeProperty(name);
2239
+ return;
2240
+ }
2241
+ this.style.setProperty(name, String(value));
2242
+ }
2243
+ _applyStyleVariableMap(styleConfig, variableMap) {
2244
+ Object.entries(variableMap).forEach(([styleKey, variableName]) => {
2245
+ this._setCssVariable(variableName, styleConfig?.[styleKey]);
2246
+ });
2247
+ }
2248
+ _syncStyleConfigVariables() {
2249
+ const styles = this._config.styles;
2250
+ this._applyStyleVariableMap(styles.option, {
2251
+ background: '--select-option-bg',
2252
+ backgroundColor: '--select-option-bg',
2253
+ color: '--select-option-color',
2254
+ border: '--select-option-border',
2255
+ borderBottom: '--select-option-border-bottom',
2256
+ borderRadius: '--select-option-border-radius',
2257
+ boxShadow: '--select-option-shadow',
2258
+ transform: '--select-option-transform',
2259
+ padding: '--select-option-padding',
2260
+ margin: '--select-option-margin',
2261
+ fontSize: '--select-option-font-size',
2262
+ fontWeight: '--select-option-font-weight',
2263
+ lineHeight: '--select-option-line-height',
2264
+ textAlign: '--select-option-text-align',
2265
+ });
2266
+ this._applyStyleVariableMap(styles.selectedOption, {
2267
+ background: '--select-option-selected-bg',
2268
+ backgroundColor: '--select-option-selected-bg',
2269
+ color: '--select-option-selected-color',
2270
+ border: '--select-option-selected-border',
2271
+ borderBottom: '--select-option-selected-border-bottom',
2272
+ borderRadius: '--select-option-selected-border-radius',
2273
+ boxShadow: '--select-option-selected-shadow',
2274
+ transform: '--select-option-selected-transform',
2275
+ fontWeight: '--select-option-selected-weight',
2276
+ });
2277
+ this._applyStyleVariableMap(styles.hoverOption, {
2278
+ background: '--select-option-hover-bg',
2279
+ backgroundColor: '--select-option-hover-bg',
2280
+ color: '--select-option-hover-color',
2281
+ border: '--select-option-hover-border',
2282
+ borderBottom: '--select-option-hover-border-bottom',
2283
+ boxShadow: '--select-option-hover-shadow',
2284
+ transform: '--select-option-hover-transform',
2285
+ });
2286
+ this._applyStyleVariableMap(styles.activeOption, {
2287
+ background: '--select-option-active-bg',
2288
+ backgroundColor: '--select-option-active-bg',
2289
+ color: '--select-option-active-color',
2290
+ border: '--select-option-active-border',
2291
+ outline: '--select-option-active-outline',
2292
+ outlineOffset: '--select-option-active-outline-offset',
2293
+ boxShadow: '--select-option-active-shadow',
2294
+ transform: '--select-option-active-transform',
2295
+ });
2296
+ this._applyStyleVariableMap(styles.disabledOption, {
2297
+ background: '--select-option-disabled-bg',
2298
+ backgroundColor: '--select-option-disabled-bg',
2299
+ color: '--select-option-disabled-color',
2300
+ border: '--select-option-disabled-border',
2301
+ borderBottom: '--select-option-disabled-border-bottom',
2302
+ opacity: '--select-option-disabled-opacity',
2303
+ cursor: '--select-option-disabled-cursor',
2304
+ });
2305
+ this._applyStyleVariableMap(styles.badge, {
2306
+ width: '--select-badge-width',
2307
+ minWidth: '--select-badge-min-width',
2308
+ maxWidth: '--select-badge-max-width',
2309
+ height: '--select-badge-height',
2310
+ minHeight: '--select-badge-min-height',
2311
+ padding: '--select-badge-padding',
2312
+ margin: '--select-badge-margin',
2313
+ gap: '--select-badge-gap',
2314
+ background: '--select-badge-bg',
2315
+ backgroundColor: '--select-badge-bg',
2316
+ color: '--select-badge-color',
2317
+ border: '--select-badge-border',
2318
+ borderRadius: '--select-badge-border-radius',
2319
+ boxShadow: '--select-badge-shadow',
2320
+ fontSize: '--select-badge-font-size',
2321
+ fontWeight: '--select-badge-font-weight',
2322
+ lineHeight: '--select-badge-line-height',
2323
+ letterSpacing: '--select-badge-letter-spacing',
2324
+ });
2325
+ this._applyStyleVariableMap(styles.badgeHover, {
2326
+ background: '--select-badge-hover-bg',
2327
+ backgroundColor: '--select-badge-hover-bg',
2328
+ color: '--select-badge-hover-color',
2329
+ border: '--select-badge-hover-border',
2330
+ boxShadow: '--select-badge-hover-shadow',
2331
+ transform: '--select-badge-hover-transform',
2332
+ });
2333
+ this._applyStyleVariableMap(styles.badgeActive, {
2334
+ background: '--select-badge-active-bg',
2335
+ backgroundColor: '--select-badge-active-bg',
2336
+ color: '--select-badge-active-color',
2337
+ border: '--select-badge-active-border',
2338
+ boxShadow: '--select-badge-active-shadow',
2339
+ transform: '--select-badge-active-transform',
2340
+ });
2341
+ this._applyStyleVariableMap(styles.badgeLabel, {
2342
+ color: '--select-badge-label-color',
2343
+ fontSize: '--select-badge-label-font-size',
2344
+ fontWeight: '--select-badge-label-font-weight',
2345
+ lineHeight: '--select-badge-label-line-height',
2346
+ letterSpacing: '--select-badge-label-letter-spacing',
2347
+ textAlign: '--select-badge-label-text-align',
2348
+ });
2349
+ this._applyStyleVariableMap(styles.badgeRemove, {
2350
+ width: '--select-badge-remove-size',
2351
+ height: '--select-badge-remove-size',
2352
+ minWidth: '--select-badge-remove-min-width',
2353
+ minHeight: '--select-badge-remove-min-height',
2354
+ marginLeft: '--select-badge-remove-margin-left',
2355
+ background: '--select-badge-remove-bg',
2356
+ backgroundColor: '--select-badge-remove-bg',
2357
+ border: '--select-badge-remove-border',
2358
+ borderRadius: '--select-badge-remove-radius',
2359
+ color: '--select-badge-remove-color',
2360
+ fontSize: '--select-badge-remove-font-size',
2361
+ fontWeight: '--select-badge-remove-font-weight',
2362
+ });
2363
+ this._applyStyleVariableMap(styles.badgeRemoveHover, {
2364
+ background: '--select-badge-remove-hover-bg',
2365
+ backgroundColor: '--select-badge-remove-hover-bg',
2366
+ color: '--select-badge-remove-hover-color',
2367
+ border: '--select-badge-remove-hover-border',
2368
+ boxShadow: '--select-badge-remove-hover-shadow',
2369
+ transform: '--select-badge-remove-hover-transform',
2370
+ });
2371
+ this._applyStyleVariableMap(styles.badgeRemoveActive, {
2372
+ background: '--select-badge-remove-active-bg',
2373
+ backgroundColor: '--select-badge-remove-active-bg',
2374
+ color: '--select-badge-remove-active-color',
2375
+ border: '--select-badge-remove-active-border',
2376
+ boxShadow: '--select-badge-remove-active-shadow',
2377
+ transform: '--select-badge-remove-active-transform',
2378
+ });
2379
+ this._applyStyleVariableMap(styles.groupHeader, {
2380
+ padding: '--select-group-header-padding',
2381
+ margin: '--select-group-header-margin',
2382
+ color: '--select-group-header-color',
2383
+ background: '--select-group-header-bg',
2384
+ backgroundColor: '--select-group-header-bg',
2385
+ border: '--select-group-header-border',
2386
+ borderBottom: '--select-group-header-border-bottom',
2387
+ borderRadius: '--select-group-header-border-radius',
2388
+ boxShadow: '--select-group-header-shadow',
2389
+ textAlign: '--select-group-header-text-align',
2390
+ fontSize: '--select-group-header-font-size',
2391
+ fontWeight: '--select-group-header-weight',
2392
+ textTransform: '--select-group-header-text-transform',
2393
+ letterSpacing: '--select-group-header-letter-spacing',
2394
+ });
2395
+ }
2396
+ _resolveDropdownPlacement() {
2397
+ const placementMode = this._config.dropdownPlacement?.mode ?? 'bottom';
2398
+ if (placementMode === 'bottom' || placementMode === 'top') {
2399
+ return placementMode;
2400
+ }
2401
+ const hostRect = this._container.getBoundingClientRect();
2402
+ const availableBelow = window.innerHeight - hostRect.bottom;
2403
+ const computedDropdown = window.getComputedStyle(this._dropdown);
2404
+ const maxHeight = Number.parseFloat(computedDropdown.maxHeight || '0');
2405
+ const desiredHeight = Number.isFinite(maxHeight) && maxHeight > 0
2406
+ ? Math.min(this._dropdown.scrollHeight, maxHeight)
2407
+ : this._dropdown.scrollHeight;
2408
+ return availableBelow >= desiredHeight ? 'bottom' : 'top';
2409
+ }
2410
+ _syncDropdownPlacement() {
2411
+ if (!this._dropdown)
2412
+ return;
2413
+ this._resolvedDropdownPlacement = this._resolveDropdownPlacement();
2414
+ this._dropdown.setAttribute('data-placement', this._resolvedDropdownPlacement);
2415
+ }
2416
+ _syncDirectionConfig() {
2417
+ this.setAttribute('dir', this._config.direction ?? 'ltr');
2418
+ }
2419
+ _setIconContent(target, markup, fallback) {
2420
+ const content = markup && markup.trim() ? markup : fallback;
2421
+ target.innerHTML = '';
2422
+ if (content.trim().startsWith('<')) {
2423
+ target.innerHTML = content;
2424
+ return;
2425
+ }
2426
+ target.textContent = content;
2427
+ }
2141
2428
  _syncInputContainerMode() {
2142
2429
  if (!this._inputContainer || !this._input)
2143
2430
  return;
@@ -2154,6 +2441,121 @@ class EnhancedSelect extends HTMLElement {
2154
2441
  this._input.style.width = '100%';
2155
2442
  this._input.style.minWidth = '0';
2156
2443
  }
2444
+ this._syncMultiSelectDisplayConfig();
2445
+ }
2446
+ _syncMultiSelectDisplayConfig() {
2447
+ if (!this._inputContainer || !this._input)
2448
+ return;
2449
+ const isMulti = this._config.selection.mode === 'multi';
2450
+ const mode = this._config.multiSelectDisplay?.mode ?? 'wrap';
2451
+ const dragEnabled = this._config.multiSelectDisplay?.dragScroll !== false;
2452
+ if (!isMulti) {
2453
+ this._inputContainer.removeAttribute('data-multi-scroll-mode');
2454
+ this._inputContainer.removeAttribute('data-drag-scroll');
2455
+ this._inputContainer.classList.remove('is-dragging-scroll');
2456
+ this._inputContainer.style.removeProperty('--select-multi-input-max-height');
2457
+ this._inputContainer.style.removeProperty('--select-multi-input-overflow-x');
2458
+ this._inputContainer.style.removeProperty('--select-multi-input-overflow-y');
2459
+ this._inputContainer.style.removeProperty('--select-multi-input-flex-wrap');
2460
+ this._inputContainer.style.removeProperty('--select-multi-input-align-content');
2461
+ return;
2462
+ }
2463
+ const maxHeight = this._config.multiSelectDisplay?.maxHeight ?? '160px';
2464
+ const overflowX = this._config.multiSelectDisplay?.overflowX ?? (mode === 'horizontal' ? 'auto' : 'hidden');
2465
+ const overflowY = this._config.multiSelectDisplay?.overflowY ?? (mode === 'horizontal' ? 'hidden' : 'auto');
2466
+ const flexWrap = mode === 'horizontal' ? 'nowrap' : 'wrap';
2467
+ const alignContent = mode === 'horizontal' ? 'center' : 'flex-start';
2468
+ this._inputContainer.setAttribute('data-multi-scroll-mode', mode);
2469
+ this._inputContainer.setAttribute('data-drag-scroll', String(dragEnabled && mode === 'horizontal'));
2470
+ this._inputContainer.style.setProperty('--select-multi-input-max-height', maxHeight);
2471
+ this._inputContainer.style.setProperty('--select-multi-input-overflow-x', overflowX);
2472
+ this._inputContainer.style.setProperty('--select-multi-input-overflow-y', overflowY);
2473
+ this._inputContainer.style.setProperty('--select-multi-input-flex-wrap', flexWrap);
2474
+ this._inputContainer.style.setProperty('--select-multi-input-align-content', alignContent);
2475
+ }
2476
+ _canUseHorizontalMultiScroll(target) {
2477
+ if (this._config.selection.mode !== 'multi')
2478
+ return false;
2479
+ if ((this._config.multiSelectDisplay?.mode ?? 'wrap') !== 'horizontal')
2480
+ return false;
2481
+ if (this._config.multiSelectDisplay?.dragScroll === false)
2482
+ return false;
2483
+ if (!target)
2484
+ return true;
2485
+ if (target.closest('.dropdown-arrow-container, .clear-control-button, .badge-remove'))
2486
+ return false;
2487
+ if (target.matches('.select-input'))
2488
+ return false;
2489
+ return true;
2490
+ }
2491
+ _isScrollableMultiSelectMode() {
2492
+ if (this._config.selection.mode !== 'multi')
2493
+ return false;
2494
+ const mode = this._config.multiSelectDisplay?.mode ?? 'wrap';
2495
+ return mode === 'vertical' || mode === 'horizontal';
2496
+ }
2497
+ _isPointerOnInputScrollbar(event) {
2498
+ if (!this._isScrollableMultiSelectMode())
2499
+ return false;
2500
+ const rect = this._inputContent.getBoundingClientRect();
2501
+ const verticalScrollbarWidth = this._inputContent.offsetWidth - this._inputContent.clientWidth;
2502
+ const horizontalScrollbarHeight = this._inputContent.offsetHeight - this._inputContent.clientHeight;
2503
+ if (verticalScrollbarWidth > 0
2504
+ && event.clientX >= rect.right - verticalScrollbarWidth
2505
+ && event.clientX <= rect.right
2506
+ && event.clientY >= rect.top
2507
+ && event.clientY <= rect.bottom) {
2508
+ return true;
2509
+ }
2510
+ if (horizontalScrollbarHeight > 0
2511
+ && event.clientY >= rect.bottom - horizontalScrollbarHeight
2512
+ && event.clientY <= rect.bottom
2513
+ && event.clientX >= rect.left
2514
+ && event.clientX <= rect.right) {
2515
+ return true;
2516
+ }
2517
+ return false;
2518
+ }
2519
+ _beginMultiScrollDrag(e) {
2520
+ const scrollHost = this._inputContent;
2521
+ this._multiScrollDrag.active = true;
2522
+ this._multiScrollDrag.moved = false;
2523
+ this._multiScrollDrag.pointerId = e.pointerId;
2524
+ this._multiScrollDrag.startX = e.clientX;
2525
+ this._multiScrollDrag.startScrollLeft = scrollHost.scrollLeft;
2526
+ this._inputContainer.classList.add('is-dragging-scroll');
2527
+ try {
2528
+ scrollHost.setPointerCapture(e.pointerId);
2529
+ }
2530
+ catch (_error) {
2531
+ // ignore pointer capture issues
2532
+ }
2533
+ }
2534
+ _updateMultiScrollDrag(e) {
2535
+ if (!this._multiScrollDrag.active || this._multiScrollDrag.pointerId !== e.pointerId)
2536
+ return;
2537
+ const deltaX = e.clientX - this._multiScrollDrag.startX;
2538
+ if (Math.abs(deltaX) > 3) {
2539
+ this._multiScrollDrag.moved = true;
2540
+ }
2541
+ this._inputContent.scrollLeft = this._multiScrollDrag.startScrollLeft - deltaX;
2542
+ }
2543
+ _endMultiScrollDrag(pointerId) {
2544
+ if (!this._multiScrollDrag.active)
2545
+ return;
2546
+ if (pointerId != null && this._multiScrollDrag.pointerId !== pointerId)
2547
+ return;
2548
+ try {
2549
+ if (this._multiScrollDrag.pointerId >= 0) {
2550
+ this._inputContent.releasePointerCapture(this._multiScrollDrag.pointerId);
2551
+ }
2552
+ }
2553
+ catch (_error) {
2554
+ // ignore pointer capture issues
2555
+ }
2556
+ this._multiScrollDrag.active = false;
2557
+ this._multiScrollDrag.pointerId = -1;
2558
+ this._inputContainer.classList.remove('is-dragging-scroll');
2157
2559
  }
2158
2560
  _createInput() {
2159
2561
  const input = document.createElement('input');
@@ -2282,7 +2684,8 @@ class EnhancedSelect extends HTMLElement {
2282
2684
  return button;
2283
2685
  }
2284
2686
  _assembleDOM() {
2285
- this._inputContainer.appendChild(this._input);
2687
+ this._inputContent.appendChild(this._input);
2688
+ this._inputContainer.appendChild(this._inputContent);
2286
2689
  if (this._clearControl) {
2287
2690
  this._inputContainer.appendChild(this._clearControl);
2288
2691
  }
@@ -2339,9 +2742,11 @@ class EnhancedSelect extends HTMLElement {
2339
2742
  --select-badge-enter-from-transform: scale(0.8) translateY(-4px);
2340
2743
  --select-badge-enter-to-opacity: 1;
2341
2744
  --select-badge-enter-to-transform: scale(1) translateY(0);
2745
+ --select-badge-active-transform: scale(0.98);
2342
2746
  --select-badge-hover-transform: scale(1.02);
2343
2747
  --select-badge-letter-spacing: 0.01em;
2344
2748
  --select-badge-hover-shadow: var(--select-shadow-md), inset 0 1px 0 rgba(255, 255, 255, 0.15);
2749
+ --select-badge-remove-icon-size: 10px;
2345
2750
  --select-badge-remove-focus-outline: 2px solid rgba(255, 255, 255, 0.5);
2346
2751
  --select-badge-remove-focus-offset: 1px;
2347
2752
  --select-badge-remove-hover-transform: scale(1.15) rotate(90deg);
@@ -2351,8 +2756,25 @@ class EnhancedSelect extends HTMLElement {
2351
2756
  --select-input-font-weight: 450;
2352
2757
  --select-input-letter-spacing: 0.01em;
2353
2758
  --select-input-disabled-opacity: 0.6;
2759
+ --select-input-overflow-x: hidden;
2760
+ --select-input-align-items: center;
2761
+ --select-input-align-content: center;
2762
+ --select-input-align-self: center;
2763
+ --select-multi-input-max-height: 160px;
2764
+ --select-multi-input-overflow-x: hidden;
2765
+ --select-multi-input-overflow-y: auto;
2766
+ --select-multi-input-flex-wrap: wrap;
2767
+ --select-multi-input-align-content: flex-start;
2768
+ --select-multi-input-horizontal-input-flex: 0 0 var(--select-multi-input-min-width, 96px);
2769
+ --select-multi-input-horizontal-cursor: grab;
2770
+ --select-multi-input-horizontal-active-cursor: grabbing;
2771
+ --select-multi-separator-inset-block: 10px;
2772
+ --select-multi-action-surface-bg: var(--select-input-bg, var(--select-surface));
2773
+ --select-multi-action-divider: 1px solid var(--select-border);
2354
2774
  --select-separator-opacity: 0.6;
2355
2775
  --select-separator-active-opacity: 1;
2776
+ --select-separator-position: var(--select-arrow-width, 42px);
2777
+ --select-separator-position-with-clear: calc(var(--select-arrow-right-with-clear, 34px) + var(--select-arrow-width, 42px));
2356
2778
  --select-separator-dark-bg: linear-gradient(
2357
2779
  to bottom,
2358
2780
  transparent 0%,
@@ -2366,11 +2788,15 @@ class EnhancedSelect extends HTMLElement {
2366
2788
  --select-clear-button-focus-offset: 2px;
2367
2789
  --select-clear-icon-size: 14px;
2368
2790
  --select-dropdown-top: calc(100% + 6px);
2791
+ --select-dropdown-bottom: calc(100% + 6px);
2369
2792
  --select-dropdown-animation: dropdownEnter 200ms cubic-bezier(0.4, 0, 0.2, 1) forwards;
2370
2793
  --select-dropdown-enter-from-opacity: 0;
2371
2794
  --select-dropdown-enter-from-transform: translateY(-8px) scale(0.98);
2372
2795
  --select-dropdown-enter-to-opacity: 1;
2373
2796
  --select-dropdown-enter-to-transform: translateY(0) scale(1);
2797
+ --select-dropdown-top-transform-origin: bottom center;
2798
+ --select-dropdown-top-enter-from-transform: translateY(8px) scale(0.98);
2799
+ --select-dropdown-padding: 6px;
2374
2800
  --select-dropdown-scroll-behavior: smooth;
2375
2801
  --select-dropdown-transform-origin: top center;
2376
2802
  --select-scrollbar-width: 6px;
@@ -2378,6 +2804,8 @@ class EnhancedSelect extends HTMLElement {
2378
2804
  --select-option-hover-transform: translateX(2px);
2379
2805
  --select-option-font-weight: 450;
2380
2806
  --select-option-margin: 2px 0;
2807
+ --select-option-disabled-opacity: 0.5;
2808
+ --select-option-disabled-cursor: not-allowed;
2381
2809
  --select-option-active-outline-offset: -2px;
2382
2810
  --select-option-selected-active-outline-offset: -2px;
2383
2811
  --select-option-selected-indicator-width: 3px;
@@ -2419,12 +2847,31 @@ class EnhancedSelect extends HTMLElement {
2419
2847
  --select-high-contrast-focus-outline-color: Highlight;
2420
2848
  --select-touch-target-min-height: 44px;
2421
2849
  --select-badge-dark-bg: linear-gradient(135deg, var(--select-accent) 0%, #4f46e5 100%);
2850
+ --select-host-z-index: auto;
2851
+ --select-host-open-z-index: var(--select-dropdown-z-index, 1000);
2852
+ --select-ancestor-open-z-index: var(--select-host-open-z-index, var(--select-dropdown-z-index, 1000));
2422
2853
 
2423
2854
  display: block;
2424
2855
  position: relative;
2856
+ z-index: var(--select-host-z-index, auto);
2425
2857
  width: var(--select-width, 100%);
2426
2858
  height: var(--select-height, auto);
2427
- font-family: var(--select-font-family, 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif);
2859
+ font-family: var(--select-font-family, inherit);
2860
+ font-size: var(--select-font-size, inherit);
2861
+ line-height: var(--select-line-height, inherit);
2862
+ color: var(--select-color, inherit);
2863
+ }
2864
+
2865
+ :host([data-open="true"]) {
2866
+ z-index: var(--select-host-open-z-index, var(--select-dropdown-z-index, 1000));
2867
+ }
2868
+
2869
+ :host([dir="ltr"]) {
2870
+ direction: ltr;
2871
+ }
2872
+
2873
+ :host([dir="rtl"]) {
2874
+ direction: rtl;
2428
2875
  }
2429
2876
 
2430
2877
  /* ─────────────────────────────────────────────────────────────────────────
@@ -2436,6 +2883,9 @@ class EnhancedSelect extends HTMLElement {
2436
2883
  align-items: center;
2437
2884
  gap: var(--select-badge-gap, 6px);
2438
2885
  flex: 0 1 auto;
2886
+ width: var(--select-badge-width, auto);
2887
+ min-width: var(--select-badge-min-width, 0);
2888
+ height: var(--select-badge-height, auto);
2439
2889
  min-height: var(--select-badge-min-height, 26px);
2440
2890
  padding: var(--select-badge-padding, 4px 10px 4px 12px);
2441
2891
  margin: var(--select-badge-margin, 3px);
@@ -2445,7 +2895,7 @@ class EnhancedSelect extends HTMLElement {
2445
2895
  border-radius: var(--select-badge-border-radius, 999px);
2446
2896
  box-shadow: var(--select-badge-shadow, var(--select-shadow-sm), inset 0 1px 0 rgba(255, 255, 255, 0.1));
2447
2897
  box-sizing: border-box;
2448
- font-size: var(--select-badge-font-size, 13px);
2898
+ font-size: var(--select-badge-font-size, 0.8667em);
2449
2899
  font-weight: var(--select-badge-font-weight, 500);
2450
2900
  line-height: var(--select-badge-line-height, 1.2);
2451
2901
  letter-spacing: var(--select-badge-letter-spacing);
@@ -2471,17 +2921,33 @@ class EnhancedSelect extends HTMLElement {
2471
2921
  }
2472
2922
 
2473
2923
  .selection-badge:hover {
2924
+ background: var(--select-badge-hover-bg, var(--select-badge-bg, linear-gradient(135deg, var(--select-accent) 0%, var(--select-primary-light) 100%)));
2925
+ color: var(--select-badge-hover-color, var(--select-badge-color, #ffffff));
2926
+ border: var(--select-badge-hover-border, var(--select-badge-border, none));
2474
2927
  box-shadow: var(--select-badge-hover-shadow);
2475
2928
  transform: var(--select-badge-hover-transform);
2476
2929
  }
2477
2930
 
2931
+ .selection-badge:active {
2932
+ background: var(--select-badge-active-bg, var(--select-badge-hover-bg, var(--select-badge-bg, linear-gradient(135deg, var(--select-accent) 0%, var(--select-primary-light) 100%))));
2933
+ color: var(--select-badge-active-color, var(--select-badge-hover-color, var(--select-badge-color, #ffffff)));
2934
+ border: var(--select-badge-active-border, var(--select-badge-hover-border, var(--select-badge-border, none)));
2935
+ box-shadow: var(--select-badge-active-shadow, var(--select-badge-hover-shadow));
2936
+ transform: var(--select-badge-active-transform);
2937
+ }
2938
+
2478
2939
  .selection-badge-label {
2479
2940
  display: block;
2480
2941
  min-width: 0;
2481
2942
  overflow: hidden;
2482
2943
  text-overflow: ellipsis;
2483
2944
  white-space: nowrap;
2484
- line-height: var(--select-badge-line-height, 1.2);
2945
+ color: var(--select-badge-label-color, inherit);
2946
+ font-size: var(--select-badge-label-font-size, inherit);
2947
+ font-weight: var(--select-badge-label-font-weight, inherit);
2948
+ line-height: var(--select-badge-label-line-height, var(--select-badge-line-height, 1.2));
2949
+ letter-spacing: var(--select-badge-label-letter-spacing, inherit);
2950
+ text-align: var(--select-badge-label-text-align, start);
2485
2951
  }
2486
2952
 
2487
2953
  .badge-remove {
@@ -2490,24 +2956,47 @@ class EnhancedSelect extends HTMLElement {
2490
2956
  justify-content: center;
2491
2957
  width: var(--select-badge-remove-size, 18px);
2492
2958
  height: var(--select-badge-remove-size, 18px);
2959
+ min-width: var(--select-badge-remove-min-width, var(--select-badge-remove-size, 18px));
2960
+ min-height: var(--select-badge-remove-min-height, var(--select-badge-remove-size, 18px));
2493
2961
  padding: 0;
2494
2962
  margin-left: var(--select-badge-remove-margin-left);
2495
2963
  background: var(--select-badge-remove-bg, rgba(255, 255, 255, 0.2));
2496
2964
  border: var(--select-badge-remove-border, none);
2497
2965
  border-radius: var(--select-badge-remove-radius);
2498
2966
  color: var(--select-badge-remove-color, #ffffff);
2499
- font-size: var(--select-badge-remove-font-size, 11px);
2967
+ font-size: var(--select-badge-remove-font-size, 0.7333em);
2500
2968
  font-weight: var(--select-badge-remove-font-weight);
2501
2969
  line-height: 1;
2502
2970
  cursor: pointer;
2503
2971
  flex: 0 0 auto;
2504
2972
  transition:
2505
2973
  background var(--select-transition-fast),
2974
+ color var(--select-transition-fast),
2975
+ border-color var(--select-transition-fast),
2976
+ box-shadow var(--select-transition-fast),
2506
2977
  transform var(--select-transition-bounce);
2507
2978
  }
2979
+
2980
+ .badge-remove-icon {
2981
+ display: inline-flex;
2982
+ align-items: center;
2983
+ justify-content: center;
2984
+ width: var(--select-badge-remove-icon-size, 10px);
2985
+ height: var(--select-badge-remove-icon-size, 10px);
2986
+ pointer-events: none;
2987
+ }
2988
+
2989
+ .badge-remove-icon svg {
2990
+ width: 100%;
2991
+ height: 100%;
2992
+ display: block;
2993
+ }
2508
2994
 
2509
2995
  .badge-remove:hover {
2510
2996
  background: var(--select-badge-remove-hover-bg, rgba(233, 69, 96, 0.9));
2997
+ color: var(--select-badge-remove-hover-color, var(--select-badge-remove-color, #ffffff));
2998
+ border: var(--select-badge-remove-hover-border, var(--select-badge-remove-border, none));
2999
+ box-shadow: var(--select-badge-remove-hover-shadow, none);
2511
3000
  transform: var(--select-badge-remove-hover-transform);
2512
3001
  }
2513
3002
 
@@ -2517,8 +3006,17 @@ class EnhancedSelect extends HTMLElement {
2517
3006
  }
2518
3007
 
2519
3008
  .badge-remove:active {
3009
+ background: var(--select-badge-remove-active-bg, var(--select-badge-remove-hover-bg, rgba(233, 69, 96, 0.9)));
3010
+ color: var(--select-badge-remove-active-color, var(--select-badge-remove-hover-color, var(--select-badge-remove-color, #ffffff)));
3011
+ border: var(--select-badge-remove-active-border, var(--select-badge-remove-hover-border, var(--select-badge-remove-border, none)));
3012
+ box-shadow: var(--select-badge-remove-active-shadow, var(--select-badge-remove-hover-shadow, none));
2520
3013
  transform: var(--select-badge-remove-active-transform);
2521
3014
  }
3015
+
3016
+ :host([dir="rtl"]) .badge-remove {
3017
+ margin-left: 0;
3018
+ margin-right: var(--select-badge-remove-margin-left);
3019
+ }
2522
3020
 
2523
3021
  /* ─────────────────────────────────────────────────────────────────────────
2524
3022
  Input Container — Sophisticated control shell
@@ -2533,15 +3031,17 @@ class EnhancedSelect extends HTMLElement {
2533
3031
  position: relative;
2534
3032
  width: 100%;
2535
3033
  display: flex;
2536
- align-items: center;
3034
+ align-items: var(--select-input-align-items, center);
2537
3035
  flex-wrap: nowrap;
3036
+ justify-content: var(--select-input-justify-content, flex-start);
2538
3037
  gap: var(--select-input-gap, 6px);
2539
3038
  padding: var(--select-input-padding, 10px 52px 10px 14px);
2540
3039
  height: var(--select-input-height, auto);
2541
3040
  min-height: var(--select-input-min-height, 48px);
2542
3041
  max-height: var(--select-input-max-height, 160px);
2543
- overflow-y: var(--select-input-overflow-y, auto);
2544
- align-content: center;
3042
+ overflow: hidden;
3043
+ align-content: var(--select-input-align-content, center);
3044
+ text-align: var(--select-input-text-align, start);
2545
3045
  background: var(--select-input-bg, var(--select-surface));
2546
3046
  border: var(--select-input-border, 1.5px solid var(--select-border));
2547
3047
  border-radius: var(--select-input-border-radius, var(--select-radius-md));
@@ -2552,6 +3052,25 @@ class EnhancedSelect extends HTMLElement {
2552
3052
  box-shadow var(--select-transition-smooth),
2553
3053
  transform var(--select-transition-fast);
2554
3054
  }
3055
+
3056
+ .input-content {
3057
+ position: relative;
3058
+ display: flex;
3059
+ flex: 1 1 auto;
3060
+ width: 100%;
3061
+ min-width: 0;
3062
+ min-height: 0;
3063
+ align-self: stretch;
3064
+ align-items: var(--select-input-align-items, center);
3065
+ align-content: var(--select-input-align-content, center);
3066
+ justify-content: var(--select-input-justify-content, flex-start);
3067
+ flex-wrap: nowrap;
3068
+ gap: var(--select-input-gap, 6px);
3069
+ overflow-x: var(--select-input-overflow-x, hidden);
3070
+ overflow-y: var(--select-input-overflow-y, hidden);
3071
+ scrollbar-width: thin;
3072
+ box-sizing: border-box;
3073
+ }
2555
3074
 
2556
3075
  .input-container:hover {
2557
3076
  border-color: var(--select-input-hover-border);
@@ -2564,8 +3083,75 @@ class EnhancedSelect extends HTMLElement {
2564
3083
  }
2565
3084
 
2566
3085
  .input-container.input-container--multi {
2567
- flex-wrap: wrap;
2568
- align-content: flex-start;
3086
+ max-height: var(--select-multi-input-max-height, var(--select-input-max-height, 160px));
3087
+ }
3088
+
3089
+ .input-container.input-container--multi .input-content {
3090
+ flex-wrap: var(--select-multi-input-flex-wrap, wrap);
3091
+ align-content: var(--select-multi-input-align-content, flex-start);
3092
+ overflow-x: var(--select-multi-input-overflow-x, hidden);
3093
+ overflow-y: var(--select-multi-input-overflow-y, auto);
3094
+ }
3095
+
3096
+ .input-container.input-container--multi::after {
3097
+ top: var(--select-multi-separator-inset-block, 10px);
3098
+ bottom: var(--select-multi-separator-inset-block, 10px);
3099
+ height: auto;
3100
+ transform: none;
3101
+ }
3102
+
3103
+ .input-container.input-container--multi[data-multi-scroll-mode="horizontal"] {
3104
+ align-items: stretch;
3105
+ }
3106
+
3107
+ .input-container.input-container--multi[data-multi-scroll-mode="horizontal"] .input-content {
3108
+ cursor: var(--select-multi-input-horizontal-cursor, grab);
3109
+ overflow-y: hidden;
3110
+ overscroll-behavior-x: contain;
3111
+ }
3112
+
3113
+ .input-container.input-container--multi[data-multi-scroll-mode="horizontal"]::after {
3114
+ display: none;
3115
+ }
3116
+
3117
+ .input-container.input-container--multi[data-multi-scroll-mode="horizontal"].is-dragging-scroll .input-content {
3118
+ cursor: var(--select-multi-input-horizontal-active-cursor, grabbing);
3119
+ user-select: none;
3120
+ }
3121
+
3122
+ .input-container.input-container--multi[data-multi-scroll-mode="horizontal"] .input-content .selection-badge {
3123
+ flex: 0 0 auto;
3124
+ }
3125
+
3126
+ .input-container.input-container--multi[data-multi-scroll-mode="horizontal"] .input-content > .select-input,
3127
+ .input-container.input-container--multi[data-multi-scroll-mode="horizontal"] .input-content > input.select-input,
3128
+ .input-container.input-container--multi[data-multi-scroll-mode="horizontal"] .input-content > .select-input[type="text"] {
3129
+ flex: var(--select-multi-input-horizontal-input-flex, 0 0 var(--select-multi-input-min-width, 96px));
3130
+ }
3131
+
3132
+ .input-container.input-container--multi[data-multi-scroll-mode="horizontal"] .dropdown-arrow-container {
3133
+ background: var(--select-multi-action-surface-bg, var(--select-input-bg, var(--select-surface)));
3134
+ border-left: var(--select-multi-action-divider, 1px solid var(--select-border));
3135
+ z-index: 4;
3136
+ }
3137
+
3138
+ .input-container.input-container--multi[data-multi-scroll-mode="horizontal"] .dropdown-arrow-container.with-clear-control {
3139
+ right: var(--select-arrow-right-with-clear, 34px);
3140
+ }
3141
+
3142
+ :host([dir="rtl"]) .input-container.input-container--multi[data-multi-scroll-mode="horizontal"] .dropdown-arrow-container {
3143
+ border-left: none;
3144
+ border-right: var(--select-multi-action-divider, 1px solid var(--select-border));
3145
+ }
3146
+
3147
+ :host([dir="rtl"]) .input-container.input-container--multi[data-multi-scroll-mode="horizontal"] .dropdown-arrow-container.with-clear-control {
3148
+ right: auto;
3149
+ left: var(--select-arrow-right-with-clear, 34px);
3150
+ }
3151
+
3152
+ .input-container.input-container--multi[data-multi-scroll-mode="horizontal"] .clear-control-button {
3153
+ background: var(--select-multi-action-surface-bg, var(--select-input-bg, var(--select-surface)));
3154
+ z-index: 4;
2569
3155
  }
2570
3156
 
2571
3157
  .input-container:focus-within {
@@ -2578,7 +3164,7 @@ class EnhancedSelect extends HTMLElement {
2578
3164
  content: '';
2579
3165
  position: absolute;
2580
3166
  top: 50%;
2581
- right: var(--select-separator-position, 42px);
3167
+ right: var(--select-separator-position, var(--select-arrow-width, 42px));
2582
3168
  transform: translateY(-50%);
2583
3169
  width: var(--select-separator-width, 1px);
2584
3170
  height: var(--select-separator-height, 50%);
@@ -2599,6 +3185,11 @@ class EnhancedSelect extends HTMLElement {
2599
3185
  .input-container:focus-within::after {
2600
3186
  opacity: var(--select-separator-active-opacity);
2601
3187
  }
3188
+
3189
+ :host([dir="rtl"]) .input-container::after {
3190
+ right: auto;
3191
+ left: var(--select-separator-position, var(--select-arrow-width, 42px));
3192
+ }
2602
3193
 
2603
3194
  /* ─────────────────────────────────────────────────────────────────────────
2604
3195
  Dropdown Arrow — Smooth rotation with refined styling
@@ -2625,13 +3216,29 @@ class EnhancedSelect extends HTMLElement {
2625
3216
  }
2626
3217
 
2627
3218
  .input-container.has-clear-control::after {
2628
- right: var(--select-separator-position-with-clear, 74px);
3219
+ right: var(--select-separator-position-with-clear, calc(var(--select-arrow-right-with-clear, 34px) + var(--select-arrow-width, 42px)));
2629
3220
  }
2630
3221
 
2631
3222
  .dropdown-arrow-container.with-clear-control {
2632
3223
  right: var(--select-arrow-right-with-clear, 34px);
2633
3224
  }
2634
3225
 
3226
+ :host([dir="rtl"]) .dropdown-arrow-container {
3227
+ right: auto;
3228
+ left: 0;
3229
+ border-radius: var(--select-arrow-border-radius-rtl, var(--select-radius-md) 0 0 var(--select-radius-md));
3230
+ }
3231
+
3232
+ :host([dir="rtl"]) .input-container.has-clear-control::after {
3233
+ right: auto;
3234
+ left: var(--select-separator-position-with-clear, calc(var(--select-arrow-right-with-clear, 34px) + var(--select-arrow-width, 42px)));
3235
+ }
3236
+
3237
+ :host([dir="rtl"]) .dropdown-arrow-container.with-clear-control {
3238
+ right: auto;
3239
+ left: var(--select-arrow-right-with-clear, 34px);
3240
+ }
3241
+
2635
3242
  /* ─────────────────────────────────────────────────────────────────────────
2636
3243
  Clear Control — Minimal and elegant dismiss button
2637
3244
  ───────────────────────────────────────────────────────────────────────── */
@@ -2677,6 +3284,11 @@ class EnhancedSelect extends HTMLElement {
2677
3284
  display: none;
2678
3285
  }
2679
3286
 
3287
+ :host([dir="rtl"]) .clear-control-button {
3288
+ right: auto;
3289
+ left: var(--select-clear-button-right, 8px);
3290
+ }
3291
+
2680
3292
  .clear-control-icon {
2681
3293
  width: var(--select-clear-icon-size);
2682
3294
  height: var(--select-clear-icon-size);
@@ -2731,7 +3343,7 @@ class EnhancedSelect extends HTMLElement {
2731
3343
  padding: var(--select-input-field-padding, 0) !important;
2732
3344
  margin: 0 !important;
2733
3345
  border: 0 !important;
2734
- font-size: var(--select-input-font-size, 15px);
3346
+ font-size: var(--select-input-font-size, inherit);
2735
3347
  line-height: var(--select-input-line-height, 1.5);
2736
3348
  color: var(--select-input-color, var(--select-text));
2737
3349
  background: transparent !important;
@@ -2739,13 +3351,16 @@ class EnhancedSelect extends HTMLElement {
2739
3351
  outline: none !important;
2740
3352
  font-weight: var(--select-input-font-weight);
2741
3353
  letter-spacing: var(--select-input-letter-spacing);
2742
- align-self: center;
3354
+ font-family: var(--select-input-font-family, inherit);
3355
+ font-style: var(--select-input-font-style, normal);
3356
+ align-self: var(--select-input-align-self, center);
2743
3357
  appearance: none !important;
2744
3358
  -webkit-appearance: none !important;
2745
3359
  box-shadow: none !important;
2746
3360
  border-radius: 0 !important;
2747
3361
  overflow: hidden;
2748
3362
  text-overflow: ellipsis;
3363
+ text-align: var(--select-input-text-align, inherit);
2749
3364
  white-space: nowrap;
2750
3365
  }
2751
3366
 
@@ -2754,6 +3369,14 @@ class EnhancedSelect extends HTMLElement {
2754
3369
  font-weight: 400;
2755
3370
  }
2756
3371
 
3372
+ :host([dir="rtl"]) .input-container {
3373
+ padding: var(--select-input-padding-rtl, 10px 14px 10px 52px);
3374
+ }
3375
+
3376
+ :host([dir="rtl"]) .input-container.has-clear-control {
3377
+ padding: var(--select-input-padding-with-clear-rtl, 10px 14px 10px 84px);
3378
+ }
3379
+
2757
3380
  .input-container.input-container--multi > .select-input,
2758
3381
  .input-container.input-container--multi > input.select-input,
2759
3382
  .input-container.input-container--multi > .select-input[type="text"] {
@@ -2784,10 +3407,12 @@ class EnhancedSelect extends HTMLElement {
2784
3407
  position: absolute;
2785
3408
  scroll-behavior: var(--select-dropdown-scroll-behavior);
2786
3409
  top: var(--select-dropdown-top);
3410
+ bottom: auto;
2787
3411
  left: 0;
2788
3412
  right: 0;
2789
3413
  max-height: var(--select-dropdown-max-height, 320px);
2790
3414
  overflow: hidden;
3415
+ box-sizing: border-box;
2791
3416
  background: var(--select-dropdown-bg, var(--select-surface));
2792
3417
  border: 1px solid var(--select-dropdown-border, var(--select-border));
2793
3418
  border-radius: var(--select-dropdown-border-radius, var(--select-radius-lg));
@@ -2796,6 +3421,16 @@ class EnhancedSelect extends HTMLElement {
2796
3421
  transform-origin: var(--select-dropdown-transform-origin);
2797
3422
  animation: var(--select-dropdown-animation);
2798
3423
  }
3424
+
3425
+ .select-dropdown[data-placement="top"] {
3426
+ top: auto;
3427
+ bottom: var(--select-dropdown-bottom, calc(100% + 6px));
3428
+ transform-origin: var(--select-dropdown-top-transform-origin, bottom center);
3429
+ }
3430
+
3431
+ .select-dropdown[data-placement="top"] {
3432
+ --select-dropdown-enter-from-transform: var(--select-dropdown-top-enter-from-transform, translateY(8px) scale(0.98));
3433
+ }
2799
3434
 
2800
3435
  @keyframes dropdownEnter {
2801
3436
  0% {
@@ -2812,8 +3447,9 @@ class EnhancedSelect extends HTMLElement {
2812
3447
  position: relative;
2813
3448
  max-height: var(--select-options-max-height, 320px);
2814
3449
  overflow: auto;
2815
- padding: var(--select-options-padding, 6px);
2816
- background: var(--select-options-bg, var(--select-surface));
3450
+ box-sizing: border-box;
3451
+ padding: var(--select-options-padding, var(--select-dropdown-padding, 6px));
3452
+ background: var(--select-options-bg, var(--select-dropdown-bg, var(--select-surface)));
2817
3453
 
2818
3454
  /* Custom scrollbar styling */
2819
3455
  scrollbar-width: thin;
@@ -2843,17 +3479,21 @@ class EnhancedSelect extends HTMLElement {
2843
3479
 
2844
3480
  .group-header {
2845
3481
  padding: var(--select-group-header-padding, 10px 12px 6px);
3482
+ margin: var(--select-group-header-margin, 0);
2846
3483
  font-weight: var(--select-group-header-weight, 600);
2847
3484
  color: var(--select-group-header-color, var(--select-text-muted));
2848
3485
  background-color: var(--select-group-header-bg, var(--select-surface));
2849
3486
  text-align: var(--select-group-header-text-align, left);
2850
- font-size: var(--select-group-header-font-size, 11px);
3487
+ font-size: var(--select-group-header-font-size, 0.7333em);
2851
3488
  text-transform: var(--select-group-header-text-transform, uppercase);
2852
3489
  letter-spacing: var(--select-group-header-letter-spacing, 0.08em);
2853
3490
  position: sticky;
2854
3491
  top: 0;
2855
3492
  z-index: 1;
3493
+ border: var(--select-group-header-border, none);
2856
3494
  border-bottom: var(--select-group-header-border-bottom, none);
3495
+ border-radius: var(--select-group-header-border-radius, 0);
3496
+ box-shadow: var(--select-group-header-shadow, none);
2857
3497
  }
2858
3498
 
2859
3499
  .group-header:not(:first-child) {
@@ -2872,13 +3512,16 @@ class EnhancedSelect extends HTMLElement {
2872
3512
  cursor: pointer;
2873
3513
  color: var(--select-option-color, var(--select-text));
2874
3514
  background: var(--select-option-bg, transparent);
3515
+ border: var(--select-option-border, none);
3516
+ text-align: var(--select-option-text-align, start);
2875
3517
  transition:
2876
3518
  background var(--select-transition-fast),
2877
3519
  color var(--select-transition-fast),
3520
+ border-color var(--select-transition-fast),
2878
3521
  transform var(--select-transition-fast),
2879
3522
  box-shadow var(--select-transition-fast);
2880
3523
  user-select: none;
2881
- font-size: var(--select-option-font-size, 14px);
3524
+ font-size: var(--select-option-font-size, inherit);
2882
3525
  font-weight: var(--select-option-font-weight);
2883
3526
  line-height: var(--select-option-line-height, 1.5);
2884
3527
  border-radius: var(--select-option-border-radius, var(--select-radius-sm));
@@ -2887,12 +3530,14 @@ class EnhancedSelect extends HTMLElement {
2887
3530
 
2888
3531
  .option:hover {
2889
3532
  background: var(--select-option-hover-bg, var(--select-surface-elevated));
3533
+ border: var(--select-option-hover-border, var(--select-option-border, none));
2890
3534
  color: var(--select-option-hover-color, var(--select-text));
2891
3535
  transform: var(--select-option-hover-transform);
2892
3536
  }
2893
3537
 
2894
3538
  .option.selected {
2895
3539
  background: var(--select-option-selected-bg, linear-gradient(135deg, rgba(15, 52, 96, 0.08) 0%, rgba(15, 52, 96, 0.04) 100%));
3540
+ border: var(--select-option-selected-border, var(--select-option-border, none));
2896
3541
  color: var(--select-option-selected-color, var(--select-accent));
2897
3542
  font-weight: var(--select-option-selected-weight, 550);
2898
3543
  }
@@ -2909,6 +3554,12 @@ class EnhancedSelect extends HTMLElement {
2909
3554
  border-radius: var(--select-option-selected-indicator-radius);
2910
3555
  animation: var(--select-option-selected-indicator-animation);
2911
3556
  }
3557
+
3558
+ :host([dir="rtl"]) .option.selected::before {
3559
+ left: auto;
3560
+ right: var(--select-option-selected-indicator-right, var(--select-option-selected-indicator-left));
3561
+ border-radius: var(--select-option-selected-indicator-radius-rtl, 2px 0 0 2px);
3562
+ }
2912
3563
 
2913
3564
  @keyframes selectedIndicator {
2914
3565
  0% {
@@ -2922,13 +3573,19 @@ class EnhancedSelect extends HTMLElement {
2922
3573
  }
2923
3574
 
2924
3575
  .option.selected:hover {
2925
- background: var(--select-option-selected-hover-bg, linear-gradient(135deg, rgba(15, 52, 96, 0.12) 0%, rgba(15, 52, 96, 0.06) 100%));
3576
+ background: var(--select-option-selected-hover-bg, var(--select-option-selected-bg, linear-gradient(135deg, rgba(15, 52, 96, 0.12) 0%, rgba(15, 52, 96, 0.06) 100%)));
3577
+ border: var(--select-option-selected-hover-border, var(--select-option-selected-border, var(--select-option-hover-border, var(--select-option-border, none))));
3578
+ color: var(--select-option-selected-hover-color, var(--select-option-selected-color, var(--select-accent)));
2926
3579
  }
2927
3580
 
2928
3581
  .option.active:not(.selected) {
2929
3582
  background: var(--select-option-active-bg, var(--select-surface-elevated));
3583
+ color: var(--select-option-active-color, var(--select-option-hover-color, var(--select-option-color, var(--select-text))));
3584
+ border: var(--select-option-active-border, var(--select-option-hover-border, var(--select-option-border, none)));
2930
3585
  outline: var(--select-option-active-outline, 2px solid rgba(15, 52, 96, 0.3));
2931
3586
  outline-offset: var(--select-option-active-outline-offset);
3587
+ box-shadow: var(--select-option-active-shadow, none);
3588
+ transform: var(--select-option-active-transform, none);
2932
3589
  }
2933
3590
 
2934
3591
  .option.selected.active {
@@ -2936,6 +3593,14 @@ class EnhancedSelect extends HTMLElement {
2936
3593
  outline-offset: var(--select-option-selected-active-outline-offset);
2937
3594
  }
2938
3595
 
3596
+ .option.disabled {
3597
+ background: var(--select-option-disabled-bg, var(--select-option-bg, transparent));
3598
+ color: var(--select-option-disabled-color, var(--select-text-muted));
3599
+ border: var(--select-option-disabled-border, var(--select-option-border, none));
3600
+ opacity: var(--select-option-disabled-opacity, 0.5);
3601
+ cursor: var(--select-option-disabled-cursor, not-allowed);
3602
+ }
3603
+
2939
3604
  .option:active:not(.selected) {
2940
3605
  background: var(--select-option-pressed-bg, rgba(15, 52, 96, 0.08));
2941
3606
  transform: var(--select-option-pressed-transform);
@@ -2961,7 +3626,7 @@ class EnhancedSelect extends HTMLElement {
2961
3626
  color: var(--select-button-color, var(--select-accent));
2962
3627
  border-radius: var(--select-button-border-radius, var(--select-radius-md));
2963
3628
  cursor: pointer;
2964
- font-size: var(--select-button-font-size, 13px);
3629
+ font-size: var(--select-button-font-size, 0.8667em);
2965
3630
  font-weight: var(--select-button-font-weight);
2966
3631
  letter-spacing: var(--select-button-letter-spacing);
2967
3632
  transition:
@@ -2993,7 +3658,7 @@ class EnhancedSelect extends HTMLElement {
2993
3658
  text-align: center;
2994
3659
  color: var(--select-busy-color, var(--select-text-muted));
2995
3660
  background: var(--select-busy-bg, transparent);
2996
- font-size: var(--select-busy-font-size, 13px);
3661
+ font-size: var(--select-busy-font-size, 0.8667em);
2997
3662
  }
2998
3663
 
2999
3664
  .spinner {
@@ -3014,7 +3679,7 @@ class EnhancedSelect extends HTMLElement {
3014
3679
  padding: var(--select-empty-padding, 32px 24px);
3015
3680
  text-align: center;
3016
3681
  color: var(--select-empty-color, var(--select-text-muted));
3017
- font-size: var(--select-empty-font-size, 14px);
3682
+ font-size: var(--select-empty-font-size, 0.9333em);
3018
3683
  background: var(--select-empty-bg, transparent);
3019
3684
  display: flex;
3020
3685
  flex-direction: column;
@@ -3027,7 +3692,7 @@ class EnhancedSelect extends HTMLElement {
3027
3692
  padding: var(--select-searching-padding, 32px 24px);
3028
3693
  text-align: center;
3029
3694
  color: var(--select-searching-color, var(--select-accent));
3030
- font-size: var(--select-searching-font-size, 14px);
3695
+ font-size: var(--select-searching-font-size, 0.9333em);
3031
3696
  background: var(--select-searching-bg, transparent);
3032
3697
  display: flex;
3033
3698
  flex-direction: column;
@@ -3117,24 +3782,28 @@ class EnhancedSelect extends HTMLElement {
3117
3782
  --select-primary-light: #2a2a3e;
3118
3783
  --select-accent: #6366f1;
3119
3784
  --select-accent-hover: #f43f5e;
3120
- --select-surface: #1a1a2e;
3785
+ --select-surface: var(--select-dark-bg, #1a1a2e);
3121
3786
  --select-surface-elevated: #252540;
3122
- --select-border: #3f3f5a;
3787
+ --select-border: var(--select-dark-border, #3f3f5a);
3123
3788
  --select-border-focus: #6366f1;
3124
- --select-text: #f5f5f5;
3789
+ --select-text: var(--select-dark-text, #f5f5f5);
3125
3790
  --select-text-muted: #9ca3af;
3126
3791
  --select-text-placeholder: #6b7280;
3127
3792
  --select-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.2);
3128
3793
  --select-shadow-md: 0 4px 12px rgba(0, 0, 0, 0.3);
3129
3794
  --select-shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.4);
3130
3795
  --select-shadow-focus: 0 0 0 3px rgba(99, 102, 241, 0.25);
3796
+
3797
+ --select-dropdown-bg: var(--select-dark-dropdown-bg, var(--select-surface));
3131
3798
 
3132
- --select-option-bg: transparent;
3133
- --select-option-color: var(--select-text);
3134
- --select-option-hover-bg: var(--select-surface-elevated);
3135
- --select-option-hover-color: var(--select-text);
3136
- --select-option-selected-bg: linear-gradient(135deg, rgba(99, 102, 241, 0.15) 0%, rgba(99, 102, 241, 0.08) 100%);
3137
- --select-option-selected-color: #a5b4fc;
3799
+ --select-option-bg: var(--select-dark-option-bg, transparent);
3800
+ --select-option-color: var(--select-dark-option-color, var(--select-text));
3801
+ --select-option-hover-bg: var(--select-dark-option-hover-bg, var(--select-surface-elevated));
3802
+ --select-option-hover-color: var(--select-dark-option-hover-color, var(--select-text));
3803
+ --select-option-selected-bg: var(--select-dark-option-selected-bg, linear-gradient(135deg, rgba(99, 102, 241, 0.15) 0%, rgba(99, 102, 241, 0.08) 100%));
3804
+ --select-option-selected-color: var(--select-dark-option-selected-color, #a5b4fc);
3805
+ --select-option-selected-hover-bg: var(--select-dark-option-selected-hover-bg, var(--select-option-selected-bg));
3806
+ --select-option-selected-hover-color: var(--select-dark-option-selected-hover-color, var(--select-option-selected-color));
3138
3807
  }
3139
3808
 
3140
3809
  :host(.dark-mode) .input-container,
@@ -3177,7 +3846,7 @@ class EnhancedSelect extends HTMLElement {
3177
3846
  :host-context([darkmode]) .select-dropdown,
3178
3847
  :host-context([data-theme="dark"]) .select-dropdown,
3179
3848
  :host-context([theme="dark"]) .select-dropdown {
3180
- background: var(--select-surface);
3849
+ background: var(--select-dropdown-bg, var(--select-surface));
3181
3850
  border-color: var(--select-border);
3182
3851
  }
3183
3852
 
@@ -3192,7 +3861,7 @@ class EnhancedSelect extends HTMLElement {
3192
3861
  :host-context([darkmode]) .options-container,
3193
3862
  :host-context([data-theme="dark"]) .options-container,
3194
3863
  :host-context([theme="dark"]) .options-container {
3195
- background: var(--select-surface);
3864
+ background: var(--select-dropdown-bg, var(--select-surface));
3196
3865
  scrollbar-color: var(--select-border) transparent;
3197
3866
  }
3198
3867
 
@@ -3289,6 +3958,19 @@ class EnhancedSelect extends HTMLElement {
3289
3958
  return;
3290
3959
  if (target && target.closest('.clear-control-button'))
3291
3960
  return;
3961
+ if (this._isPointerOnInputScrollbar(e)) {
3962
+ this._suppressNextOpenClick = true;
3963
+ return;
3964
+ }
3965
+ const isHorizontalMultiMode = this._config.selection.mode === 'multi'
3966
+ && (this._config.multiSelectDisplay?.mode ?? 'wrap') === 'horizontal';
3967
+ const enableHorizontalDrag = this._canUseHorizontalMultiScroll(target);
3968
+ if (enableHorizontalDrag && e.button === 0) {
3969
+ this._beginMultiScrollDrag(e);
3970
+ this._suppressNextOpenClick = false;
3971
+ e.preventDefault();
3972
+ return;
3973
+ }
3292
3974
  // If we clicked the container, but not the input itself, we must prevent default
3293
3975
  // otherwise the browser moves focus from our input to the body, immediately triggering blur.
3294
3976
  if (target && !target.matches('.select-input')) {
@@ -3297,6 +3979,8 @@ class EnhancedSelect extends HTMLElement {
3297
3979
  const clickedInput = Boolean(target && target.matches('.select-input'));
3298
3980
  if (this._state.isOpen &&
3299
3981
  this._config.selection.toggleOnTriggerClick !== false &&
3982
+ !isHorizontalMultiMode &&
3983
+ !enableHorizontalDrag &&
3300
3984
  !(clickedInput && this._config.searchable)) {
3301
3985
  this._handleClose();
3302
3986
  return;
@@ -3319,6 +4003,47 @@ class EnhancedSelect extends HTMLElement {
3319
4003
  }
3320
4004
  }
3321
4005
  });
4006
+ this._inputContainer.addEventListener('click', (e) => {
4007
+ const target = e.target;
4008
+ const isHorizontalMultiMode = this._config.selection.mode === 'multi'
4009
+ && (this._config.multiSelectDisplay?.mode ?? 'wrap') === 'horizontal';
4010
+ if (!this._config.enabled || !isHorizontalMultiMode) {
4011
+ this._suppressNextOpenClick = false;
4012
+ this._multiScrollDrag.moved = false;
4013
+ return;
4014
+ }
4015
+ if (target && target.closest('.dropdown-arrow-container, .clear-control-button')) {
4016
+ this._suppressNextOpenClick = false;
4017
+ this._multiScrollDrag.moved = false;
4018
+ return;
4019
+ }
4020
+ if (this._suppressNextOpenClick || this._multiScrollDrag.moved || this._isPointerOnInputScrollbar(e)) {
4021
+ this._suppressNextOpenClick = false;
4022
+ this._multiScrollDrag.moved = false;
4023
+ return;
4024
+ }
4025
+ this._suppressNextOpenClick = false;
4026
+ this._multiScrollDrag.moved = false;
4027
+ if (!this._state.isOpen) {
4028
+ this._handleOpen();
4029
+ }
4030
+ this._input.focus();
4031
+ });
4032
+ this._inputContent.addEventListener('pointermove', (e) => {
4033
+ this._updateMultiScrollDrag(e);
4034
+ });
4035
+ this._inputContent.addEventListener('pointerup', (e) => {
4036
+ this._endMultiScrollDrag(e.pointerId);
4037
+ });
4038
+ this._inputContent.addEventListener('pointercancel', (e) => {
4039
+ this._endMultiScrollDrag(e.pointerId);
4040
+ });
4041
+ this._inputContent.addEventListener('wheel', (e) => {
4042
+ if (this._config.selection.mode === 'multi'
4043
+ && (this._config.multiSelectDisplay?.mode ?? 'wrap') === 'horizontal') {
4044
+ e.preventDefault();
4045
+ }
4046
+ }, { passive: false });
3322
4047
  // Input container click - prevent event from reaching document listener
3323
4048
  this._container.addEventListener('click', (e) => {
3324
4049
  e.stopPropagation();
@@ -3489,11 +4214,14 @@ class EnhancedSelect extends HTMLElement {
3489
4214
  this._input.focus();
3490
4215
  this._markOpenStart();
3491
4216
  this._state.isOpen = true;
4217
+ this.setAttribute('data-open', 'true');
4218
+ this._liftStackingAncestors();
3492
4219
  this._dropdown.style.display = 'block';
3493
4220
  this._input.setAttribute('aria-expanded', 'true');
3494
4221
  this._updateArrowRotation();
3495
4222
  // Render options when opening
3496
4223
  this._renderOptions();
4224
+ this._syncDropdownPlacement();
3497
4225
  this._setInitialActiveOption();
3498
4226
  this._emit('open', {});
3499
4227
  this._config.callbacks.onOpen?.();
@@ -3513,7 +4241,10 @@ class EnhancedSelect extends HTMLElement {
3513
4241
  if (!this._state.isOpen)
3514
4242
  return;
3515
4243
  this._state.isOpen = false;
4244
+ this.removeAttribute('data-open');
4245
+ this._restoreLiftedAncestors();
3516
4246
  this._dropdown.style.display = 'none';
4247
+ this._dropdown.setAttribute('data-placement', this._resolvedDropdownPlacement);
3517
4248
  this._input.setAttribute('aria-expanded', 'false');
3518
4249
  this._input.removeAttribute('aria-activedescendant');
3519
4250
  this._updateArrowRotation();
@@ -3523,14 +4254,76 @@ class EnhancedSelect extends HTMLElement {
3523
4254
  }
3524
4255
  _updateDropdownVisibility() {
3525
4256
  if (this._state.isOpen) {
4257
+ this.setAttribute('data-open', 'true');
4258
+ this._liftStackingAncestors();
3526
4259
  this._dropdown.style.display = 'block';
4260
+ this._syncDropdownPlacement();
3527
4261
  this._input.setAttribute('aria-expanded', 'true');
3528
4262
  }
3529
4263
  else {
4264
+ this.removeAttribute('data-open');
4265
+ this._restoreLiftedAncestors();
3530
4266
  this._dropdown.style.display = 'none';
3531
4267
  this._input.setAttribute('aria-expanded', 'false');
3532
4268
  }
3533
4269
  }
4270
+ _liftStackingAncestors() {
4271
+ this._restoreLiftedAncestors();
4272
+ let ancestor = this.parentElement;
4273
+ while (ancestor && ancestor !== document.body) {
4274
+ if (this._createsStackingContext(ancestor)) {
4275
+ const hadMarker = ancestor.hasAttribute('data-smilodon-open-ancestor');
4276
+ this._liftedAncestors.push({
4277
+ element: ancestor,
4278
+ position: ancestor.style.position,
4279
+ zIndex: ancestor.style.zIndex,
4280
+ hadMarker,
4281
+ });
4282
+ if (getComputedStyle(ancestor).position === 'static') {
4283
+ ancestor.style.position = 'relative';
4284
+ }
4285
+ ancestor.style.zIndex = 'var(--select-ancestor-open-z-index, var(--select-host-open-z-index, var(--select-dropdown-z-index, 1000)))';
4286
+ ancestor.setAttribute('data-smilodon-open-ancestor', 'true');
4287
+ }
4288
+ ancestor = ancestor.parentElement;
4289
+ }
4290
+ }
4291
+ _restoreLiftedAncestors() {
4292
+ for (const lifted of this._liftedAncestors) {
4293
+ lifted.element.style.position = lifted.position;
4294
+ lifted.element.style.zIndex = lifted.zIndex;
4295
+ if (!lifted.hadMarker) {
4296
+ lifted.element.removeAttribute('data-smilodon-open-ancestor');
4297
+ }
4298
+ }
4299
+ this._liftedAncestors = [];
4300
+ }
4301
+ _createsStackingContext(element) {
4302
+ const style = getComputedStyle(element);
4303
+ if (style.position === 'fixed' || style.position === 'sticky')
4304
+ return true;
4305
+ if (style.zIndex !== 'auto' && style.position !== 'static')
4306
+ return true;
4307
+ if (style.opacity !== '1')
4308
+ return true;
4309
+ if (style.transform !== 'none')
4310
+ return true;
4311
+ if (style.filter !== 'none')
4312
+ return true;
4313
+ if (style.backdropFilter && style.backdropFilter !== 'none')
4314
+ return true;
4315
+ if (style.perspective !== 'none')
4316
+ return true;
4317
+ if (style.mixBlendMode !== 'normal')
4318
+ return true;
4319
+ if (style.isolation === 'isolate')
4320
+ return true;
4321
+ if (style.contain.includes('paint') || style.contain.includes('layout'))
4322
+ return true;
4323
+ if (style.willChange.includes('transform') || style.willChange.includes('opacity') || style.willChange.includes('filter'))
4324
+ return true;
4325
+ return false;
4326
+ }
3534
4327
  _updateArrowRotation() {
3535
4328
  if (this._arrowContainer) {
3536
4329
  const arrow = this._arrowContainer.querySelector('.dropdown-arrow');
@@ -4002,7 +4795,7 @@ class EnhancedSelect extends HTMLElement {
4002
4795
  this._input.value = '';
4003
4796
  this._input.placeholder = this._config.placeholder || 'Select an option...';
4004
4797
  // Clear any badges
4005
- const existingBadges = this._inputContainer.querySelectorAll('.selection-badge');
4798
+ const existingBadges = this._inputContent.querySelectorAll('.selection-badge');
4006
4799
  existingBadges.forEach(badge => badge.remove());
4007
4800
  }
4008
4801
  else if (this._config.selection.mode === 'single') {
@@ -4013,16 +4806,23 @@ class EnhancedSelect extends HTMLElement {
4013
4806
  this._input.value = '';
4014
4807
  this._input.placeholder = '';
4015
4808
  // Clear existing badges
4016
- const existingBadges = this._inputContainer.querySelectorAll('.selection-badge');
4809
+ const existingBadges = this._inputContent.querySelectorAll('.selection-badge');
4017
4810
  existingBadges.forEach(badge => badge.remove());
4018
4811
  // Create badges for each selected item
4019
4812
  const selectedEntries = Array.from(this._state.selectedItems.entries());
4020
4813
  selectedEntries.forEach(([index, item]) => {
4021
4814
  const badge = document.createElement('span');
4022
4815
  badge.className = 'selection-badge';
4816
+ if (this._config.styles.classNames?.badge) {
4817
+ badge.classList.add(...this._config.styles.classNames.badge.split(' ').filter(Boolean));
4818
+ }
4023
4819
  badge.setAttribute('part', 'chip');
4024
4820
  const badgeLabel = document.createElement('span');
4025
4821
  badgeLabel.className = 'selection-badge-label';
4822
+ if (this._config.styles.classNames?.badgeLabel) {
4823
+ badgeLabel.classList.add(...this._config.styles.classNames.badgeLabel.split(' ').filter(Boolean));
4824
+ }
4825
+ badgeLabel.setAttribute('part', 'chip-label');
4026
4826
  badgeLabel.textContent = getLabel(item);
4027
4827
  badge.appendChild(badgeLabel);
4028
4828
  // Add remove button to badge
@@ -4030,9 +4830,19 @@ class EnhancedSelect extends HTMLElement {
4030
4830
  const removeBtn = document.createElement('button');
4031
4831
  removeBtn.type = 'button';
4032
4832
  removeBtn.className = 'badge-remove';
4833
+ if (this._config.styles.classNames?.removeButton) {
4834
+ removeBtn.classList.add(...this._config.styles.classNames.removeButton.split(' ').filter(Boolean));
4835
+ }
4836
+ if (this._config.styles.classNames?.badgeRemove) {
4837
+ removeBtn.classList.add(...this._config.styles.classNames.badgeRemove.split(' ').filter(Boolean));
4838
+ }
4033
4839
  removeBtn.setAttribute('part', 'chip-remove');
4034
- removeBtn.innerHTML = '×';
4035
4840
  removeBtn.setAttribute('aria-label', `Remove ${getLabel(item)}`);
4841
+ const removeIcon = document.createElement('span');
4842
+ removeIcon.className = 'badge-remove-icon';
4843
+ removeIcon.setAttribute('part', 'chip-remove-icon');
4844
+ this._setIconContent(removeIcon, this._config.selection.removeButtonIcon, '×');
4845
+ removeBtn.appendChild(removeIcon);
4036
4846
  removeBtn.addEventListener('pointerdown', (e) => {
4037
4847
  e.stopPropagation();
4038
4848
  e.preventDefault();
@@ -4044,7 +4854,7 @@ class EnhancedSelect extends HTMLElement {
4044
4854
  });
4045
4855
  badge.appendChild(removeBtn);
4046
4856
  }
4047
- this._inputContainer.insertBefore(badge, this._input);
4857
+ this._inputContent.insertBefore(badge, this._input);
4048
4858
  });
4049
4859
  }
4050
4860
  this._syncClearControlState();
@@ -4517,6 +5327,7 @@ class EnhancedSelect extends HTMLElement {
4517
5327
  if (this._clearControlIcon) {
4518
5328
  this._clearControlIcon.innerHTML = `<svg viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M12 4L4 12M4 4L12 12" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>`;
4519
5329
  }
5330
+ this._syncStyleConfigVariables();
4520
5331
  if (this._dropdown) {
4521
5332
  if (this._config.selection.mode === 'multi') {
4522
5333
  this._dropdown.setAttribute('aria-multiselectable', 'true');
@@ -4525,10 +5336,14 @@ class EnhancedSelect extends HTMLElement {
4525
5336
  this._dropdown.removeAttribute('aria-multiselectable');
4526
5337
  }
4527
5338
  }
5339
+ this._syncDirectionConfig();
4528
5340
  this._syncInputContainerMode();
5341
+ this._syncMultiSelectDisplayConfig();
5342
+ this._syncDropdownPlacement();
4529
5343
  // Re-initialize observers in case infinite scroll was enabled/disabled
4530
5344
  this._initializeObservers();
4531
5345
  this._syncClearControlState();
5346
+ this._updateInputDisplay();
4532
5347
  this._renderOptions();
4533
5348
  }
4534
5349
  _mergeConfig(target, source) {
@@ -4684,6 +5499,9 @@ class EnhancedSelect extends HTMLElement {
4684
5499
  header.textContent = group.label;
4685
5500
  }
4686
5501
  header.classList.add('group-header');
5502
+ if (this._config.styles.classNames?.groupHeader) {
5503
+ header.classList.add(...this._config.styles.classNames.groupHeader.split(' ').filter(Boolean));
5504
+ }
4687
5505
  header.setAttribute('part', 'group-header');
4688
5506
  this._optionsContainer.appendChild(header);
4689
5507
  group.options.forEach(item => {
@@ -4811,6 +5629,7 @@ class EnhancedSelect extends HTMLElement {
4811
5629
  disabled: isDisabled,
4812
5630
  id: optionId,
4813
5631
  });
5632
+ optionElement.setAttribute('dir', this._config.direction ?? 'ltr');
4814
5633
  targetContainer.appendChild(optionElement);
4815
5634
  return;
4816
5635
  }
@@ -4824,8 +5643,23 @@ class EnhancedSelect extends HTMLElement {
4824
5643
  getValue,
4825
5644
  getLabel,
4826
5645
  showRemoveButton: this._config.selection.mode === 'multi' && this._config.selection.showRemoveButton,
5646
+ removeButtonIcon: this._config.selection.removeButtonIcon,
4827
5647
  classMap: this.classMap,
5648
+ className: this._config.styles.classNames?.option,
4828
5649
  });
5650
+ if (this._config.styles.classNames?.option) {
5651
+ option.classList.add(...this._config.styles.classNames.option.split(' ').filter(Boolean));
5652
+ }
5653
+ option.setAttribute('dir', this._config.direction ?? 'ltr');
5654
+ if (isSelected && this._config.styles.classNames?.selectedOption) {
5655
+ option.classList.add(...this._config.styles.classNames.selectedOption.split(' ').filter(Boolean));
5656
+ }
5657
+ if (this._state.activeIndex === index && this._config.styles.classNames?.activeOption) {
5658
+ option.classList.add(...this._config.styles.classNames.activeOption.split(' ').filter(Boolean));
5659
+ }
5660
+ if (isDisabled && this._config.styles.classNames?.disabledOption) {
5661
+ option.classList.add(...this._config.styles.classNames.disabledOption.split(' ').filter(Boolean));
5662
+ }
4829
5663
  // Valid part attribute on the web component host itself
4830
5664
  option.setAttribute('part', 'option');
4831
5665
  option.dataset.index = String(index);
@@ -4859,6 +5693,9 @@ class EnhancedSelect extends HTMLElement {
4859
5693
  }
4860
5694
  // Add both semantic namespaced classes and the legacy internal classes that CSS uses
4861
5695
  optionEl.classList.add('smilodon-option', 'option');
5696
+ if (this._config.styles.classNames?.option) {
5697
+ optionEl.classList.add(...this._config.styles.classNames.option.split(' ').filter(Boolean));
5698
+ }
4862
5699
  // Toggle state classes using classMap if available
4863
5700
  const isSelected = meta.selected;
4864
5701
  const isActive = meta.active;
@@ -4870,26 +5707,44 @@ class EnhancedSelect extends HTMLElement {
4870
5707
  if (isSelected) {
4871
5708
  optionEl.classList.add(...selectedClasses);
4872
5709
  optionEl.classList.add('smilodon-option--selected');
5710
+ if (this._config.styles.classNames?.selectedOption) {
5711
+ optionEl.classList.add(...this._config.styles.classNames.selectedOption.split(' ').filter(Boolean));
5712
+ }
4873
5713
  }
4874
5714
  else {
4875
5715
  optionEl.classList.remove(...selectedClasses);
4876
5716
  optionEl.classList.remove('smilodon-option--selected');
5717
+ if (this._config.styles.classNames?.selectedOption) {
5718
+ optionEl.classList.remove(...this._config.styles.classNames.selectedOption.split(' ').filter(Boolean));
5719
+ }
4877
5720
  }
4878
5721
  if (isActive) {
4879
5722
  optionEl.classList.add(...activeClasses);
4880
5723
  optionEl.classList.add('smilodon-option--active');
5724
+ if (this._config.styles.classNames?.activeOption) {
5725
+ optionEl.classList.add(...this._config.styles.classNames.activeOption.split(' ').filter(Boolean));
5726
+ }
4881
5727
  }
4882
5728
  else {
4883
5729
  optionEl.classList.remove(...activeClasses);
4884
5730
  optionEl.classList.remove('smilodon-option--active');
5731
+ if (this._config.styles.classNames?.activeOption) {
5732
+ optionEl.classList.remove(...this._config.styles.classNames.activeOption.split(' ').filter(Boolean));
5733
+ }
4885
5734
  }
4886
5735
  if (isDisabled) {
4887
5736
  optionEl.classList.add(...disabledClasses);
4888
5737
  optionEl.classList.add('smilodon-option--disabled');
5738
+ if (this._config.styles.classNames?.disabledOption) {
5739
+ optionEl.classList.add(...this._config.styles.classNames.disabledOption.split(' ').filter(Boolean));
5740
+ }
4889
5741
  }
4890
5742
  else {
4891
5743
  optionEl.classList.remove(...disabledClasses);
4892
5744
  optionEl.classList.remove('smilodon-option--disabled');
5745
+ if (this._config.styles.classNames?.disabledOption) {
5746
+ optionEl.classList.remove(...this._config.styles.classNames.disabledOption.split(' ').filter(Boolean));
5747
+ }
4893
5748
  }
4894
5749
  // Data Attributes Contract
4895
5750
  const state = [];