@smilodon/core 1.4.12 → 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/README.md +128 -15
- package/dist/index.cjs +1802 -474
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1802 -474
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +1 -1
- package/dist/index.min.js.map +1 -1
- package/dist/index.umd.js +1801 -473
- package/dist/index.umd.js.map +1 -1
- package/dist/index.umd.min.js +1 -1
- package/dist/index.umd.min.js.map +1 -1
- package/dist/types/src/components/enhanced-select.d.ts +28 -0
- package/dist/types/src/components/select-option.d.ts +2 -0
- package/dist/types/src/config/global-config.d.ts +50 -0
- package/package.json +1 -1
package/dist/index.umd.js
CHANGED
|
@@ -1354,7 +1354,20 @@
|
|
|
1354
1354
|
allowDeselect: false,
|
|
1355
1355
|
maxSelections: 0,
|
|
1356
1356
|
showRemoveButton: true,
|
|
1357
|
+
removeButtonIcon: '×',
|
|
1357
1358
|
closeOnSelect: true,
|
|
1359
|
+
toggleOnTriggerClick: true,
|
|
1360
|
+
},
|
|
1361
|
+
direction: 'ltr',
|
|
1362
|
+
dropdownPlacement: {
|
|
1363
|
+
mode: 'bottom',
|
|
1364
|
+
},
|
|
1365
|
+
multiSelectDisplay: {
|
|
1366
|
+
mode: 'wrap',
|
|
1367
|
+
maxHeight: '160px',
|
|
1368
|
+
overflowX: 'hidden',
|
|
1369
|
+
overflowY: 'auto',
|
|
1370
|
+
dragScroll: true,
|
|
1358
1371
|
},
|
|
1359
1372
|
scrollToSelected: {
|
|
1360
1373
|
enabled: true,
|
|
@@ -1516,6 +1529,8 @@
|
|
|
1516
1529
|
:host {
|
|
1517
1530
|
display: block;
|
|
1518
1531
|
position: relative;
|
|
1532
|
+
font: inherit;
|
|
1533
|
+
color: inherit;
|
|
1519
1534
|
}
|
|
1520
1535
|
|
|
1521
1536
|
/* Allow authors to style selected state from outside the shadow root
|
|
@@ -1547,7 +1562,7 @@
|
|
|
1547
1562
|
display: flex;
|
|
1548
1563
|
align-items: center;
|
|
1549
1564
|
justify-content: space-between;
|
|
1550
|
-
padding: var(--select-option-padding,
|
|
1565
|
+
padding: var(--select-option-padding, 10px 14px);
|
|
1551
1566
|
cursor: pointer;
|
|
1552
1567
|
user-select: none;
|
|
1553
1568
|
color: var(--select-option-color, var(--select-text-color, #1f2937));
|
|
@@ -1555,13 +1570,19 @@
|
|
|
1555
1570
|
transition: var(--select-option-transition, background-color 0.2s ease);
|
|
1556
1571
|
border: var(--select-option-border, none);
|
|
1557
1572
|
border-bottom: var(--select-option-border-bottom, none);
|
|
1558
|
-
border-radius: var(--select-option-border-radius,
|
|
1573
|
+
border-radius: var(--select-option-border-radius, var(--select-radius-sm, 6px));
|
|
1559
1574
|
box-shadow: var(--select-option-shadow, none);
|
|
1560
1575
|
transform: var(--select-option-transform, none);
|
|
1576
|
+
font: inherit;
|
|
1561
1577
|
}
|
|
1562
1578
|
|
|
1563
1579
|
.option-container:hover {
|
|
1564
1580
|
background: var(--select-option-hover-bg, #f0f0f0);
|
|
1581
|
+
color: var(--select-option-hover-color, var(--select-option-color, var(--select-text-color, #1f2937)));
|
|
1582
|
+
border: var(--select-option-hover-border, var(--select-option-border, none));
|
|
1583
|
+
border-bottom: var(--select-option-hover-border-bottom, var(--select-option-border-bottom, none));
|
|
1584
|
+
box-shadow: var(--select-option-hover-shadow, var(--select-option-shadow, none));
|
|
1585
|
+
transform: var(--select-option-hover-transform, var(--select-option-transform, none));
|
|
1565
1586
|
}
|
|
1566
1587
|
|
|
1567
1588
|
.option-container.selected {
|
|
@@ -1584,13 +1605,22 @@
|
|
|
1584
1605
|
}
|
|
1585
1606
|
|
|
1586
1607
|
.option-container.active {
|
|
1587
|
-
|
|
1588
|
-
|
|
1608
|
+
background: var(--select-option-active-bg, var(--select-option-hover-bg, #f0f0f0));
|
|
1609
|
+
color: var(--select-option-active-color, var(--select-option-hover-color, var(--select-option-color, var(--select-text-color, #1f2937))));
|
|
1610
|
+
border: var(--select-option-active-border, var(--select-option-hover-border, var(--select-option-border, none)));
|
|
1611
|
+
box-shadow: var(--select-option-active-shadow, var(--select-option-shadow, none));
|
|
1612
|
+
transform: var(--select-option-active-transform, var(--select-option-transform, none));
|
|
1613
|
+
outline: var(--select-option-active-outline, 2px solid #1976d2);
|
|
1614
|
+
outline-offset: var(--select-option-active-outline-offset, -2px);
|
|
1589
1615
|
}
|
|
1590
1616
|
|
|
1591
1617
|
.option-container.disabled {
|
|
1592
|
-
|
|
1593
|
-
|
|
1618
|
+
background: var(--select-option-disabled-bg, var(--select-option-bg, var(--select-dropdown-bg, var(--select-bg, white))));
|
|
1619
|
+
color: var(--select-option-disabled-color, var(--select-option-color, var(--select-text-color, #1f2937)));
|
|
1620
|
+
border: var(--select-option-disabled-border, var(--select-option-border, none));
|
|
1621
|
+
border-bottom: var(--select-option-disabled-border-bottom, var(--select-option-border-bottom, none));
|
|
1622
|
+
opacity: var(--select-option-disabled-opacity, 0.5);
|
|
1623
|
+
cursor: var(--select-option-disabled-cursor, not-allowed);
|
|
1594
1624
|
pointer-events: none;
|
|
1595
1625
|
}
|
|
1596
1626
|
|
|
@@ -1607,6 +1637,12 @@
|
|
|
1607
1637
|
color: var(--select-checkmark-color, currentColor);
|
|
1608
1638
|
}
|
|
1609
1639
|
|
|
1640
|
+
:host([dir="rtl"]) .checkmark-icon,
|
|
1641
|
+
:host-context([dir="rtl"]) .checkmark-icon {
|
|
1642
|
+
margin-left: 0;
|
|
1643
|
+
margin-right: var(--select-checkmark-margin-left, 8px);
|
|
1644
|
+
}
|
|
1645
|
+
|
|
1610
1646
|
:host([aria-selected="true"]) .checkmark-icon,
|
|
1611
1647
|
.option-container.selected .checkmark-icon {
|
|
1612
1648
|
display: inline-flex;
|
|
@@ -1614,20 +1650,49 @@
|
|
|
1614
1650
|
|
|
1615
1651
|
.remove-button {
|
|
1616
1652
|
margin-left: 8px;
|
|
1617
|
-
|
|
1653
|
+
width: var(--select-badge-remove-size, 18px);
|
|
1654
|
+
height: var(--select-badge-remove-size, 18px);
|
|
1655
|
+
min-width: var(--select-badge-remove-min-width, var(--select-badge-remove-size, 18px));
|
|
1656
|
+
min-height: var(--select-badge-remove-min-height, var(--select-badge-remove-size, 18px));
|
|
1657
|
+
padding: 0;
|
|
1618
1658
|
border: none;
|
|
1619
|
-
background-color: var(--select-remove-
|
|
1620
|
-
color: var(--select-remove-
|
|
1659
|
+
background-color: var(--select-badge-remove-bg, rgba(255, 255, 255, 0.2));
|
|
1660
|
+
color: var(--select-badge-remove-color, currentColor);
|
|
1621
1661
|
cursor: pointer;
|
|
1622
|
-
border-radius:
|
|
1623
|
-
font-size:
|
|
1662
|
+
border-radius: var(--select-badge-remove-radius, 50%);
|
|
1663
|
+
font-size: var(--select-badge-remove-font-size, 0.7333em);
|
|
1664
|
+
font-weight: var(--select-badge-remove-font-weight, 600);
|
|
1624
1665
|
line-height: 1;
|
|
1666
|
+
display: inline-flex;
|
|
1667
|
+
align-items: center;
|
|
1668
|
+
justify-content: center;
|
|
1625
1669
|
transition: all 0.2s ease;
|
|
1626
1670
|
}
|
|
1671
|
+
|
|
1672
|
+
:host([dir="rtl"]) .remove-button,
|
|
1673
|
+
:host-context([dir="rtl"]) .remove-button {
|
|
1674
|
+
margin-left: 0;
|
|
1675
|
+
margin-right: 8px;
|
|
1676
|
+
}
|
|
1677
|
+
|
|
1678
|
+
.remove-button-icon {
|
|
1679
|
+
display: inline-flex;
|
|
1680
|
+
align-items: center;
|
|
1681
|
+
justify-content: center;
|
|
1682
|
+
width: var(--select-badge-remove-icon-size, 10px);
|
|
1683
|
+
height: var(--select-badge-remove-icon-size, 10px);
|
|
1684
|
+
pointer-events: none;
|
|
1685
|
+
}
|
|
1686
|
+
|
|
1687
|
+
.remove-button-icon svg {
|
|
1688
|
+
width: 100%;
|
|
1689
|
+
height: 100%;
|
|
1690
|
+
display: block;
|
|
1691
|
+
}
|
|
1627
1692
|
|
|
1628
1693
|
.remove-button:hover {
|
|
1629
|
-
background-color: var(--select-remove-
|
|
1630
|
-
color: var(--select-remove-
|
|
1694
|
+
background-color: var(--select-badge-remove-hover-bg, #ffebee);
|
|
1695
|
+
color: var(--select-badge-remove-hover-color, #c62828);
|
|
1631
1696
|
}
|
|
1632
1697
|
|
|
1633
1698
|
.remove-button:focus {
|
|
@@ -1714,10 +1779,22 @@
|
|
|
1714
1779
|
if (showRemoveButton && selected) {
|
|
1715
1780
|
this._removeButton = document.createElement('button');
|
|
1716
1781
|
this._removeButton.className = 'remove-button';
|
|
1717
|
-
this._removeButton.innerHTML = '×';
|
|
1718
1782
|
this._removeButton.setAttribute('part', 'chip-remove');
|
|
1719
1783
|
this._removeButton.setAttribute('aria-label', 'Remove option');
|
|
1720
1784
|
this._removeButton.setAttribute('type', 'button');
|
|
1785
|
+
const removeIcon = document.createElement('span');
|
|
1786
|
+
removeIcon.className = 'remove-button-icon';
|
|
1787
|
+
removeIcon.setAttribute('part', 'chip-remove-icon');
|
|
1788
|
+
const iconMarkup = this._config.removeButtonIcon && this._config.removeButtonIcon.trim()
|
|
1789
|
+
? this._config.removeButtonIcon
|
|
1790
|
+
: '×';
|
|
1791
|
+
if (iconMarkup.trim().startsWith('<')) {
|
|
1792
|
+
removeIcon.innerHTML = iconMarkup;
|
|
1793
|
+
}
|
|
1794
|
+
else {
|
|
1795
|
+
removeIcon.textContent = iconMarkup;
|
|
1796
|
+
}
|
|
1797
|
+
this._removeButton.appendChild(removeIcon);
|
|
1721
1798
|
this._container.appendChild(this._removeButton);
|
|
1722
1799
|
}
|
|
1723
1800
|
// Set ARIA attributes and State attributes on Host
|
|
@@ -1887,6 +1964,8 @@
|
|
|
1887
1964
|
* Enhanced Select Component
|
|
1888
1965
|
* Implements all advanced features: infinite scroll, load more, busy state,
|
|
1889
1966
|
* server-side selection, and full customization
|
|
1967
|
+
*
|
|
1968
|
+
* ✨ Redesigned with formal elegance, refined microinteractions, and polished UX
|
|
1890
1969
|
*/
|
|
1891
1970
|
class EnhancedSelect extends HTMLElement {
|
|
1892
1971
|
get classMap() {
|
|
@@ -1934,6 +2013,18 @@
|
|
|
1934
2013
|
this._globalStylesObserver = null;
|
|
1935
2014
|
this._globalStylesContainer = null;
|
|
1936
2015
|
this._tracking = { events: [], styles: [], limitations: [] };
|
|
2016
|
+
this._suppressBlurClose = false;
|
|
2017
|
+
this._renderCycleId = 0;
|
|
2018
|
+
this._suppressNextOpenClick = false;
|
|
2019
|
+
this._resolvedDropdownPlacement = 'bottom';
|
|
2020
|
+
this._multiScrollDrag = {
|
|
2021
|
+
active: false,
|
|
2022
|
+
moved: false,
|
|
2023
|
+
pointerId: -1,
|
|
2024
|
+
startX: 0,
|
|
2025
|
+
startScrollLeft: 0,
|
|
2026
|
+
};
|
|
2027
|
+
this._liftedAncestors = [];
|
|
1937
2028
|
this._shadow = this.attachShadow({ mode: 'open' });
|
|
1938
2029
|
this._uniqueId = `enhanced-select-${Math.random().toString(36).substr(2, 9)}`;
|
|
1939
2030
|
this._rendererHelpers = this._buildRendererHelpers();
|
|
@@ -1961,6 +2052,7 @@
|
|
|
1961
2052
|
// Create DOM structure
|
|
1962
2053
|
this._container = this._createContainer();
|
|
1963
2054
|
this._inputContainer = this._createInputContainer();
|
|
2055
|
+
this._inputContent = this._createInputContent();
|
|
1964
2056
|
this._input = this._createInput();
|
|
1965
2057
|
this._arrowContainer = this._createArrowContainer();
|
|
1966
2058
|
this._clearControl = this._createClearControl();
|
|
@@ -1969,6 +2061,8 @@
|
|
|
1969
2061
|
this._liveRegion = this._createLiveRegion();
|
|
1970
2062
|
// Initialize styles BEFORE assembling DOM (order matters in shadow DOM)
|
|
1971
2063
|
this._initializeStyles();
|
|
2064
|
+
this._syncStyleConfigVariables();
|
|
2065
|
+
this._syncDirectionConfig();
|
|
1972
2066
|
this._assembleDOM();
|
|
1973
2067
|
this._attachEventListeners();
|
|
1974
2068
|
this._initializeObservers();
|
|
@@ -2004,10 +2098,12 @@
|
|
|
2004
2098
|
clearTimeout(this._typeTimeout);
|
|
2005
2099
|
if (this._searchTimeout)
|
|
2006
2100
|
clearTimeout(this._searchTimeout);
|
|
2101
|
+
this._endMultiScrollDrag();
|
|
2007
2102
|
// Cleanup arrow click listener
|
|
2008
2103
|
if (this._boundArrowClick && this._arrowContainer) {
|
|
2009
2104
|
this._arrowContainer.removeEventListener('click', this._boundArrowClick);
|
|
2010
2105
|
}
|
|
2106
|
+
this._renderCycleId += 1;
|
|
2011
2107
|
this._teardownGlobalStylesMirroring();
|
|
2012
2108
|
}
|
|
2013
2109
|
_setGlobalStylesMirroring(enabled) {
|
|
@@ -2111,8 +2207,360 @@
|
|
|
2111
2207
|
const container = document.createElement('div');
|
|
2112
2208
|
container.className = 'input-container';
|
|
2113
2209
|
container.setAttribute('part', 'button');
|
|
2210
|
+
const inputStyles = this._config.styles.input;
|
|
2211
|
+
if (inputStyles && !this._config.styles.container) {
|
|
2212
|
+
const shellStyleKeys = [
|
|
2213
|
+
'background',
|
|
2214
|
+
'backgroundColor',
|
|
2215
|
+
'border',
|
|
2216
|
+
'borderColor',
|
|
2217
|
+
'borderStyle',
|
|
2218
|
+
'borderWidth',
|
|
2219
|
+
'borderRadius',
|
|
2220
|
+
'boxShadow',
|
|
2221
|
+
'padding',
|
|
2222
|
+
'height',
|
|
2223
|
+
'minHeight',
|
|
2224
|
+
'maxHeight',
|
|
2225
|
+
];
|
|
2226
|
+
for (const key of shellStyleKeys) {
|
|
2227
|
+
const value = inputStyles[key];
|
|
2228
|
+
if (value != null && value !== '') {
|
|
2229
|
+
container.style[key] = value;
|
|
2230
|
+
}
|
|
2231
|
+
}
|
|
2232
|
+
}
|
|
2114
2233
|
return container;
|
|
2115
2234
|
}
|
|
2235
|
+
_createInputContent() {
|
|
2236
|
+
const content = document.createElement('div');
|
|
2237
|
+
content.className = 'input-content';
|
|
2238
|
+
return content;
|
|
2239
|
+
}
|
|
2240
|
+
_setCssVariable(name, value) {
|
|
2241
|
+
if (value == null || value === '') {
|
|
2242
|
+
this.style.removeProperty(name);
|
|
2243
|
+
return;
|
|
2244
|
+
}
|
|
2245
|
+
this.style.setProperty(name, String(value));
|
|
2246
|
+
}
|
|
2247
|
+
_applyStyleVariableMap(styleConfig, variableMap) {
|
|
2248
|
+
Object.entries(variableMap).forEach(([styleKey, variableName]) => {
|
|
2249
|
+
this._setCssVariable(variableName, styleConfig?.[styleKey]);
|
|
2250
|
+
});
|
|
2251
|
+
}
|
|
2252
|
+
_syncStyleConfigVariables() {
|
|
2253
|
+
const styles = this._config.styles;
|
|
2254
|
+
this._applyStyleVariableMap(styles.option, {
|
|
2255
|
+
background: '--select-option-bg',
|
|
2256
|
+
backgroundColor: '--select-option-bg',
|
|
2257
|
+
color: '--select-option-color',
|
|
2258
|
+
border: '--select-option-border',
|
|
2259
|
+
borderBottom: '--select-option-border-bottom',
|
|
2260
|
+
borderRadius: '--select-option-border-radius',
|
|
2261
|
+
boxShadow: '--select-option-shadow',
|
|
2262
|
+
transform: '--select-option-transform',
|
|
2263
|
+
padding: '--select-option-padding',
|
|
2264
|
+
margin: '--select-option-margin',
|
|
2265
|
+
fontSize: '--select-option-font-size',
|
|
2266
|
+
fontWeight: '--select-option-font-weight',
|
|
2267
|
+
lineHeight: '--select-option-line-height',
|
|
2268
|
+
textAlign: '--select-option-text-align',
|
|
2269
|
+
});
|
|
2270
|
+
this._applyStyleVariableMap(styles.selectedOption, {
|
|
2271
|
+
background: '--select-option-selected-bg',
|
|
2272
|
+
backgroundColor: '--select-option-selected-bg',
|
|
2273
|
+
color: '--select-option-selected-color',
|
|
2274
|
+
border: '--select-option-selected-border',
|
|
2275
|
+
borderBottom: '--select-option-selected-border-bottom',
|
|
2276
|
+
borderRadius: '--select-option-selected-border-radius',
|
|
2277
|
+
boxShadow: '--select-option-selected-shadow',
|
|
2278
|
+
transform: '--select-option-selected-transform',
|
|
2279
|
+
fontWeight: '--select-option-selected-weight',
|
|
2280
|
+
});
|
|
2281
|
+
this._applyStyleVariableMap(styles.hoverOption, {
|
|
2282
|
+
background: '--select-option-hover-bg',
|
|
2283
|
+
backgroundColor: '--select-option-hover-bg',
|
|
2284
|
+
color: '--select-option-hover-color',
|
|
2285
|
+
border: '--select-option-hover-border',
|
|
2286
|
+
borderBottom: '--select-option-hover-border-bottom',
|
|
2287
|
+
boxShadow: '--select-option-hover-shadow',
|
|
2288
|
+
transform: '--select-option-hover-transform',
|
|
2289
|
+
});
|
|
2290
|
+
this._applyStyleVariableMap(styles.activeOption, {
|
|
2291
|
+
background: '--select-option-active-bg',
|
|
2292
|
+
backgroundColor: '--select-option-active-bg',
|
|
2293
|
+
color: '--select-option-active-color',
|
|
2294
|
+
border: '--select-option-active-border',
|
|
2295
|
+
outline: '--select-option-active-outline',
|
|
2296
|
+
outlineOffset: '--select-option-active-outline-offset',
|
|
2297
|
+
boxShadow: '--select-option-active-shadow',
|
|
2298
|
+
transform: '--select-option-active-transform',
|
|
2299
|
+
});
|
|
2300
|
+
this._applyStyleVariableMap(styles.disabledOption, {
|
|
2301
|
+
background: '--select-option-disabled-bg',
|
|
2302
|
+
backgroundColor: '--select-option-disabled-bg',
|
|
2303
|
+
color: '--select-option-disabled-color',
|
|
2304
|
+
border: '--select-option-disabled-border',
|
|
2305
|
+
borderBottom: '--select-option-disabled-border-bottom',
|
|
2306
|
+
opacity: '--select-option-disabled-opacity',
|
|
2307
|
+
cursor: '--select-option-disabled-cursor',
|
|
2308
|
+
});
|
|
2309
|
+
this._applyStyleVariableMap(styles.badge, {
|
|
2310
|
+
width: '--select-badge-width',
|
|
2311
|
+
minWidth: '--select-badge-min-width',
|
|
2312
|
+
maxWidth: '--select-badge-max-width',
|
|
2313
|
+
height: '--select-badge-height',
|
|
2314
|
+
minHeight: '--select-badge-min-height',
|
|
2315
|
+
padding: '--select-badge-padding',
|
|
2316
|
+
margin: '--select-badge-margin',
|
|
2317
|
+
gap: '--select-badge-gap',
|
|
2318
|
+
background: '--select-badge-bg',
|
|
2319
|
+
backgroundColor: '--select-badge-bg',
|
|
2320
|
+
color: '--select-badge-color',
|
|
2321
|
+
border: '--select-badge-border',
|
|
2322
|
+
borderRadius: '--select-badge-border-radius',
|
|
2323
|
+
boxShadow: '--select-badge-shadow',
|
|
2324
|
+
fontSize: '--select-badge-font-size',
|
|
2325
|
+
fontWeight: '--select-badge-font-weight',
|
|
2326
|
+
lineHeight: '--select-badge-line-height',
|
|
2327
|
+
letterSpacing: '--select-badge-letter-spacing',
|
|
2328
|
+
});
|
|
2329
|
+
this._applyStyleVariableMap(styles.badgeHover, {
|
|
2330
|
+
background: '--select-badge-hover-bg',
|
|
2331
|
+
backgroundColor: '--select-badge-hover-bg',
|
|
2332
|
+
color: '--select-badge-hover-color',
|
|
2333
|
+
border: '--select-badge-hover-border',
|
|
2334
|
+
boxShadow: '--select-badge-hover-shadow',
|
|
2335
|
+
transform: '--select-badge-hover-transform',
|
|
2336
|
+
});
|
|
2337
|
+
this._applyStyleVariableMap(styles.badgeActive, {
|
|
2338
|
+
background: '--select-badge-active-bg',
|
|
2339
|
+
backgroundColor: '--select-badge-active-bg',
|
|
2340
|
+
color: '--select-badge-active-color',
|
|
2341
|
+
border: '--select-badge-active-border',
|
|
2342
|
+
boxShadow: '--select-badge-active-shadow',
|
|
2343
|
+
transform: '--select-badge-active-transform',
|
|
2344
|
+
});
|
|
2345
|
+
this._applyStyleVariableMap(styles.badgeLabel, {
|
|
2346
|
+
color: '--select-badge-label-color',
|
|
2347
|
+
fontSize: '--select-badge-label-font-size',
|
|
2348
|
+
fontWeight: '--select-badge-label-font-weight',
|
|
2349
|
+
lineHeight: '--select-badge-label-line-height',
|
|
2350
|
+
letterSpacing: '--select-badge-label-letter-spacing',
|
|
2351
|
+
textAlign: '--select-badge-label-text-align',
|
|
2352
|
+
});
|
|
2353
|
+
this._applyStyleVariableMap(styles.badgeRemove, {
|
|
2354
|
+
width: '--select-badge-remove-size',
|
|
2355
|
+
height: '--select-badge-remove-size',
|
|
2356
|
+
minWidth: '--select-badge-remove-min-width',
|
|
2357
|
+
minHeight: '--select-badge-remove-min-height',
|
|
2358
|
+
marginLeft: '--select-badge-remove-margin-left',
|
|
2359
|
+
background: '--select-badge-remove-bg',
|
|
2360
|
+
backgroundColor: '--select-badge-remove-bg',
|
|
2361
|
+
border: '--select-badge-remove-border',
|
|
2362
|
+
borderRadius: '--select-badge-remove-radius',
|
|
2363
|
+
color: '--select-badge-remove-color',
|
|
2364
|
+
fontSize: '--select-badge-remove-font-size',
|
|
2365
|
+
fontWeight: '--select-badge-remove-font-weight',
|
|
2366
|
+
});
|
|
2367
|
+
this._applyStyleVariableMap(styles.badgeRemoveHover, {
|
|
2368
|
+
background: '--select-badge-remove-hover-bg',
|
|
2369
|
+
backgroundColor: '--select-badge-remove-hover-bg',
|
|
2370
|
+
color: '--select-badge-remove-hover-color',
|
|
2371
|
+
border: '--select-badge-remove-hover-border',
|
|
2372
|
+
boxShadow: '--select-badge-remove-hover-shadow',
|
|
2373
|
+
transform: '--select-badge-remove-hover-transform',
|
|
2374
|
+
});
|
|
2375
|
+
this._applyStyleVariableMap(styles.badgeRemoveActive, {
|
|
2376
|
+
background: '--select-badge-remove-active-bg',
|
|
2377
|
+
backgroundColor: '--select-badge-remove-active-bg',
|
|
2378
|
+
color: '--select-badge-remove-active-color',
|
|
2379
|
+
border: '--select-badge-remove-active-border',
|
|
2380
|
+
boxShadow: '--select-badge-remove-active-shadow',
|
|
2381
|
+
transform: '--select-badge-remove-active-transform',
|
|
2382
|
+
});
|
|
2383
|
+
this._applyStyleVariableMap(styles.groupHeader, {
|
|
2384
|
+
padding: '--select-group-header-padding',
|
|
2385
|
+
margin: '--select-group-header-margin',
|
|
2386
|
+
color: '--select-group-header-color',
|
|
2387
|
+
background: '--select-group-header-bg',
|
|
2388
|
+
backgroundColor: '--select-group-header-bg',
|
|
2389
|
+
border: '--select-group-header-border',
|
|
2390
|
+
borderBottom: '--select-group-header-border-bottom',
|
|
2391
|
+
borderRadius: '--select-group-header-border-radius',
|
|
2392
|
+
boxShadow: '--select-group-header-shadow',
|
|
2393
|
+
textAlign: '--select-group-header-text-align',
|
|
2394
|
+
fontSize: '--select-group-header-font-size',
|
|
2395
|
+
fontWeight: '--select-group-header-weight',
|
|
2396
|
+
textTransform: '--select-group-header-text-transform',
|
|
2397
|
+
letterSpacing: '--select-group-header-letter-spacing',
|
|
2398
|
+
});
|
|
2399
|
+
}
|
|
2400
|
+
_resolveDropdownPlacement() {
|
|
2401
|
+
const placementMode = this._config.dropdownPlacement?.mode ?? 'bottom';
|
|
2402
|
+
if (placementMode === 'bottom' || placementMode === 'top') {
|
|
2403
|
+
return placementMode;
|
|
2404
|
+
}
|
|
2405
|
+
const hostRect = this._container.getBoundingClientRect();
|
|
2406
|
+
const availableBelow = window.innerHeight - hostRect.bottom;
|
|
2407
|
+
const computedDropdown = window.getComputedStyle(this._dropdown);
|
|
2408
|
+
const maxHeight = Number.parseFloat(computedDropdown.maxHeight || '0');
|
|
2409
|
+
const desiredHeight = Number.isFinite(maxHeight) && maxHeight > 0
|
|
2410
|
+
? Math.min(this._dropdown.scrollHeight, maxHeight)
|
|
2411
|
+
: this._dropdown.scrollHeight;
|
|
2412
|
+
return availableBelow >= desiredHeight ? 'bottom' : 'top';
|
|
2413
|
+
}
|
|
2414
|
+
_syncDropdownPlacement() {
|
|
2415
|
+
if (!this._dropdown)
|
|
2416
|
+
return;
|
|
2417
|
+
this._resolvedDropdownPlacement = this._resolveDropdownPlacement();
|
|
2418
|
+
this._dropdown.setAttribute('data-placement', this._resolvedDropdownPlacement);
|
|
2419
|
+
}
|
|
2420
|
+
_syncDirectionConfig() {
|
|
2421
|
+
this.setAttribute('dir', this._config.direction ?? 'ltr');
|
|
2422
|
+
}
|
|
2423
|
+
_setIconContent(target, markup, fallback) {
|
|
2424
|
+
const content = markup && markup.trim() ? markup : fallback;
|
|
2425
|
+
target.innerHTML = '';
|
|
2426
|
+
if (content.trim().startsWith('<')) {
|
|
2427
|
+
target.innerHTML = content;
|
|
2428
|
+
return;
|
|
2429
|
+
}
|
|
2430
|
+
target.textContent = content;
|
|
2431
|
+
}
|
|
2432
|
+
_syncInputContainerMode() {
|
|
2433
|
+
if (!this._inputContainer || !this._input)
|
|
2434
|
+
return;
|
|
2435
|
+
const isMulti = this._config.selection.mode === 'multi';
|
|
2436
|
+
this._inputContainer.classList.toggle('input-container--multi', isMulti);
|
|
2437
|
+
this._inputContainer.classList.toggle('input-container--single', !isMulti);
|
|
2438
|
+
if (isMulti) {
|
|
2439
|
+
this._input.style.flex = '1 0 var(--select-multi-input-min-width, 96px)';
|
|
2440
|
+
this._input.style.width = 'auto';
|
|
2441
|
+
this._input.style.minWidth = 'var(--select-multi-input-min-width, 96px)';
|
|
2442
|
+
}
|
|
2443
|
+
else {
|
|
2444
|
+
this._input.style.flex = '1 1 auto';
|
|
2445
|
+
this._input.style.width = '100%';
|
|
2446
|
+
this._input.style.minWidth = '0';
|
|
2447
|
+
}
|
|
2448
|
+
this._syncMultiSelectDisplayConfig();
|
|
2449
|
+
}
|
|
2450
|
+
_syncMultiSelectDisplayConfig() {
|
|
2451
|
+
if (!this._inputContainer || !this._input)
|
|
2452
|
+
return;
|
|
2453
|
+
const isMulti = this._config.selection.mode === 'multi';
|
|
2454
|
+
const mode = this._config.multiSelectDisplay?.mode ?? 'wrap';
|
|
2455
|
+
const dragEnabled = this._config.multiSelectDisplay?.dragScroll !== false;
|
|
2456
|
+
if (!isMulti) {
|
|
2457
|
+
this._inputContainer.removeAttribute('data-multi-scroll-mode');
|
|
2458
|
+
this._inputContainer.removeAttribute('data-drag-scroll');
|
|
2459
|
+
this._inputContainer.classList.remove('is-dragging-scroll');
|
|
2460
|
+
this._inputContainer.style.removeProperty('--select-multi-input-max-height');
|
|
2461
|
+
this._inputContainer.style.removeProperty('--select-multi-input-overflow-x');
|
|
2462
|
+
this._inputContainer.style.removeProperty('--select-multi-input-overflow-y');
|
|
2463
|
+
this._inputContainer.style.removeProperty('--select-multi-input-flex-wrap');
|
|
2464
|
+
this._inputContainer.style.removeProperty('--select-multi-input-align-content');
|
|
2465
|
+
return;
|
|
2466
|
+
}
|
|
2467
|
+
const maxHeight = this._config.multiSelectDisplay?.maxHeight ?? '160px';
|
|
2468
|
+
const overflowX = this._config.multiSelectDisplay?.overflowX ?? (mode === 'horizontal' ? 'auto' : 'hidden');
|
|
2469
|
+
const overflowY = this._config.multiSelectDisplay?.overflowY ?? (mode === 'horizontal' ? 'hidden' : 'auto');
|
|
2470
|
+
const flexWrap = mode === 'horizontal' ? 'nowrap' : 'wrap';
|
|
2471
|
+
const alignContent = mode === 'horizontal' ? 'center' : 'flex-start';
|
|
2472
|
+
this._inputContainer.setAttribute('data-multi-scroll-mode', mode);
|
|
2473
|
+
this._inputContainer.setAttribute('data-drag-scroll', String(dragEnabled && mode === 'horizontal'));
|
|
2474
|
+
this._inputContainer.style.setProperty('--select-multi-input-max-height', maxHeight);
|
|
2475
|
+
this._inputContainer.style.setProperty('--select-multi-input-overflow-x', overflowX);
|
|
2476
|
+
this._inputContainer.style.setProperty('--select-multi-input-overflow-y', overflowY);
|
|
2477
|
+
this._inputContainer.style.setProperty('--select-multi-input-flex-wrap', flexWrap);
|
|
2478
|
+
this._inputContainer.style.setProperty('--select-multi-input-align-content', alignContent);
|
|
2479
|
+
}
|
|
2480
|
+
_canUseHorizontalMultiScroll(target) {
|
|
2481
|
+
if (this._config.selection.mode !== 'multi')
|
|
2482
|
+
return false;
|
|
2483
|
+
if ((this._config.multiSelectDisplay?.mode ?? 'wrap') !== 'horizontal')
|
|
2484
|
+
return false;
|
|
2485
|
+
if (this._config.multiSelectDisplay?.dragScroll === false)
|
|
2486
|
+
return false;
|
|
2487
|
+
if (!target)
|
|
2488
|
+
return true;
|
|
2489
|
+
if (target.closest('.dropdown-arrow-container, .clear-control-button, .badge-remove'))
|
|
2490
|
+
return false;
|
|
2491
|
+
if (target.matches('.select-input'))
|
|
2492
|
+
return false;
|
|
2493
|
+
return true;
|
|
2494
|
+
}
|
|
2495
|
+
_isScrollableMultiSelectMode() {
|
|
2496
|
+
if (this._config.selection.mode !== 'multi')
|
|
2497
|
+
return false;
|
|
2498
|
+
const mode = this._config.multiSelectDisplay?.mode ?? 'wrap';
|
|
2499
|
+
return mode === 'vertical' || mode === 'horizontal';
|
|
2500
|
+
}
|
|
2501
|
+
_isPointerOnInputScrollbar(event) {
|
|
2502
|
+
if (!this._isScrollableMultiSelectMode())
|
|
2503
|
+
return false;
|
|
2504
|
+
const rect = this._inputContent.getBoundingClientRect();
|
|
2505
|
+
const verticalScrollbarWidth = this._inputContent.offsetWidth - this._inputContent.clientWidth;
|
|
2506
|
+
const horizontalScrollbarHeight = this._inputContent.offsetHeight - this._inputContent.clientHeight;
|
|
2507
|
+
if (verticalScrollbarWidth > 0
|
|
2508
|
+
&& event.clientX >= rect.right - verticalScrollbarWidth
|
|
2509
|
+
&& event.clientX <= rect.right
|
|
2510
|
+
&& event.clientY >= rect.top
|
|
2511
|
+
&& event.clientY <= rect.bottom) {
|
|
2512
|
+
return true;
|
|
2513
|
+
}
|
|
2514
|
+
if (horizontalScrollbarHeight > 0
|
|
2515
|
+
&& event.clientY >= rect.bottom - horizontalScrollbarHeight
|
|
2516
|
+
&& event.clientY <= rect.bottom
|
|
2517
|
+
&& event.clientX >= rect.left
|
|
2518
|
+
&& event.clientX <= rect.right) {
|
|
2519
|
+
return true;
|
|
2520
|
+
}
|
|
2521
|
+
return false;
|
|
2522
|
+
}
|
|
2523
|
+
_beginMultiScrollDrag(e) {
|
|
2524
|
+
const scrollHost = this._inputContent;
|
|
2525
|
+
this._multiScrollDrag.active = true;
|
|
2526
|
+
this._multiScrollDrag.moved = false;
|
|
2527
|
+
this._multiScrollDrag.pointerId = e.pointerId;
|
|
2528
|
+
this._multiScrollDrag.startX = e.clientX;
|
|
2529
|
+
this._multiScrollDrag.startScrollLeft = scrollHost.scrollLeft;
|
|
2530
|
+
this._inputContainer.classList.add('is-dragging-scroll');
|
|
2531
|
+
try {
|
|
2532
|
+
scrollHost.setPointerCapture(e.pointerId);
|
|
2533
|
+
}
|
|
2534
|
+
catch (_error) {
|
|
2535
|
+
// ignore pointer capture issues
|
|
2536
|
+
}
|
|
2537
|
+
}
|
|
2538
|
+
_updateMultiScrollDrag(e) {
|
|
2539
|
+
if (!this._multiScrollDrag.active || this._multiScrollDrag.pointerId !== e.pointerId)
|
|
2540
|
+
return;
|
|
2541
|
+
const deltaX = e.clientX - this._multiScrollDrag.startX;
|
|
2542
|
+
if (Math.abs(deltaX) > 3) {
|
|
2543
|
+
this._multiScrollDrag.moved = true;
|
|
2544
|
+
}
|
|
2545
|
+
this._inputContent.scrollLeft = this._multiScrollDrag.startScrollLeft - deltaX;
|
|
2546
|
+
}
|
|
2547
|
+
_endMultiScrollDrag(pointerId) {
|
|
2548
|
+
if (!this._multiScrollDrag.active)
|
|
2549
|
+
return;
|
|
2550
|
+
if (pointerId != null && this._multiScrollDrag.pointerId !== pointerId)
|
|
2551
|
+
return;
|
|
2552
|
+
try {
|
|
2553
|
+
if (this._multiScrollDrag.pointerId >= 0) {
|
|
2554
|
+
this._inputContent.releasePointerCapture(this._multiScrollDrag.pointerId);
|
|
2555
|
+
}
|
|
2556
|
+
}
|
|
2557
|
+
catch (_error) {
|
|
2558
|
+
// ignore pointer capture issues
|
|
2559
|
+
}
|
|
2560
|
+
this._multiScrollDrag.active = false;
|
|
2561
|
+
this._multiScrollDrag.pointerId = -1;
|
|
2562
|
+
this._inputContainer.classList.remove('is-dragging-scroll');
|
|
2563
|
+
}
|
|
2116
2564
|
_createInput() {
|
|
2117
2565
|
const input = document.createElement('input');
|
|
2118
2566
|
input.setAttribute('part', 'input');
|
|
@@ -2122,6 +2570,35 @@
|
|
|
2122
2570
|
input.placeholder = this._config.placeholder || 'Select an option...';
|
|
2123
2571
|
input.disabled = !this._config.enabled;
|
|
2124
2572
|
input.readOnly = !this._config.searchable;
|
|
2573
|
+
// Apply a direct inline reset so the input is only the writable text layer,
|
|
2574
|
+
// while the `.input-container` remains the sole visible control shell.
|
|
2575
|
+
input.style.all = 'unset';
|
|
2576
|
+
input.style.display = 'block';
|
|
2577
|
+
input.style.flex = '1 1 auto';
|
|
2578
|
+
input.style.width = '100%';
|
|
2579
|
+
input.style.maxWidth = '100%';
|
|
2580
|
+
input.style.minWidth = '0';
|
|
2581
|
+
input.style.minInlineSize = '0';
|
|
2582
|
+
input.style.minHeight = '0';
|
|
2583
|
+
input.style.padding = '0';
|
|
2584
|
+
input.style.margin = '0';
|
|
2585
|
+
input.style.border = '0';
|
|
2586
|
+
input.style.background = 'transparent';
|
|
2587
|
+
input.style.boxSizing = 'border-box';
|
|
2588
|
+
input.style.outline = 'none';
|
|
2589
|
+
input.style.font = 'inherit';
|
|
2590
|
+
input.style.fontFamily = 'inherit';
|
|
2591
|
+
input.style.lineHeight = 'inherit';
|
|
2592
|
+
input.style.color = 'inherit';
|
|
2593
|
+
input.style.alignSelf = 'center';
|
|
2594
|
+
input.style.appearance = 'none';
|
|
2595
|
+
input.style.webkitAppearance = 'none';
|
|
2596
|
+
input.style.boxShadow = 'none';
|
|
2597
|
+
input.style.borderRadius = '0';
|
|
2598
|
+
input.style.overflow = 'hidden';
|
|
2599
|
+
input.style.textOverflow = 'ellipsis';
|
|
2600
|
+
input.style.whiteSpace = 'nowrap';
|
|
2601
|
+
input.style.cursor = this._config.searchable ? 'text' : 'default';
|
|
2125
2602
|
// Update readonly when input is focused if searchable
|
|
2126
2603
|
input.addEventListener('focus', () => {
|
|
2127
2604
|
if (this._config.searchable) {
|
|
@@ -2132,7 +2609,22 @@
|
|
|
2132
2609
|
input.className += ' ' + this._config.styles.classNames.input;
|
|
2133
2610
|
}
|
|
2134
2611
|
if (this._config.styles.input) {
|
|
2135
|
-
|
|
2612
|
+
const inputStyles = { ...this._config.styles.input };
|
|
2613
|
+
// Route shell-like styling to .input-container so the control appears as
|
|
2614
|
+
// a single styled input instead of two visually separate layers.
|
|
2615
|
+
delete inputStyles.background;
|
|
2616
|
+
delete inputStyles.backgroundColor;
|
|
2617
|
+
delete inputStyles.border;
|
|
2618
|
+
delete inputStyles.borderColor;
|
|
2619
|
+
delete inputStyles.borderStyle;
|
|
2620
|
+
delete inputStyles.borderWidth;
|
|
2621
|
+
delete inputStyles.borderRadius;
|
|
2622
|
+
delete inputStyles.boxShadow;
|
|
2623
|
+
delete inputStyles.padding;
|
|
2624
|
+
delete inputStyles.height;
|
|
2625
|
+
delete inputStyles.minHeight;
|
|
2626
|
+
delete inputStyles.maxHeight;
|
|
2627
|
+
Object.assign(input.style, inputStyles);
|
|
2136
2628
|
}
|
|
2137
2629
|
input.setAttribute('role', 'combobox');
|
|
2138
2630
|
input.setAttribute('aria-expanded', 'false');
|
|
@@ -2176,7 +2668,7 @@
|
|
|
2176
2668
|
container.className = 'dropdown-arrow-container';
|
|
2177
2669
|
container.innerHTML = `
|
|
2178
2670
|
<svg class="dropdown-arrow" part="arrow" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2179
|
-
<path d="M4 6L8 10L12 6" stroke="currentColor" stroke-width="
|
|
2671
|
+
<path d="M4 6L8 10L12 6" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
|
2180
2672
|
</svg>
|
|
2181
2673
|
`;
|
|
2182
2674
|
return container;
|
|
@@ -2189,14 +2681,15 @@
|
|
|
2189
2681
|
const icon = document.createElement('span');
|
|
2190
2682
|
icon.className = 'clear-control-icon';
|
|
2191
2683
|
icon.setAttribute('part', 'clear-icon');
|
|
2192
|
-
icon.
|
|
2684
|
+
icon.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>`;
|
|
2193
2685
|
button.setAttribute('aria-label', this._config.clearControl.ariaLabel || 'Clear selection and search');
|
|
2194
2686
|
button.appendChild(icon);
|
|
2195
2687
|
this._clearControlIcon = icon;
|
|
2196
2688
|
return button;
|
|
2197
2689
|
}
|
|
2198
2690
|
_assembleDOM() {
|
|
2199
|
-
this.
|
|
2691
|
+
this._inputContent.appendChild(this._input);
|
|
2692
|
+
this._inputContainer.appendChild(this._inputContent);
|
|
2200
2693
|
if (this._clearControl) {
|
|
2201
2694
|
this._inputContainer.appendChild(this._clearControl);
|
|
2202
2695
|
}
|
|
@@ -2215,17 +2708,323 @@
|
|
|
2215
2708
|
this._dropdown.id = listboxId;
|
|
2216
2709
|
this._input.setAttribute('aria-controls', listboxId);
|
|
2217
2710
|
this._input.setAttribute('aria-owns', listboxId);
|
|
2711
|
+
this._syncInputContainerMode();
|
|
2218
2712
|
this._syncClearControlState();
|
|
2219
2713
|
}
|
|
2220
2714
|
_initializeStyles() {
|
|
2221
2715
|
const style = document.createElement('style');
|
|
2222
2716
|
style.textContent = `
|
|
2717
|
+
/* ═══════════════════════════════════════════════════════════════════════════
|
|
2718
|
+
ELEGANT SELECT COMPONENT — Refined Design System
|
|
2719
|
+
Formal aesthetics with sophisticated microinteractions
|
|
2720
|
+
═══════════════════════════════════════════════════════════════════════════ */
|
|
2721
|
+
|
|
2223
2722
|
:host {
|
|
2723
|
+
--select-primary: #1a1a2e;
|
|
2724
|
+
--select-primary-light: #16213e;
|
|
2725
|
+
--select-accent: #0f3460;
|
|
2726
|
+
--select-accent-hover: #e94560;
|
|
2727
|
+
--select-surface: #ffffff;
|
|
2728
|
+
--select-surface-elevated: #fafbfc;
|
|
2729
|
+
--select-border: #e1e5eb;
|
|
2730
|
+
--select-border-focus: #0f3460;
|
|
2731
|
+
--select-text: #1a1a2e;
|
|
2732
|
+
--select-text-muted: #6b7280;
|
|
2733
|
+
--select-text-placeholder: #9ca3af;
|
|
2734
|
+
--select-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.04);
|
|
2735
|
+
--select-shadow-md: 0 4px 12px rgba(0, 0, 0, 0.08);
|
|
2736
|
+
--select-shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.12);
|
|
2737
|
+
--select-shadow-focus: 0 0 0 3px rgba(15, 52, 96, 0.12);
|
|
2738
|
+
--select-radius-sm: 6px;
|
|
2739
|
+
--select-radius-md: 10px;
|
|
2740
|
+
--select-radius-lg: 14px;
|
|
2741
|
+
--select-transition-fast: 150ms cubic-bezier(0.4, 0, 0.2, 1);
|
|
2742
|
+
--select-transition-smooth: 250ms cubic-bezier(0.4, 0, 0.2, 1);
|
|
2743
|
+
--select-transition-bounce: 350ms cubic-bezier(0.34, 1.56, 0.64, 1);
|
|
2744
|
+
--select-badge-animation: badgeEnter 300ms cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
|
|
2745
|
+
--select-badge-enter-from-opacity: 0;
|
|
2746
|
+
--select-badge-enter-from-transform: scale(0.8) translateY(-4px);
|
|
2747
|
+
--select-badge-enter-to-opacity: 1;
|
|
2748
|
+
--select-badge-enter-to-transform: scale(1) translateY(0);
|
|
2749
|
+
--select-badge-active-transform: scale(0.98);
|
|
2750
|
+
--select-badge-hover-transform: scale(1.02);
|
|
2751
|
+
--select-badge-letter-spacing: 0.01em;
|
|
2752
|
+
--select-badge-hover-shadow: var(--select-shadow-md), inset 0 1px 0 rgba(255, 255, 255, 0.15);
|
|
2753
|
+
--select-badge-remove-icon-size: 10px;
|
|
2754
|
+
--select-badge-remove-focus-outline: 2px solid rgba(255, 255, 255, 0.5);
|
|
2755
|
+
--select-badge-remove-focus-offset: 1px;
|
|
2756
|
+
--select-badge-remove-hover-transform: scale(1.15) rotate(90deg);
|
|
2757
|
+
--select-badge-remove-active-transform: scale(0.95) rotate(90deg);
|
|
2758
|
+
--select-input-hover-border: var(--select-border-focus);
|
|
2759
|
+
--select-input-hover-shadow: var(--select-shadow-sm), 0 0 0 1px rgba(15, 52, 96, 0.05);
|
|
2760
|
+
--select-input-font-weight: 450;
|
|
2761
|
+
--select-input-letter-spacing: 0.01em;
|
|
2762
|
+
--select-input-disabled-opacity: 0.6;
|
|
2763
|
+
--select-input-overflow-x: hidden;
|
|
2764
|
+
--select-input-align-items: center;
|
|
2765
|
+
--select-input-align-content: center;
|
|
2766
|
+
--select-input-align-self: center;
|
|
2767
|
+
--select-multi-input-max-height: 160px;
|
|
2768
|
+
--select-multi-input-overflow-x: hidden;
|
|
2769
|
+
--select-multi-input-overflow-y: auto;
|
|
2770
|
+
--select-multi-input-flex-wrap: wrap;
|
|
2771
|
+
--select-multi-input-align-content: flex-start;
|
|
2772
|
+
--select-multi-input-horizontal-input-flex: 0 0 var(--select-multi-input-min-width, 96px);
|
|
2773
|
+
--select-multi-input-horizontal-cursor: grab;
|
|
2774
|
+
--select-multi-input-horizontal-active-cursor: grabbing;
|
|
2775
|
+
--select-multi-separator-inset-block: 10px;
|
|
2776
|
+
--select-multi-action-surface-bg: var(--select-input-bg, var(--select-surface));
|
|
2777
|
+
--select-multi-action-divider: 1px solid var(--select-border);
|
|
2778
|
+
--select-separator-opacity: 0.6;
|
|
2779
|
+
--select-separator-active-opacity: 1;
|
|
2780
|
+
--select-separator-position: var(--select-arrow-width, 42px);
|
|
2781
|
+
--select-separator-position-with-clear: calc(var(--select-arrow-right-with-clear, 34px) + var(--select-arrow-width, 42px));
|
|
2782
|
+
--select-separator-dark-bg: linear-gradient(
|
|
2783
|
+
to bottom,
|
|
2784
|
+
transparent 0%,
|
|
2785
|
+
var(--select-border) 20%,
|
|
2786
|
+
var(--select-border) 80%,
|
|
2787
|
+
transparent 100%
|
|
2788
|
+
);
|
|
2789
|
+
--select-arrow-open-transform: rotate(180deg);
|
|
2790
|
+
--select-clear-button-hover-transform: translateY(-50%) scale(1.1);
|
|
2791
|
+
--select-clear-button-active-transform: translateY(-50%) scale(0.95);
|
|
2792
|
+
--select-clear-button-focus-offset: 2px;
|
|
2793
|
+
--select-clear-icon-size: 14px;
|
|
2794
|
+
--select-dropdown-top: calc(100% + 6px);
|
|
2795
|
+
--select-dropdown-bottom: calc(100% + 6px);
|
|
2796
|
+
--select-dropdown-animation: dropdownEnter 200ms cubic-bezier(0.4, 0, 0.2, 1) forwards;
|
|
2797
|
+
--select-dropdown-enter-from-opacity: 0;
|
|
2798
|
+
--select-dropdown-enter-from-transform: translateY(-8px) scale(0.98);
|
|
2799
|
+
--select-dropdown-enter-to-opacity: 1;
|
|
2800
|
+
--select-dropdown-enter-to-transform: translateY(0) scale(1);
|
|
2801
|
+
--select-dropdown-top-transform-origin: bottom center;
|
|
2802
|
+
--select-dropdown-top-enter-from-transform: translateY(8px) scale(0.98);
|
|
2803
|
+
--select-dropdown-padding: 6px;
|
|
2804
|
+
--select-dropdown-scroll-behavior: smooth;
|
|
2805
|
+
--select-dropdown-transform-origin: top center;
|
|
2806
|
+
--select-scrollbar-width: 6px;
|
|
2807
|
+
--select-scrollbar-thumb-radius: 3px;
|
|
2808
|
+
--select-option-hover-transform: translateX(2px);
|
|
2809
|
+
--select-option-font-weight: 450;
|
|
2810
|
+
--select-option-margin: 2px 0;
|
|
2811
|
+
--select-option-disabled-opacity: 0.5;
|
|
2812
|
+
--select-option-disabled-cursor: not-allowed;
|
|
2813
|
+
--select-option-active-outline-offset: -2px;
|
|
2814
|
+
--select-option-selected-active-outline-offset: -2px;
|
|
2815
|
+
--select-option-selected-indicator-width: 3px;
|
|
2816
|
+
--select-option-selected-indicator-height: 60%;
|
|
2817
|
+
--select-option-selected-indicator-bg: var(--select-accent);
|
|
2818
|
+
--select-option-selected-indicator-radius: 0 2px 2px 0;
|
|
2819
|
+
--select-option-selected-indicator-left: 0;
|
|
2820
|
+
--select-option-selected-indicator-top: 50%;
|
|
2821
|
+
--select-option-selected-indicator-transform: translateY(-50%);
|
|
2822
|
+
--select-option-selected-indicator-animation: selectedIndicator 200ms cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
|
|
2823
|
+
--select-option-selected-indicator-from-height: 0;
|
|
2824
|
+
--select-option-selected-indicator-to-height: 60%;
|
|
2825
|
+
--select-option-selected-indicator-from-opacity: 0;
|
|
2826
|
+
--select-option-selected-indicator-to-opacity: 1;
|
|
2827
|
+
--select-option-pressed-transform: translateX(2px) scale(0.99);
|
|
2828
|
+
--select-option-selected-pressed-transform: scale(0.99);
|
|
2829
|
+
--select-button-hover-transform: translateY(-1px);
|
|
2830
|
+
--select-button-active-transform: translateY(0) scale(0.98);
|
|
2831
|
+
--select-button-font-weight: 550;
|
|
2832
|
+
--select-button-letter-spacing: 0.02em;
|
|
2833
|
+
--select-spinner-animation: spin 0.8s cubic-bezier(0.4, 0, 0.2, 1) infinite;
|
|
2834
|
+
--select-searching-spinner-active-color: var(--select-accent);
|
|
2835
|
+
--select-badge-remove-margin-left: 2px;
|
|
2836
|
+
--select-badge-remove-radius: 50%;
|
|
2837
|
+
--select-badge-remove-font-weight: 600;
|
|
2838
|
+
--select-empty-gap: 8px;
|
|
2839
|
+
--select-searching-gap: 8px;
|
|
2840
|
+
--select-searching-spinner-size: 24px;
|
|
2841
|
+
--select-searching-spinner-border: 2px solid var(--select-border);
|
|
2842
|
+
--select-searching-spinner-animation: var(--select-spinner-animation);
|
|
2843
|
+
--select-group-header-separator-margin-top: 8px;
|
|
2844
|
+
--select-group-header-separator-padding-top: 14px;
|
|
2845
|
+
--select-group-header-separator-border-top: 1px solid var(--select-border);
|
|
2846
|
+
--select-reduced-motion-duration: 0.01ms;
|
|
2847
|
+
--select-reduced-motion-iteration-count: 1;
|
|
2848
|
+
--select-high-contrast-border-width: 2px;
|
|
2849
|
+
--select-high-contrast-indicator-width: 4px;
|
|
2850
|
+
--select-high-contrast-focus-outline-width: 3px;
|
|
2851
|
+
--select-high-contrast-focus-outline-color: Highlight;
|
|
2852
|
+
--select-touch-target-min-height: 44px;
|
|
2853
|
+
--select-badge-dark-bg: linear-gradient(135deg, var(--select-accent) 0%, #4f46e5 100%);
|
|
2854
|
+
--select-host-z-index: auto;
|
|
2855
|
+
--select-host-open-z-index: var(--select-dropdown-z-index, 1000);
|
|
2856
|
+
--select-ancestor-open-z-index: var(--select-host-open-z-index, var(--select-dropdown-z-index, 1000));
|
|
2857
|
+
|
|
2224
2858
|
display: block;
|
|
2225
2859
|
position: relative;
|
|
2860
|
+
z-index: var(--select-host-z-index, auto);
|
|
2226
2861
|
width: var(--select-width, 100%);
|
|
2227
2862
|
height: var(--select-height, auto);
|
|
2863
|
+
font-family: var(--select-font-family, inherit);
|
|
2864
|
+
font-size: var(--select-font-size, inherit);
|
|
2865
|
+
line-height: var(--select-line-height, inherit);
|
|
2866
|
+
color: var(--select-color, inherit);
|
|
2867
|
+
}
|
|
2868
|
+
|
|
2869
|
+
:host([data-open="true"]) {
|
|
2870
|
+
z-index: var(--select-host-open-z-index, var(--select-dropdown-z-index, 1000));
|
|
2871
|
+
}
|
|
2872
|
+
|
|
2873
|
+
:host([dir="ltr"]) {
|
|
2874
|
+
direction: ltr;
|
|
2875
|
+
}
|
|
2876
|
+
|
|
2877
|
+
:host([dir="rtl"]) {
|
|
2878
|
+
direction: rtl;
|
|
2879
|
+
}
|
|
2880
|
+
|
|
2881
|
+
/* ─────────────────────────────────────────────────────────────────────────
|
|
2882
|
+
Selection Badges — Refined pill design with elegant interactions
|
|
2883
|
+
───────────────────────────────────────────────────────────────────────── */
|
|
2884
|
+
|
|
2885
|
+
.selection-badge {
|
|
2886
|
+
display: inline-flex;
|
|
2887
|
+
align-items: center;
|
|
2888
|
+
gap: var(--select-badge-gap, 6px);
|
|
2889
|
+
flex: 0 1 auto;
|
|
2890
|
+
width: var(--select-badge-width, auto);
|
|
2891
|
+
min-width: var(--select-badge-min-width, 0);
|
|
2892
|
+
height: var(--select-badge-height, auto);
|
|
2893
|
+
min-height: var(--select-badge-min-height, 26px);
|
|
2894
|
+
padding: var(--select-badge-padding, 4px 10px 4px 12px);
|
|
2895
|
+
margin: var(--select-badge-margin, 3px);
|
|
2896
|
+
background: var(--select-badge-bg, linear-gradient(135deg, var(--select-accent) 0%, var(--select-primary-light) 100%));
|
|
2897
|
+
color: var(--select-badge-color, #ffffff);
|
|
2898
|
+
border: var(--select-badge-border, none);
|
|
2899
|
+
border-radius: var(--select-badge-border-radius, 999px);
|
|
2900
|
+
box-shadow: var(--select-badge-shadow, var(--select-shadow-sm), inset 0 1px 0 rgba(255, 255, 255, 0.1));
|
|
2901
|
+
box-sizing: border-box;
|
|
2902
|
+
font-size: var(--select-badge-font-size, 0.8667em);
|
|
2903
|
+
font-weight: var(--select-badge-font-weight, 500);
|
|
2904
|
+
line-height: var(--select-badge-line-height, 1.2);
|
|
2905
|
+
letter-spacing: var(--select-badge-letter-spacing);
|
|
2906
|
+
max-width: var(--select-badge-max-width, 100%);
|
|
2907
|
+
overflow: hidden;
|
|
2908
|
+
transform: scale(1);
|
|
2909
|
+
transition:
|
|
2910
|
+
transform var(--select-transition-bounce),
|
|
2911
|
+
box-shadow var(--select-transition-fast),
|
|
2912
|
+
background var(--select-transition-fast);
|
|
2913
|
+
animation: var(--select-badge-animation);
|
|
2914
|
+
}
|
|
2915
|
+
|
|
2916
|
+
@keyframes badgeEnter {
|
|
2917
|
+
0% {
|
|
2918
|
+
opacity: var(--select-badge-enter-from-opacity);
|
|
2919
|
+
transform: var(--select-badge-enter-from-transform);
|
|
2920
|
+
}
|
|
2921
|
+
100% {
|
|
2922
|
+
opacity: var(--select-badge-enter-to-opacity);
|
|
2923
|
+
transform: var(--select-badge-enter-to-transform);
|
|
2924
|
+
}
|
|
2925
|
+
}
|
|
2926
|
+
|
|
2927
|
+
.selection-badge:hover {
|
|
2928
|
+
background: var(--select-badge-hover-bg, var(--select-badge-bg, linear-gradient(135deg, var(--select-accent) 0%, var(--select-primary-light) 100%)));
|
|
2929
|
+
color: var(--select-badge-hover-color, var(--select-badge-color, #ffffff));
|
|
2930
|
+
border: var(--select-badge-hover-border, var(--select-badge-border, none));
|
|
2931
|
+
box-shadow: var(--select-badge-hover-shadow);
|
|
2932
|
+
transform: var(--select-badge-hover-transform);
|
|
2933
|
+
}
|
|
2934
|
+
|
|
2935
|
+
.selection-badge:active {
|
|
2936
|
+
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%))));
|
|
2937
|
+
color: var(--select-badge-active-color, var(--select-badge-hover-color, var(--select-badge-color, #ffffff)));
|
|
2938
|
+
border: var(--select-badge-active-border, var(--select-badge-hover-border, var(--select-badge-border, none)));
|
|
2939
|
+
box-shadow: var(--select-badge-active-shadow, var(--select-badge-hover-shadow));
|
|
2940
|
+
transform: var(--select-badge-active-transform);
|
|
2941
|
+
}
|
|
2942
|
+
|
|
2943
|
+
.selection-badge-label {
|
|
2944
|
+
display: block;
|
|
2945
|
+
min-width: 0;
|
|
2946
|
+
overflow: hidden;
|
|
2947
|
+
text-overflow: ellipsis;
|
|
2948
|
+
white-space: nowrap;
|
|
2949
|
+
color: var(--select-badge-label-color, inherit);
|
|
2950
|
+
font-size: var(--select-badge-label-font-size, inherit);
|
|
2951
|
+
font-weight: var(--select-badge-label-font-weight, inherit);
|
|
2952
|
+
line-height: var(--select-badge-label-line-height, var(--select-badge-line-height, 1.2));
|
|
2953
|
+
letter-spacing: var(--select-badge-label-letter-spacing, inherit);
|
|
2954
|
+
text-align: var(--select-badge-label-text-align, start);
|
|
2955
|
+
}
|
|
2956
|
+
|
|
2957
|
+
.badge-remove {
|
|
2958
|
+
display: inline-flex;
|
|
2959
|
+
align-items: center;
|
|
2960
|
+
justify-content: center;
|
|
2961
|
+
width: var(--select-badge-remove-size, 18px);
|
|
2962
|
+
height: var(--select-badge-remove-size, 18px);
|
|
2963
|
+
min-width: var(--select-badge-remove-min-width, var(--select-badge-remove-size, 18px));
|
|
2964
|
+
min-height: var(--select-badge-remove-min-height, var(--select-badge-remove-size, 18px));
|
|
2965
|
+
padding: 0;
|
|
2966
|
+
margin-left: var(--select-badge-remove-margin-left);
|
|
2967
|
+
background: var(--select-badge-remove-bg, rgba(255, 255, 255, 0.2));
|
|
2968
|
+
border: var(--select-badge-remove-border, none);
|
|
2969
|
+
border-radius: var(--select-badge-remove-radius);
|
|
2970
|
+
color: var(--select-badge-remove-color, #ffffff);
|
|
2971
|
+
font-size: var(--select-badge-remove-font-size, 0.7333em);
|
|
2972
|
+
font-weight: var(--select-badge-remove-font-weight);
|
|
2973
|
+
line-height: 1;
|
|
2974
|
+
cursor: pointer;
|
|
2975
|
+
flex: 0 0 auto;
|
|
2976
|
+
transition:
|
|
2977
|
+
background var(--select-transition-fast),
|
|
2978
|
+
color var(--select-transition-fast),
|
|
2979
|
+
border-color var(--select-transition-fast),
|
|
2980
|
+
box-shadow var(--select-transition-fast),
|
|
2981
|
+
transform var(--select-transition-bounce);
|
|
2982
|
+
}
|
|
2983
|
+
|
|
2984
|
+
.badge-remove-icon {
|
|
2985
|
+
display: inline-flex;
|
|
2986
|
+
align-items: center;
|
|
2987
|
+
justify-content: center;
|
|
2988
|
+
width: var(--select-badge-remove-icon-size, 10px);
|
|
2989
|
+
height: var(--select-badge-remove-icon-size, 10px);
|
|
2990
|
+
pointer-events: none;
|
|
2991
|
+
}
|
|
2992
|
+
|
|
2993
|
+
.badge-remove-icon svg {
|
|
2994
|
+
width: 100%;
|
|
2995
|
+
height: 100%;
|
|
2996
|
+
display: block;
|
|
2997
|
+
}
|
|
2998
|
+
|
|
2999
|
+
.badge-remove:hover {
|
|
3000
|
+
background: var(--select-badge-remove-hover-bg, rgba(233, 69, 96, 0.9));
|
|
3001
|
+
color: var(--select-badge-remove-hover-color, var(--select-badge-remove-color, #ffffff));
|
|
3002
|
+
border: var(--select-badge-remove-hover-border, var(--select-badge-remove-border, none));
|
|
3003
|
+
box-shadow: var(--select-badge-remove-hover-shadow, none);
|
|
3004
|
+
transform: var(--select-badge-remove-hover-transform);
|
|
2228
3005
|
}
|
|
3006
|
+
|
|
3007
|
+
.badge-remove:focus-visible {
|
|
3008
|
+
outline: var(--select-badge-remove-focus-outline);
|
|
3009
|
+
outline-offset: var(--select-badge-remove-focus-offset);
|
|
3010
|
+
}
|
|
3011
|
+
|
|
3012
|
+
.badge-remove:active {
|
|
3013
|
+
background: var(--select-badge-remove-active-bg, var(--select-badge-remove-hover-bg, rgba(233, 69, 96, 0.9)));
|
|
3014
|
+
color: var(--select-badge-remove-active-color, var(--select-badge-remove-hover-color, var(--select-badge-remove-color, #ffffff)));
|
|
3015
|
+
border: var(--select-badge-remove-active-border, var(--select-badge-remove-hover-border, var(--select-badge-remove-border, none)));
|
|
3016
|
+
box-shadow: var(--select-badge-remove-active-shadow, var(--select-badge-remove-hover-shadow, none));
|
|
3017
|
+
transform: var(--select-badge-remove-active-transform);
|
|
3018
|
+
}
|
|
3019
|
+
|
|
3020
|
+
:host([dir="rtl"]) .badge-remove {
|
|
3021
|
+
margin-left: 0;
|
|
3022
|
+
margin-right: var(--select-badge-remove-margin-left);
|
|
3023
|
+
}
|
|
3024
|
+
|
|
3025
|
+
/* ─────────────────────────────────────────────────────────────────────────
|
|
3026
|
+
Input Container — Sophisticated control shell
|
|
3027
|
+
───────────��───────────────────────────────────────────────────────────── */
|
|
2229
3028
|
|
|
2230
3029
|
.select-container {
|
|
2231
3030
|
position: relative;
|
|
@@ -2236,364 +3035,644 @@
|
|
|
2236
3035
|
position: relative;
|
|
2237
3036
|
width: 100%;
|
|
2238
3037
|
display: flex;
|
|
2239
|
-
align-items: center;
|
|
2240
|
-
flex-wrap:
|
|
3038
|
+
align-items: var(--select-input-align-items, center);
|
|
3039
|
+
flex-wrap: nowrap;
|
|
3040
|
+
justify-content: var(--select-input-justify-content, flex-start);
|
|
2241
3041
|
gap: var(--select-input-gap, 6px);
|
|
2242
|
-
padding: var(--select-input-padding,
|
|
3042
|
+
padding: var(--select-input-padding, 10px 52px 10px 14px);
|
|
2243
3043
|
height: var(--select-input-height, auto);
|
|
2244
|
-
min-height: var(--select-input-min-height,
|
|
3044
|
+
min-height: var(--select-input-min-height, 48px);
|
|
2245
3045
|
max-height: var(--select-input-max-height, 160px);
|
|
2246
|
-
overflow
|
|
2247
|
-
align-content:
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
border
|
|
3046
|
+
overflow: hidden;
|
|
3047
|
+
align-content: var(--select-input-align-content, center);
|
|
3048
|
+
text-align: var(--select-input-text-align, start);
|
|
3049
|
+
background: var(--select-input-bg, var(--select-surface));
|
|
3050
|
+
border: var(--select-input-border, 1.5px solid var(--select-border));
|
|
3051
|
+
border-radius: var(--select-input-border-radius, var(--select-radius-md));
|
|
3052
|
+
box-shadow: var(--select-shadow-sm);
|
|
2251
3053
|
box-sizing: border-box;
|
|
2252
|
-
transition:
|
|
3054
|
+
transition:
|
|
3055
|
+
border-color var(--select-transition-fast),
|
|
3056
|
+
box-shadow var(--select-transition-smooth),
|
|
3057
|
+
transform var(--select-transition-fast);
|
|
3058
|
+
}
|
|
3059
|
+
|
|
3060
|
+
.input-content {
|
|
3061
|
+
position: relative;
|
|
3062
|
+
display: flex;
|
|
3063
|
+
flex: 1 1 auto;
|
|
3064
|
+
width: 100%;
|
|
3065
|
+
min-width: 0;
|
|
3066
|
+
min-height: 0;
|
|
3067
|
+
align-self: stretch;
|
|
3068
|
+
align-items: var(--select-input-align-items, center);
|
|
3069
|
+
align-content: var(--select-input-align-content, center);
|
|
3070
|
+
justify-content: var(--select-input-justify-content, flex-start);
|
|
3071
|
+
flex-wrap: nowrap;
|
|
3072
|
+
gap: var(--select-input-gap, 6px);
|
|
3073
|
+
overflow-x: var(--select-input-overflow-x, hidden);
|
|
3074
|
+
overflow-y: var(--select-input-overflow-y, hidden);
|
|
3075
|
+
scrollbar-width: thin;
|
|
3076
|
+
box-sizing: border-box;
|
|
3077
|
+
}
|
|
3078
|
+
|
|
3079
|
+
.input-container:hover {
|
|
3080
|
+
border-color: var(--select-input-hover-border);
|
|
3081
|
+
box-shadow: var(--select-input-hover-shadow);
|
|
3082
|
+
}
|
|
3083
|
+
|
|
3084
|
+
.input-container.input-container--single {
|
|
3085
|
+
flex-wrap: nowrap;
|
|
3086
|
+
align-content: center;
|
|
3087
|
+
}
|
|
3088
|
+
|
|
3089
|
+
.input-container.input-container--multi {
|
|
3090
|
+
max-height: var(--select-multi-input-max-height, var(--select-input-max-height, 160px));
|
|
3091
|
+
}
|
|
3092
|
+
|
|
3093
|
+
.input-container.input-container--multi .input-content {
|
|
3094
|
+
flex-wrap: var(--select-multi-input-flex-wrap, wrap);
|
|
3095
|
+
align-content: var(--select-multi-input-align-content, flex-start);
|
|
3096
|
+
overflow-x: var(--select-multi-input-overflow-x, hidden);
|
|
3097
|
+
overflow-y: var(--select-multi-input-overflow-y, auto);
|
|
3098
|
+
}
|
|
3099
|
+
|
|
3100
|
+
.input-container.input-container--multi::after {
|
|
3101
|
+
top: var(--select-multi-separator-inset-block, 10px);
|
|
3102
|
+
bottom: var(--select-multi-separator-inset-block, 10px);
|
|
3103
|
+
height: auto;
|
|
3104
|
+
transform: none;
|
|
3105
|
+
}
|
|
3106
|
+
|
|
3107
|
+
.input-container.input-container--multi[data-multi-scroll-mode="horizontal"] {
|
|
3108
|
+
align-items: stretch;
|
|
3109
|
+
}
|
|
3110
|
+
|
|
3111
|
+
.input-container.input-container--multi[data-multi-scroll-mode="horizontal"] .input-content {
|
|
3112
|
+
cursor: var(--select-multi-input-horizontal-cursor, grab);
|
|
3113
|
+
overflow-y: hidden;
|
|
3114
|
+
overscroll-behavior-x: contain;
|
|
3115
|
+
}
|
|
3116
|
+
|
|
3117
|
+
.input-container.input-container--multi[data-multi-scroll-mode="horizontal"]::after {
|
|
3118
|
+
display: none;
|
|
3119
|
+
}
|
|
3120
|
+
|
|
3121
|
+
.input-container.input-container--multi[data-multi-scroll-mode="horizontal"].is-dragging-scroll .input-content {
|
|
3122
|
+
cursor: var(--select-multi-input-horizontal-active-cursor, grabbing);
|
|
3123
|
+
user-select: none;
|
|
3124
|
+
}
|
|
3125
|
+
|
|
3126
|
+
.input-container.input-container--multi[data-multi-scroll-mode="horizontal"] .input-content .selection-badge {
|
|
3127
|
+
flex: 0 0 auto;
|
|
3128
|
+
}
|
|
3129
|
+
|
|
3130
|
+
.input-container.input-container--multi[data-multi-scroll-mode="horizontal"] .input-content > .select-input,
|
|
3131
|
+
.input-container.input-container--multi[data-multi-scroll-mode="horizontal"] .input-content > input.select-input,
|
|
3132
|
+
.input-container.input-container--multi[data-multi-scroll-mode="horizontal"] .input-content > .select-input[type="text"] {
|
|
3133
|
+
flex: var(--select-multi-input-horizontal-input-flex, 0 0 var(--select-multi-input-min-width, 96px));
|
|
3134
|
+
}
|
|
3135
|
+
|
|
3136
|
+
.input-container.input-container--multi[data-multi-scroll-mode="horizontal"] .dropdown-arrow-container {
|
|
3137
|
+
background: var(--select-multi-action-surface-bg, var(--select-input-bg, var(--select-surface)));
|
|
3138
|
+
border-left: var(--select-multi-action-divider, 1px solid var(--select-border));
|
|
3139
|
+
z-index: 4;
|
|
3140
|
+
}
|
|
3141
|
+
|
|
3142
|
+
.input-container.input-container--multi[data-multi-scroll-mode="horizontal"] .dropdown-arrow-container.with-clear-control {
|
|
3143
|
+
right: var(--select-arrow-right-with-clear, 34px);
|
|
3144
|
+
}
|
|
3145
|
+
|
|
3146
|
+
:host([dir="rtl"]) .input-container.input-container--multi[data-multi-scroll-mode="horizontal"] .dropdown-arrow-container {
|
|
3147
|
+
border-left: none;
|
|
3148
|
+
border-right: var(--select-multi-action-divider, 1px solid var(--select-border));
|
|
3149
|
+
}
|
|
3150
|
+
|
|
3151
|
+
:host([dir="rtl"]) .input-container.input-container--multi[data-multi-scroll-mode="horizontal"] .dropdown-arrow-container.with-clear-control {
|
|
3152
|
+
right: auto;
|
|
3153
|
+
left: var(--select-arrow-right-with-clear, 34px);
|
|
3154
|
+
}
|
|
3155
|
+
|
|
3156
|
+
.input-container.input-container--multi[data-multi-scroll-mode="horizontal"] .clear-control-button {
|
|
3157
|
+
background: var(--select-multi-action-surface-bg, var(--select-input-bg, var(--select-surface)));
|
|
3158
|
+
z-index: 4;
|
|
2253
3159
|
}
|
|
2254
3160
|
|
|
2255
3161
|
.input-container:focus-within {
|
|
2256
|
-
border-color: var(--select-input-focus-border, var(--select-border-focus
|
|
2257
|
-
box-shadow: var(--select-
|
|
3162
|
+
border-color: var(--select-input-focus-border, var(--select-border-focus));
|
|
3163
|
+
box-shadow: var(--select-shadow-focus), var(--select-shadow-sm);
|
|
2258
3164
|
}
|
|
2259
3165
|
|
|
2260
|
-
/*
|
|
3166
|
+
/* Elegant separator line before arrow */
|
|
2261
3167
|
.input-container::after {
|
|
2262
3168
|
content: '';
|
|
2263
3169
|
position: absolute;
|
|
2264
3170
|
top: 50%;
|
|
2265
|
-
right: var(--select-separator-position, var(--select-
|
|
3171
|
+
right: var(--select-separator-position, var(--select-arrow-width, 42px));
|
|
2266
3172
|
transform: translateY(-50%);
|
|
2267
|
-
width: var(--select-separator-width,
|
|
2268
|
-
height: var(--select-separator-height,
|
|
2269
|
-
background: var(--select-separator-bg,
|
|
3173
|
+
width: var(--select-separator-width, 1px);
|
|
3174
|
+
height: var(--select-separator-height, 50%);
|
|
3175
|
+
background: var(--select-separator-bg, linear-gradient(
|
|
2270
3176
|
to bottom,
|
|
2271
3177
|
transparent 0%,
|
|
2272
|
-
|
|
2273
|
-
|
|
3178
|
+
var(--select-border) 20%,
|
|
3179
|
+
var(--select-border) 80%,
|
|
2274
3180
|
transparent 100%
|
|
2275
|
-
))
|
|
3181
|
+
));
|
|
2276
3182
|
pointer-events: none;
|
|
2277
3183
|
z-index: 1;
|
|
3184
|
+
opacity: var(--select-separator-opacity);
|
|
3185
|
+
transition: opacity var(--select-transition-fast);
|
|
3186
|
+
}
|
|
3187
|
+
|
|
3188
|
+
.input-container:hover::after,
|
|
3189
|
+
.input-container:focus-within::after {
|
|
3190
|
+
opacity: var(--select-separator-active-opacity);
|
|
3191
|
+
}
|
|
3192
|
+
|
|
3193
|
+
:host([dir="rtl"]) .input-container::after {
|
|
3194
|
+
right: auto;
|
|
3195
|
+
left: var(--select-separator-position, var(--select-arrow-width, 42px));
|
|
2278
3196
|
}
|
|
2279
3197
|
|
|
3198
|
+
/* ─────────────────────────────────────────────────────────────────────────
|
|
3199
|
+
Dropdown Arrow — Smooth rotation with refined styling
|
|
3200
|
+
───────────────────────────────────────────────────────────────────────── */
|
|
3201
|
+
|
|
2280
3202
|
.dropdown-arrow-container {
|
|
2281
3203
|
position: absolute;
|
|
2282
3204
|
top: 0;
|
|
2283
3205
|
right: 0;
|
|
2284
3206
|
bottom: 0;
|
|
2285
|
-
width: var(--select-arrow-width,
|
|
2286
|
-
/* allow explicit height override even though container normally stretches */
|
|
3207
|
+
width: var(--select-arrow-width, 42px);
|
|
2287
3208
|
height: var(--select-arrow-height, auto);
|
|
2288
3209
|
display: flex;
|
|
2289
3210
|
align-items: center;
|
|
2290
3211
|
justify-content: center;
|
|
2291
3212
|
cursor: pointer;
|
|
2292
|
-
|
|
2293
|
-
border-radius: var(--select-arrow-border-radius, 0 4px 4px 0);
|
|
3213
|
+
border-radius: var(--select-arrow-border-radius, 0 var(--select-radius-md) var(--select-radius-md) 0);
|
|
2294
3214
|
z-index: 2;
|
|
3215
|
+
transition: background-color var(--select-transition-fast);
|
|
2295
3216
|
}
|
|
2296
3217
|
|
|
2297
3218
|
.input-container.has-clear-control {
|
|
2298
|
-
padding: var(--select-input-padding-with-clear,
|
|
3219
|
+
padding: var(--select-input-padding-with-clear, 10px 84px 10px 14px);
|
|
2299
3220
|
}
|
|
2300
3221
|
|
|
2301
3222
|
.input-container.has-clear-control::after {
|
|
2302
|
-
right: var(--select-separator-position-with-clear, var(--select-
|
|
3223
|
+
right: var(--select-separator-position-with-clear, calc(var(--select-arrow-right-with-clear, 34px) + var(--select-arrow-width, 42px)));
|
|
2303
3224
|
}
|
|
2304
3225
|
|
|
2305
3226
|
.dropdown-arrow-container.with-clear-control {
|
|
2306
|
-
right: var(--select-arrow-right-with-clear,
|
|
3227
|
+
right: var(--select-arrow-right-with-clear, 34px);
|
|
3228
|
+
}
|
|
3229
|
+
|
|
3230
|
+
:host([dir="rtl"]) .dropdown-arrow-container {
|
|
3231
|
+
right: auto;
|
|
3232
|
+
left: 0;
|
|
3233
|
+
border-radius: var(--select-arrow-border-radius-rtl, var(--select-radius-md) 0 0 var(--select-radius-md));
|
|
3234
|
+
}
|
|
3235
|
+
|
|
3236
|
+
:host([dir="rtl"]) .input-container.has-clear-control::after {
|
|
3237
|
+
right: auto;
|
|
3238
|
+
left: var(--select-separator-position-with-clear, calc(var(--select-arrow-right-with-clear, 34px) + var(--select-arrow-width, 42px)));
|
|
3239
|
+
}
|
|
3240
|
+
|
|
3241
|
+
:host([dir="rtl"]) .dropdown-arrow-container.with-clear-control {
|
|
3242
|
+
right: auto;
|
|
3243
|
+
left: var(--select-arrow-right-with-clear, 34px);
|
|
2307
3244
|
}
|
|
2308
3245
|
|
|
3246
|
+
/* ─────────────────────────────────────────────────────────────────────────
|
|
3247
|
+
Clear Control — Minimal and elegant dismiss button
|
|
3248
|
+
───────────────────────────────────────────────────────────────────────── */
|
|
3249
|
+
|
|
2309
3250
|
.clear-control-button {
|
|
2310
3251
|
position: absolute;
|
|
2311
3252
|
top: 50%;
|
|
2312
|
-
right: var(--select-clear-button-right,
|
|
3253
|
+
right: var(--select-clear-button-right, 8px);
|
|
2313
3254
|
transform: translateY(-50%);
|
|
2314
|
-
width: var(--select-clear-button-size,
|
|
2315
|
-
height: var(--select-clear-button-size,
|
|
3255
|
+
width: var(--select-clear-button-size, 26px);
|
|
3256
|
+
height: var(--select-clear-button-size, 26px);
|
|
2316
3257
|
border: var(--select-clear-button-border, none);
|
|
2317
|
-
border-radius: var(--select-clear-button-radius,
|
|
3258
|
+
border-radius: var(--select-clear-button-radius, 50%);
|
|
2318
3259
|
background: var(--select-clear-button-bg, transparent);
|
|
2319
|
-
color: var(--select-clear-button-color,
|
|
3260
|
+
color: var(--select-clear-button-color, var(--select-text-muted));
|
|
2320
3261
|
display: inline-flex;
|
|
2321
3262
|
align-items: center;
|
|
2322
3263
|
justify-content: center;
|
|
2323
3264
|
cursor: pointer;
|
|
2324
3265
|
z-index: 3;
|
|
2325
|
-
transition:
|
|
3266
|
+
transition:
|
|
3267
|
+
background var(--select-transition-fast),
|
|
3268
|
+
color var(--select-transition-fast),
|
|
3269
|
+
transform var(--select-transition-bounce);
|
|
2326
3270
|
}
|
|
2327
3271
|
|
|
2328
3272
|
.clear-control-button:hover {
|
|
2329
|
-
background: var(--select-clear-button-hover-bg, rgba(
|
|
2330
|
-
color: var(--select-clear-button-hover-color,
|
|
3273
|
+
background: var(--select-clear-button-hover-bg, rgba(233, 69, 96, 0.1));
|
|
3274
|
+
color: var(--select-clear-button-hover-color, var(--select-accent-hover));
|
|
3275
|
+
transform: var(--select-clear-button-hover-transform);
|
|
3276
|
+
}
|
|
3277
|
+
|
|
3278
|
+
.clear-control-button:active {
|
|
3279
|
+
transform: var(--select-clear-button-active-transform);
|
|
2331
3280
|
}
|
|
2332
3281
|
|
|
2333
3282
|
.clear-control-button:focus-visible {
|
|
2334
|
-
outline: var(--select-clear-button-focus-outline, 2px solid
|
|
2335
|
-
outline-offset:
|
|
3283
|
+
outline: var(--select-clear-button-focus-outline, 2px solid var(--select-border-focus));
|
|
3284
|
+
outline-offset: var(--select-clear-button-focus-offset);
|
|
2336
3285
|
}
|
|
2337
3286
|
|
|
2338
3287
|
.clear-control-button[hidden] {
|
|
2339
3288
|
display: none;
|
|
2340
3289
|
}
|
|
2341
3290
|
|
|
3291
|
+
:host([dir="rtl"]) .clear-control-button {
|
|
3292
|
+
right: auto;
|
|
3293
|
+
left: var(--select-clear-button-right, 8px);
|
|
3294
|
+
}
|
|
3295
|
+
|
|
2342
3296
|
.clear-control-icon {
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
font-weight: var(--select-clear-icon-weight, 500);
|
|
3297
|
+
width: var(--select-clear-icon-size);
|
|
3298
|
+
height: var(--select-clear-icon-size);
|
|
2346
3299
|
pointer-events: none;
|
|
2347
3300
|
}
|
|
2348
3301
|
|
|
2349
|
-
.
|
|
2350
|
-
|
|
3302
|
+
.clear-control-icon svg {
|
|
3303
|
+
width: 100%;
|
|
3304
|
+
height: 100%;
|
|
2351
3305
|
}
|
|
2352
3306
|
|
|
2353
|
-
.dropdown-arrow:hover {
|
|
2354
|
-
|
|
2355
|
-
color: var(--select-arrow-hover, var(--select-arrow-hover-color, #667eea));
|
|
3307
|
+
.dropdown-arrow-container:hover {
|
|
3308
|
+
background-color: var(--select-arrow-hover-bg, rgba(15, 52, 96, 0.05));
|
|
2356
3309
|
}
|
|
2357
3310
|
|
|
2358
3311
|
.dropdown-arrow {
|
|
2359
|
-
width: var(--select-arrow-
|
|
2360
|
-
height: var(--select-arrow-
|
|
2361
|
-
color: var(--select-arrow-color,
|
|
2362
|
-
transition:
|
|
2363
|
-
|
|
3312
|
+
width: var(--select-arrow-size, 18px);
|
|
3313
|
+
height: var(--select-arrow-size, 18px);
|
|
3314
|
+
color: var(--select-arrow-color, var(--select-text-muted));
|
|
3315
|
+
transition:
|
|
3316
|
+
transform var(--select-transition-smooth),
|
|
3317
|
+
color var(--select-transition-fast);
|
|
3318
|
+
transform-origin: center;
|
|
2364
3319
|
}
|
|
2365
3320
|
|
|
2366
3321
|
.dropdown-arrow path {
|
|
2367
|
-
stroke-width: var(--select-arrow-stroke-width,
|
|
3322
|
+
stroke-width: var(--select-arrow-stroke-width, 1.5);
|
|
2368
3323
|
}
|
|
2369
3324
|
|
|
2370
3325
|
.dropdown-arrow-container:hover .dropdown-arrow {
|
|
2371
|
-
color: var(--select-arrow-hover-color,
|
|
3326
|
+
color: var(--select-arrow-hover-color, var(--select-accent));
|
|
2372
3327
|
}
|
|
2373
3328
|
|
|
2374
3329
|
.dropdown-arrow.open {
|
|
2375
|
-
transform:
|
|
3330
|
+
transform: var(--select-arrow-open-transform);
|
|
2376
3331
|
}
|
|
2377
3332
|
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
3333
|
+
/* ─────────────────────────────────────────────────────────────────────────
|
|
3334
|
+
Input Field — Clean text entry
|
|
3335
|
+
───────────────────────────────────────────────────────────────────────── */
|
|
3336
|
+
|
|
3337
|
+
.input-container > .select-input,
|
|
3338
|
+
input.select-input,
|
|
3339
|
+
.select-input[type="text"] {
|
|
3340
|
+
display: block;
|
|
3341
|
+
flex: 1 1 auto;
|
|
3342
|
+
width: var(--select-input-width, 100%);
|
|
3343
|
+
max-width: 100%;
|
|
3344
|
+
min-width: var(--select-input-min-width, 0);
|
|
3345
|
+
min-inline-size: 0;
|
|
3346
|
+
min-height: 0;
|
|
3347
|
+
padding: var(--select-input-field-padding, 0) !important;
|
|
3348
|
+
margin: 0 !important;
|
|
3349
|
+
border: 0 !important;
|
|
3350
|
+
font-size: var(--select-input-font-size, inherit);
|
|
2385
3351
|
line-height: var(--select-input-line-height, 1.5);
|
|
2386
|
-
color: var(--select-input-color, var(--select-text
|
|
2387
|
-
background: transparent;
|
|
3352
|
+
color: var(--select-input-color, var(--select-text));
|
|
3353
|
+
background: transparent !important;
|
|
2388
3354
|
box-sizing: border-box;
|
|
2389
|
-
outline: none;
|
|
2390
|
-
font-
|
|
3355
|
+
outline: none !important;
|
|
3356
|
+
font-weight: var(--select-input-font-weight);
|
|
3357
|
+
letter-spacing: var(--select-input-letter-spacing);
|
|
3358
|
+
font-family: var(--select-input-font-family, inherit);
|
|
3359
|
+
font-style: var(--select-input-font-style, normal);
|
|
3360
|
+
align-self: var(--select-input-align-self, center);
|
|
3361
|
+
appearance: none !important;
|
|
3362
|
+
-webkit-appearance: none !important;
|
|
3363
|
+
box-shadow: none !important;
|
|
3364
|
+
border-radius: 0 !important;
|
|
3365
|
+
overflow: hidden;
|
|
3366
|
+
text-overflow: ellipsis;
|
|
3367
|
+
text-align: var(--select-input-text-align, inherit);
|
|
3368
|
+
white-space: nowrap;
|
|
2391
3369
|
}
|
|
2392
3370
|
|
|
2393
3371
|
.select-input::placeholder {
|
|
2394
|
-
color: var(--select-input-placeholder-color, var(--select-placeholder
|
|
3372
|
+
color: var(--select-input-placeholder-color, var(--select-text-placeholder));
|
|
3373
|
+
font-weight: 400;
|
|
2395
3374
|
}
|
|
2396
|
-
|
|
2397
|
-
.
|
|
2398
|
-
|
|
2399
|
-
align-items: center;
|
|
2400
|
-
gap: var(--select-badge-gap, 4px);
|
|
2401
|
-
padding: var(--select-badge-padding, 4px 8px);
|
|
2402
|
-
margin: var(--select-badge-margin, 2px);
|
|
2403
|
-
background: var(--select-badge-bg, #667eea);
|
|
2404
|
-
color: var(--select-badge-color, white);
|
|
2405
|
-
border-radius: var(--select-badge-border-radius, 4px);
|
|
2406
|
-
font-size: var(--select-badge-font-size, 13px);
|
|
2407
|
-
line-height: 1;
|
|
2408
|
-
max-width: var(--select-badge-max-width, 100%);
|
|
2409
|
-
white-space: nowrap;
|
|
2410
|
-
overflow: hidden;
|
|
2411
|
-
text-overflow: ellipsis;
|
|
3375
|
+
|
|
3376
|
+
:host([dir="rtl"]) .input-container {
|
|
3377
|
+
padding: var(--select-input-padding-rtl, 10px 14px 10px 52px);
|
|
2412
3378
|
}
|
|
2413
|
-
|
|
2414
|
-
.
|
|
2415
|
-
|
|
2416
|
-
align-items: center;
|
|
2417
|
-
justify-content: center;
|
|
2418
|
-
width: var(--select-badge-remove-size, 16px);
|
|
2419
|
-
height: var(--select-badge-remove-size, 16px);
|
|
2420
|
-
padding: 0;
|
|
2421
|
-
margin-left: 4px;
|
|
2422
|
-
background: var(--select-badge-remove-bg, rgba(255, 255, 255, 0.3));
|
|
2423
|
-
border: none;
|
|
2424
|
-
border-radius: 50%;
|
|
2425
|
-
color: var(--select-badge-remove-color, white);
|
|
2426
|
-
font-size: var(--select-badge-remove-font-size, 16px);
|
|
2427
|
-
line-height: 1;
|
|
2428
|
-
cursor: pointer;
|
|
2429
|
-
transition: background 0.2s;
|
|
3379
|
+
|
|
3380
|
+
:host([dir="rtl"]) .input-container.has-clear-control {
|
|
3381
|
+
padding: var(--select-input-padding-with-clear-rtl, 10px 14px 10px 84px);
|
|
2430
3382
|
}
|
|
2431
|
-
|
|
2432
|
-
.
|
|
2433
|
-
|
|
3383
|
+
|
|
3384
|
+
.input-container.input-container--multi > .select-input,
|
|
3385
|
+
.input-container.input-container--multi > input.select-input,
|
|
3386
|
+
.input-container.input-container--multi > .select-input[type="text"] {
|
|
3387
|
+
width: auto;
|
|
3388
|
+
min-width: var(--select-multi-input-min-width, 96px);
|
|
3389
|
+
flex: 1 0 var(--select-multi-input-min-width, 96px);
|
|
2434
3390
|
}
|
|
2435
3391
|
|
|
2436
|
-
.
|
|
2437
|
-
|
|
2438
|
-
|
|
3392
|
+
.input-container.input-container--single > .select-input,
|
|
3393
|
+
.input-container.input-container--single > input.select-input,
|
|
3394
|
+
.input-container.input-container--single > .select-input[type="text"] {
|
|
3395
|
+
width: var(--select-input-width, 100%);
|
|
3396
|
+
min-width: 0;
|
|
3397
|
+
flex: 1 1 auto;
|
|
2439
3398
|
}
|
|
2440
3399
|
|
|
2441
3400
|
.select-input:disabled {
|
|
2442
3401
|
background-color: var(--select-disabled-bg, #f5f5f5);
|
|
2443
3402
|
cursor: not-allowed;
|
|
3403
|
+
opacity: var(--select-input-disabled-opacity);
|
|
2444
3404
|
}
|
|
2445
3405
|
|
|
3406
|
+
/* ─────────────────────────────────────────────────────────────────────────
|
|
3407
|
+
Dropdown Panel — Elegant floating container
|
|
3408
|
+
───────────────────────────────────────────────────────────────────────── */
|
|
3409
|
+
|
|
2446
3410
|
.select-dropdown {
|
|
2447
3411
|
position: absolute;
|
|
2448
|
-
scroll-behavior:
|
|
2449
|
-
top:
|
|
3412
|
+
scroll-behavior: var(--select-dropdown-scroll-behavior);
|
|
3413
|
+
top: var(--select-dropdown-top);
|
|
3414
|
+
bottom: auto;
|
|
2450
3415
|
left: 0;
|
|
2451
3416
|
right: 0;
|
|
2452
|
-
|
|
2453
|
-
max-height: var(--select-dropdown-max-height, 300px);
|
|
3417
|
+
max-height: var(--select-dropdown-max-height, 320px);
|
|
2454
3418
|
overflow: hidden;
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
border
|
|
2458
|
-
|
|
3419
|
+
box-sizing: border-box;
|
|
3420
|
+
background: var(--select-dropdown-bg, var(--select-surface));
|
|
3421
|
+
border: 1px solid var(--select-dropdown-border, var(--select-border));
|
|
3422
|
+
border-radius: var(--select-dropdown-border-radius, var(--select-radius-lg));
|
|
3423
|
+
box-shadow: var(--select-dropdown-shadow, var(--select-shadow-lg));
|
|
2459
3424
|
z-index: var(--select-dropdown-z-index, 1000);
|
|
3425
|
+
transform-origin: var(--select-dropdown-transform-origin);
|
|
3426
|
+
animation: var(--select-dropdown-animation);
|
|
3427
|
+
}
|
|
3428
|
+
|
|
3429
|
+
.select-dropdown[data-placement="top"] {
|
|
3430
|
+
top: auto;
|
|
3431
|
+
bottom: var(--select-dropdown-bottom, calc(100% + 6px));
|
|
3432
|
+
transform-origin: var(--select-dropdown-top-transform-origin, bottom center);
|
|
3433
|
+
}
|
|
3434
|
+
|
|
3435
|
+
.select-dropdown[data-placement="top"] {
|
|
3436
|
+
--select-dropdown-enter-from-transform: var(--select-dropdown-top-enter-from-transform, translateY(8px) scale(0.98));
|
|
3437
|
+
}
|
|
3438
|
+
|
|
3439
|
+
@keyframes dropdownEnter {
|
|
3440
|
+
0% {
|
|
3441
|
+
opacity: var(--select-dropdown-enter-from-opacity);
|
|
3442
|
+
transform: var(--select-dropdown-enter-from-transform);
|
|
3443
|
+
}
|
|
3444
|
+
100% {
|
|
3445
|
+
opacity: var(--select-dropdown-enter-to-opacity);
|
|
3446
|
+
transform: var(--select-dropdown-enter-to-transform);
|
|
3447
|
+
}
|
|
2460
3448
|
}
|
|
2461
3449
|
|
|
2462
3450
|
.options-container {
|
|
2463
3451
|
position: relative;
|
|
2464
|
-
max-height: var(--select-options-max-height,
|
|
3452
|
+
max-height: var(--select-options-max-height, 320px);
|
|
2465
3453
|
overflow: auto;
|
|
2466
|
-
|
|
2467
|
-
|
|
3454
|
+
box-sizing: border-box;
|
|
3455
|
+
padding: var(--select-options-padding, var(--select-dropdown-padding, 6px));
|
|
3456
|
+
background: var(--select-options-bg, var(--select-dropdown-bg, var(--select-surface)));
|
|
3457
|
+
|
|
3458
|
+
/* Custom scrollbar styling */
|
|
3459
|
+
scrollbar-width: thin;
|
|
3460
|
+
scrollbar-color: var(--select-border) transparent;
|
|
2468
3461
|
}
|
|
3462
|
+
|
|
3463
|
+
.options-container::-webkit-scrollbar {
|
|
3464
|
+
width: var(--select-scrollbar-width);
|
|
3465
|
+
}
|
|
3466
|
+
|
|
3467
|
+
.options-container::-webkit-scrollbar-track {
|
|
3468
|
+
background: transparent;
|
|
3469
|
+
}
|
|
3470
|
+
|
|
3471
|
+
.options-container::-webkit-scrollbar-thumb {
|
|
3472
|
+
background: var(--select-border);
|
|
3473
|
+
border-radius: var(--select-scrollbar-thumb-radius);
|
|
3474
|
+
}
|
|
3475
|
+
|
|
3476
|
+
.options-container::-webkit-scrollbar-thumb:hover {
|
|
3477
|
+
background: var(--select-text-muted);
|
|
3478
|
+
}
|
|
3479
|
+
|
|
3480
|
+
/* ─────────────────────────────────────────────────────────────────────────
|
|
3481
|
+
Group Headers — Refined section dividers
|
|
3482
|
+
───────────────────────────────────────────────────────────────────────── */
|
|
2469
3483
|
|
|
2470
3484
|
.group-header {
|
|
2471
|
-
padding: var(--select-group-header-padding,
|
|
3485
|
+
padding: var(--select-group-header-padding, 10px 12px 6px);
|
|
3486
|
+
margin: var(--select-group-header-margin, 0);
|
|
2472
3487
|
font-weight: var(--select-group-header-weight, 600);
|
|
2473
|
-
color: var(--select-group-header-color,
|
|
2474
|
-
background-color: var(--select-group-header-bg,
|
|
3488
|
+
color: var(--select-group-header-color, var(--select-text-muted));
|
|
3489
|
+
background-color: var(--select-group-header-bg, var(--select-surface));
|
|
2475
3490
|
text-align: var(--select-group-header-text-align, left);
|
|
2476
|
-
font-size: var(--select-group-header-font-size,
|
|
3491
|
+
font-size: var(--select-group-header-font-size, 0.7333em);
|
|
2477
3492
|
text-transform: var(--select-group-header-text-transform, uppercase);
|
|
2478
|
-
letter-spacing: var(--select-group-header-letter-spacing, 0.
|
|
3493
|
+
letter-spacing: var(--select-group-header-letter-spacing, 0.08em);
|
|
2479
3494
|
position: sticky;
|
|
2480
3495
|
top: 0;
|
|
2481
3496
|
z-index: 1;
|
|
2482
|
-
border
|
|
3497
|
+
border: var(--select-group-header-border, none);
|
|
3498
|
+
border-bottom: var(--select-group-header-border-bottom, none);
|
|
3499
|
+
border-radius: var(--select-group-header-border-radius, 0);
|
|
3500
|
+
box-shadow: var(--select-group-header-shadow, none);
|
|
3501
|
+
}
|
|
3502
|
+
|
|
3503
|
+
.group-header:not(:first-child) {
|
|
3504
|
+
margin-top: var(--select-group-header-separator-margin-top);
|
|
3505
|
+
padding-top: var(--select-group-header-separator-padding-top);
|
|
3506
|
+
border-top: var(--select-group-header-separator-border-top);
|
|
2483
3507
|
}
|
|
2484
3508
|
|
|
3509
|
+
/* ─────────────────────────────────────────────────────────────────────────
|
|
3510
|
+
Options — Elegant hover and selection states
|
|
3511
|
+
───────────────────────────────────────────────────────────────────────── */
|
|
3512
|
+
|
|
2485
3513
|
.option {
|
|
2486
|
-
|
|
3514
|
+
position: relative;
|
|
3515
|
+
padding: var(--select-option-padding, 10px 14px);
|
|
2487
3516
|
cursor: pointer;
|
|
2488
|
-
color: var(--select-option-color, var(--select-text
|
|
2489
|
-
background: var(--select-option-bg,
|
|
2490
|
-
|
|
3517
|
+
color: var(--select-option-color, var(--select-text));
|
|
3518
|
+
background: var(--select-option-bg, transparent);
|
|
3519
|
+
border: var(--select-option-border, none);
|
|
3520
|
+
text-align: var(--select-option-text-align, start);
|
|
3521
|
+
transition:
|
|
3522
|
+
background var(--select-transition-fast),
|
|
3523
|
+
color var(--select-transition-fast),
|
|
3524
|
+
border-color var(--select-transition-fast),
|
|
3525
|
+
transform var(--select-transition-fast),
|
|
3526
|
+
box-shadow var(--select-transition-fast);
|
|
2491
3527
|
user-select: none;
|
|
2492
|
-
font-size: var(--select-option-font-size,
|
|
3528
|
+
font-size: var(--select-option-font-size, inherit);
|
|
3529
|
+
font-weight: var(--select-option-font-weight);
|
|
2493
3530
|
line-height: var(--select-option-line-height, 1.5);
|
|
2494
|
-
border: var(--select-option-border,
|
|
2495
|
-
|
|
2496
|
-
border-radius: var(--select-option-border-radius, 0);
|
|
2497
|
-
box-shadow: var(--select-option-shadow, none);
|
|
2498
|
-
transform: var(--select-option-transform, none);
|
|
3531
|
+
border-radius: var(--select-option-border-radius, var(--select-radius-sm));
|
|
3532
|
+
margin: var(--select-option-margin);
|
|
2499
3533
|
}
|
|
2500
3534
|
|
|
2501
3535
|
.option:hover {
|
|
2502
|
-
background: var(--select-option-hover-bg,
|
|
2503
|
-
|
|
3536
|
+
background: var(--select-option-hover-bg, var(--select-surface-elevated));
|
|
3537
|
+
border: var(--select-option-hover-border, var(--select-option-border, none));
|
|
3538
|
+
color: var(--select-option-hover-color, var(--select-text));
|
|
3539
|
+
transform: var(--select-option-hover-transform);
|
|
2504
3540
|
}
|
|
2505
3541
|
|
|
2506
3542
|
.option.selected {
|
|
2507
|
-
background: var(--select-option-selected-bg,
|
|
2508
|
-
color: var(--select-option-selected-color, #4338ca);
|
|
2509
|
-
font-weight: var(--select-option-selected-weight, 500);
|
|
3543
|
+
background: var(--select-option-selected-bg, linear-gradient(135deg, rgba(15, 52, 96, 0.08) 0%, rgba(15, 52, 96, 0.04) 100%));
|
|
2510
3544
|
border: var(--select-option-selected-border, var(--select-option-border, none));
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
3545
|
+
color: var(--select-option-selected-color, var(--select-accent));
|
|
3546
|
+
font-weight: var(--select-option-selected-weight, 550);
|
|
3547
|
+
}
|
|
3548
|
+
|
|
3549
|
+
.option.selected::before {
|
|
3550
|
+
content: '';
|
|
3551
|
+
position: absolute;
|
|
3552
|
+
left: var(--select-option-selected-indicator-left);
|
|
3553
|
+
top: var(--select-option-selected-indicator-top);
|
|
3554
|
+
transform: var(--select-option-selected-indicator-transform);
|
|
3555
|
+
width: var(--select-option-selected-indicator-width);
|
|
3556
|
+
height: var(--select-option-selected-indicator-height);
|
|
3557
|
+
background: var(--select-option-selected-indicator-bg);
|
|
3558
|
+
border-radius: var(--select-option-selected-indicator-radius);
|
|
3559
|
+
animation: var(--select-option-selected-indicator-animation);
|
|
3560
|
+
}
|
|
3561
|
+
|
|
3562
|
+
:host([dir="rtl"]) .option.selected::before {
|
|
3563
|
+
left: auto;
|
|
3564
|
+
right: var(--select-option-selected-indicator-right, var(--select-option-selected-indicator-left));
|
|
3565
|
+
border-radius: var(--select-option-selected-indicator-radius-rtl, 2px 0 0 2px);
|
|
3566
|
+
}
|
|
3567
|
+
|
|
3568
|
+
@keyframes selectedIndicator {
|
|
3569
|
+
0% {
|
|
3570
|
+
height: var(--select-option-selected-indicator-from-height);
|
|
3571
|
+
opacity: var(--select-option-selected-indicator-from-opacity);
|
|
3572
|
+
}
|
|
3573
|
+
100% {
|
|
3574
|
+
height: var(--select-option-selected-indicator-to-height);
|
|
3575
|
+
opacity: var(--select-option-selected-indicator-to-opacity);
|
|
3576
|
+
}
|
|
2515
3577
|
}
|
|
2516
3578
|
|
|
2517
3579
|
.option.selected:hover {
|
|
2518
|
-
background: var(--select-option-selected-hover-bg, var(--select-option-selected-bg,
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
border-bottom: var(--select-option-selected-hover-border-bottom, var(--select-option-selected-border-bottom, var(--select-option-border-bottom, none)));
|
|
2522
|
-
box-shadow: var(--select-option-selected-hover-shadow, var(--select-option-selected-shadow, var(--select-option-shadow, none)));
|
|
2523
|
-
transform: var(--select-option-selected-hover-transform, var(--select-option-selected-transform, var(--select-option-transform, none)));
|
|
3580
|
+
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%)));
|
|
3581
|
+
border: var(--select-option-selected-hover-border, var(--select-option-selected-border, var(--select-option-hover-border, var(--select-option-border, none))));
|
|
3582
|
+
color: var(--select-option-selected-hover-color, var(--select-option-selected-color, var(--select-accent)));
|
|
2524
3583
|
}
|
|
2525
3584
|
|
|
2526
3585
|
.option.active:not(.selected) {
|
|
2527
|
-
background: var(--select-option-active-bg,
|
|
2528
|
-
color: var(--select-option-active-color,
|
|
2529
|
-
|
|
2530
|
-
outline
|
|
3586
|
+
background: var(--select-option-active-bg, var(--select-surface-elevated));
|
|
3587
|
+
color: var(--select-option-active-color, var(--select-option-hover-color, var(--select-option-color, var(--select-text))));
|
|
3588
|
+
border: var(--select-option-active-border, var(--select-option-hover-border, var(--select-option-border, none)));
|
|
3589
|
+
outline: var(--select-option-active-outline, 2px solid rgba(15, 52, 96, 0.3));
|
|
3590
|
+
outline-offset: var(--select-option-active-outline-offset);
|
|
3591
|
+
box-shadow: var(--select-option-active-shadow, none);
|
|
3592
|
+
transform: var(--select-option-active-transform, none);
|
|
2531
3593
|
}
|
|
2532
3594
|
|
|
2533
3595
|
.option.selected.active {
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
|
|
3596
|
+
outline: var(--select-option-selected-active-outline, 2px solid rgba(15, 52, 96, 0.4));
|
|
3597
|
+
outline-offset: var(--select-option-selected-active-outline-offset);
|
|
3598
|
+
}
|
|
3599
|
+
|
|
3600
|
+
.option.disabled {
|
|
3601
|
+
background: var(--select-option-disabled-bg, var(--select-option-bg, transparent));
|
|
3602
|
+
color: var(--select-option-disabled-color, var(--select-text-muted));
|
|
3603
|
+
border: var(--select-option-disabled-border, var(--select-option-border, none));
|
|
3604
|
+
opacity: var(--select-option-disabled-opacity, 0.5);
|
|
3605
|
+
cursor: var(--select-option-disabled-cursor, not-allowed);
|
|
2542
3606
|
}
|
|
2543
3607
|
|
|
2544
3608
|
.option:active:not(.selected) {
|
|
2545
|
-
background: var(--select-option-pressed-bg,
|
|
3609
|
+
background: var(--select-option-pressed-bg, rgba(15, 52, 96, 0.08));
|
|
3610
|
+
transform: var(--select-option-pressed-transform);
|
|
2546
3611
|
}
|
|
2547
3612
|
|
|
2548
3613
|
.option.selected:active {
|
|
2549
|
-
|
|
3614
|
+
transform: var(--select-option-selected-pressed-transform);
|
|
2550
3615
|
}
|
|
2551
3616
|
|
|
3617
|
+
/* ─────────────────────────────────────────────────────────────────────────
|
|
3618
|
+
Load More & Busy States — Refined feedback indicators
|
|
3619
|
+
───────────────────────────────────────────────────────────────────────── */
|
|
3620
|
+
|
|
2552
3621
|
.load-more-container {
|
|
2553
3622
|
padding: var(--select-load-more-padding, 12px);
|
|
2554
3623
|
text-align: center;
|
|
2555
|
-
border-top: var(--select-divider-border, 1px solid #e0e0e0);
|
|
2556
|
-
background: var(--select-load-more-bg, white);
|
|
2557
3624
|
}
|
|
2558
3625
|
|
|
2559
3626
|
.load-more-button {
|
|
2560
|
-
padding: var(--select-button-padding,
|
|
2561
|
-
border: var(--select-button-border,
|
|
2562
|
-
background: var(--select-button-bg,
|
|
2563
|
-
color: var(--select-button-color,
|
|
2564
|
-
border-radius: var(--select-button-border-radius,
|
|
3627
|
+
padding: var(--select-button-padding, 10px 20px);
|
|
3628
|
+
border: var(--select-button-border, 1.5px solid var(--select-border));
|
|
3629
|
+
background: var(--select-button-bg, transparent);
|
|
3630
|
+
color: var(--select-button-color, var(--select-accent));
|
|
3631
|
+
border-radius: var(--select-button-border-radius, var(--select-radius-md));
|
|
2565
3632
|
cursor: pointer;
|
|
2566
|
-
font-size: var(--select-button-font-size,
|
|
2567
|
-
font-
|
|
2568
|
-
|
|
3633
|
+
font-size: var(--select-button-font-size, 0.8667em);
|
|
3634
|
+
font-weight: var(--select-button-font-weight);
|
|
3635
|
+
letter-spacing: var(--select-button-letter-spacing);
|
|
3636
|
+
transition:
|
|
3637
|
+
background var(--select-transition-fast),
|
|
3638
|
+
border-color var(--select-transition-fast),
|
|
3639
|
+
color var(--select-transition-fast),
|
|
3640
|
+
transform var(--select-transition-bounce);
|
|
2569
3641
|
}
|
|
2570
3642
|
|
|
2571
3643
|
.load-more-button:hover {
|
|
2572
|
-
background: var(--select-button-hover-bg,
|
|
3644
|
+
background: var(--select-button-hover-bg, var(--select-accent));
|
|
3645
|
+
border-color: var(--select-accent);
|
|
2573
3646
|
color: var(--select-button-hover-color, white);
|
|
3647
|
+
transform: var(--select-button-hover-transform);
|
|
3648
|
+
}
|
|
3649
|
+
|
|
3650
|
+
.load-more-button:active {
|
|
3651
|
+
transform: var(--select-button-active-transform);
|
|
2574
3652
|
}
|
|
2575
3653
|
|
|
2576
3654
|
.load-more-button:disabled {
|
|
2577
3655
|
opacity: var(--select-button-disabled-opacity, 0.5);
|
|
2578
3656
|
cursor: not-allowed;
|
|
3657
|
+
transform: none;
|
|
2579
3658
|
}
|
|
2580
3659
|
|
|
2581
3660
|
.busy-bucket {
|
|
2582
|
-
padding: var(--select-busy-padding,
|
|
3661
|
+
padding: var(--select-busy-padding, 20px);
|
|
2583
3662
|
text-align: center;
|
|
2584
|
-
color: var(--select-busy-color,
|
|
2585
|
-
background: var(--select-busy-bg,
|
|
2586
|
-
font-size: var(--select-busy-font-size,
|
|
3663
|
+
color: var(--select-busy-color, var(--select-text-muted));
|
|
3664
|
+
background: var(--select-busy-bg, transparent);
|
|
3665
|
+
font-size: var(--select-busy-font-size, 0.8667em);
|
|
2587
3666
|
}
|
|
2588
3667
|
|
|
2589
3668
|
.spinner {
|
|
2590
3669
|
display: inline-block;
|
|
2591
|
-
width: var(--select-spinner-size,
|
|
2592
|
-
height: var(--select-spinner-size,
|
|
2593
|
-
border: var(--select-spinner-border, 2px solid
|
|
2594
|
-
border-top-color: var(--select-spinner-active-color,
|
|
3670
|
+
width: var(--select-spinner-size, 22px);
|
|
3671
|
+
height: var(--select-spinner-size, 22px);
|
|
3672
|
+
border: var(--select-spinner-border, 2px solid var(--select-border));
|
|
3673
|
+
border-top-color: var(--select-spinner-active-color, var(--select-accent));
|
|
2595
3674
|
border-radius: 50%;
|
|
2596
|
-
animation:
|
|
3675
|
+
animation: var(--select-spinner-animation);
|
|
2597
3676
|
}
|
|
2598
3677
|
|
|
2599
3678
|
@keyframes spin {
|
|
@@ -2601,61 +3680,97 @@
|
|
|
2601
3680
|
}
|
|
2602
3681
|
|
|
2603
3682
|
.empty-state {
|
|
2604
|
-
padding: var(--select-empty-padding, 24px);
|
|
3683
|
+
padding: var(--select-empty-padding, 32px 24px);
|
|
2605
3684
|
text-align: center;
|
|
2606
|
-
color: var(--select-empty-color,
|
|
2607
|
-
font-size: var(--select-empty-font-size,
|
|
2608
|
-
background: var(--select-empty-bg,
|
|
3685
|
+
color: var(--select-empty-color, var(--select-text-muted));
|
|
3686
|
+
font-size: var(--select-empty-font-size, 0.9333em);
|
|
3687
|
+
background: var(--select-empty-bg, transparent);
|
|
2609
3688
|
display: flex;
|
|
2610
3689
|
flex-direction: column;
|
|
2611
3690
|
align-items: center;
|
|
2612
3691
|
justify-content: center;
|
|
2613
|
-
gap:
|
|
2614
|
-
min-height: var(--select-empty-min-height, 72px);
|
|
3692
|
+
gap: var(--select-empty-gap);
|
|
2615
3693
|
}
|
|
2616
3694
|
|
|
2617
3695
|
.searching-state {
|
|
2618
|
-
padding: var(--select-searching-padding, 24px);
|
|
3696
|
+
padding: var(--select-searching-padding, 32px 24px);
|
|
2619
3697
|
text-align: center;
|
|
2620
|
-
color: var(--select-searching-color,
|
|
2621
|
-
font-size: var(--select-searching-font-size,
|
|
2622
|
-
|
|
2623
|
-
background: var(--select-searching-bg, white);
|
|
2624
|
-
animation: pulse 1.5s ease-in-out infinite;
|
|
3698
|
+
color: var(--select-searching-color, var(--select-accent));
|
|
3699
|
+
font-size: var(--select-searching-font-size, 0.9333em);
|
|
3700
|
+
background: var(--select-searching-bg, transparent);
|
|
2625
3701
|
display: flex;
|
|
2626
3702
|
flex-direction: column;
|
|
2627
3703
|
align-items: center;
|
|
2628
3704
|
justify-content: center;
|
|
2629
|
-
gap:
|
|
2630
|
-
min-height: var(--select-searching-min-height, 72px);
|
|
3705
|
+
gap: var(--select-searching-gap);
|
|
2631
3706
|
}
|
|
2632
3707
|
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
3708
|
+
.searching-state::before {
|
|
3709
|
+
content: '';
|
|
3710
|
+
width: var(--select-searching-spinner-size);
|
|
3711
|
+
height: var(--select-searching-spinner-size);
|
|
3712
|
+
border: var(--select-searching-spinner-border);
|
|
3713
|
+
border-top-color: var(--select-searching-spinner-active-color);
|
|
3714
|
+
border-radius: 50%;
|
|
3715
|
+
animation: var(--select-searching-spinner-animation);
|
|
2636
3716
|
}
|
|
2637
3717
|
|
|
2638
|
-
/*
|
|
3718
|
+
/* ─────────────────────────────────────────────────────────────────────────
|
|
3719
|
+
Error States — Clear visual feedback
|
|
3720
|
+
───────────────────────────────────────────────────────────────────────── */
|
|
3721
|
+
|
|
2639
3722
|
.select-input[aria-invalid="true"] {
|
|
2640
|
-
border-color: var(--select-error-border, #
|
|
3723
|
+
border-color: var(--select-error-border, #e94560);
|
|
2641
3724
|
}
|
|
2642
3725
|
|
|
2643
3726
|
.select-input[aria-invalid="true"]:focus {
|
|
2644
|
-
border-color: var(--select-error-border, #
|
|
2645
|
-
box-shadow: 0 0 0
|
|
2646
|
-
outline-color: var(--select-error-border, #dc2626);
|
|
3727
|
+
border-color: var(--select-error-border, #e94560);
|
|
3728
|
+
box-shadow: 0 0 0 3px var(--select-error-shadow, rgba(233, 69, 96, 0.15));
|
|
2647
3729
|
}
|
|
2648
3730
|
|
|
2649
|
-
/*
|
|
3731
|
+
/* ──────────────────────────────────────────────────��──────────────────────
|
|
3732
|
+
Accessibility — Reduced motion & High contrast
|
|
3733
|
+
───────────────────────────────────────────────────────────────────────── */
|
|
3734
|
+
|
|
2650
3735
|
@media (prefers-reduced-motion: reduce) {
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
|
|
3736
|
+
*,
|
|
3737
|
+
*::before,
|
|
3738
|
+
*::after {
|
|
3739
|
+
animation-duration: var(--select-reduced-motion-duration) !important;
|
|
3740
|
+
animation-iteration-count: var(--select-reduced-motion-iteration-count) !important;
|
|
3741
|
+
transition-duration: var(--select-reduced-motion-duration) !important;
|
|
3742
|
+
}
|
|
3743
|
+
|
|
3744
|
+
.dropdown-arrow.open {
|
|
3745
|
+
transform: var(--select-arrow-open-transform);
|
|
3746
|
+
}
|
|
3747
|
+
}
|
|
3748
|
+
|
|
3749
|
+
@media (prefers-contrast: high) {
|
|
3750
|
+
.select-input:focus {
|
|
3751
|
+
outline-width: var(--select-high-contrast-focus-outline-width);
|
|
3752
|
+
outline-color: var(--select-high-contrast-focus-outline-color);
|
|
3753
|
+
}
|
|
3754
|
+
|
|
3755
|
+
.input-container {
|
|
3756
|
+
border-width: var(--select-high-contrast-border-width);
|
|
2655
3757
|
}
|
|
3758
|
+
|
|
3759
|
+
.option.selected::before {
|
|
3760
|
+
width: var(--select-high-contrast-indicator-width);
|
|
3761
|
+
}
|
|
3762
|
+
}
|
|
3763
|
+
|
|
3764
|
+
/* Touch targets (WCAG 2.5.5) */
|
|
3765
|
+
.load-more-button,
|
|
3766
|
+
select-option {
|
|
3767
|
+
min-height: var(--select-touch-target-min-height);
|
|
2656
3768
|
}
|
|
2657
3769
|
|
|
2658
|
-
/*
|
|
3770
|
+
/* ─────────────────────────────────────────────────────────────────────────
|
|
3771
|
+
Dark Mode — Elegant dark theme
|
|
3772
|
+
───────────────────────────────────────────────────────────────────────── */
|
|
3773
|
+
|
|
2659
3774
|
:host(.dark-mode),
|
|
2660
3775
|
:host([dark-mode]),
|
|
2661
3776
|
:host([darkmode]),
|
|
@@ -2667,139 +3782,133 @@
|
|
|
2667
3782
|
:host-context([darkmode]),
|
|
2668
3783
|
:host-context([data-theme="dark"]),
|
|
2669
3784
|
:host-context([theme="dark"]) {
|
|
2670
|
-
|
|
2671
|
-
|
|
2672
|
-
--select-
|
|
2673
|
-
--select-
|
|
2674
|
-
--select-
|
|
2675
|
-
--select-
|
|
2676
|
-
--select-
|
|
2677
|
-
--select-
|
|
2678
|
-
|
|
2679
|
-
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
|
|
2685
|
-
color: var(--select-dark-text, #f9fafb);
|
|
2686
|
-
}
|
|
2687
|
-
|
|
2688
|
-
.select-input::placeholder {
|
|
2689
|
-
color: var(--select-dark-placeholder, #6b7280);
|
|
2690
|
-
}
|
|
2691
|
-
|
|
2692
|
-
.select-dropdown {
|
|
2693
|
-
background: var(--select-dark-dropdown-bg, #1f2937);
|
|
2694
|
-
border-color: var(--select-dark-dropdown-border, #4b5563);
|
|
2695
|
-
}
|
|
2696
|
-
|
|
2697
|
-
.options-container {
|
|
2698
|
-
background: var(--select-dark-options-bg, #1f2937);
|
|
2699
|
-
}
|
|
2700
|
-
|
|
2701
|
-
.option {
|
|
2702
|
-
color: var(--select-dark-option-color, #f9fafb);
|
|
2703
|
-
background: var(--select-dark-option-bg, #1f2937);
|
|
2704
|
-
}
|
|
2705
|
-
|
|
2706
|
-
.option:hover {
|
|
2707
|
-
background: var(--select-dark-option-hover-bg, #374151);
|
|
2708
|
-
color: var(--select-dark-option-hover-color, #f9fafb);
|
|
2709
|
-
}
|
|
2710
|
-
|
|
2711
|
-
.option.selected {
|
|
2712
|
-
background: var(--select-dark-option-selected-bg, #3730a3);
|
|
2713
|
-
color: var(--select-dark-option-selected-text, #e0e7ff);
|
|
2714
|
-
border: var(--select-dark-option-selected-border, var(--select-option-selected-border, var(--select-option-border, none)));
|
|
2715
|
-
border-bottom: var(--select-dark-option-selected-border-bottom, var(--select-option-selected-border-bottom, var(--select-option-border-bottom, none)));
|
|
2716
|
-
box-shadow: var(--select-dark-option-selected-shadow, var(--select-option-selected-shadow, var(--select-option-shadow, none)));
|
|
2717
|
-
transform: var(--select-dark-option-selected-transform, var(--select-option-selected-transform, var(--select-option-transform, none)));
|
|
2718
|
-
}
|
|
3785
|
+
--select-primary: #e5e5e5;
|
|
3786
|
+
--select-primary-light: #2a2a3e;
|
|
3787
|
+
--select-accent: #6366f1;
|
|
3788
|
+
--select-accent-hover: #f43f5e;
|
|
3789
|
+
--select-surface: var(--select-dark-bg, #1a1a2e);
|
|
3790
|
+
--select-surface-elevated: #252540;
|
|
3791
|
+
--select-border: var(--select-dark-border, #3f3f5a);
|
|
3792
|
+
--select-border-focus: #6366f1;
|
|
3793
|
+
--select-text: var(--select-dark-text, #f5f5f5);
|
|
3794
|
+
--select-text-muted: #9ca3af;
|
|
3795
|
+
--select-text-placeholder: #6b7280;
|
|
3796
|
+
--select-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.2);
|
|
3797
|
+
--select-shadow-md: 0 4px 12px rgba(0, 0, 0, 0.3);
|
|
3798
|
+
--select-shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.4);
|
|
3799
|
+
--select-shadow-focus: 0 0 0 3px rgba(99, 102, 241, 0.25);
|
|
2719
3800
|
|
|
2720
|
-
|
|
2721
|
-
background: var(--select-dark-option-selected-hover-bg, var(--select-dark-option-selected-bg, #3730a3));
|
|
2722
|
-
color: var(--select-dark-option-selected-hover-color, var(--select-dark-option-selected-text, #e0e7ff));
|
|
2723
|
-
border: var(--select-dark-option-selected-hover-border, var(--select-dark-option-selected-border, var(--select-option-selected-hover-border, var(--select-option-selected-border, var(--select-option-border, none)))));
|
|
2724
|
-
border-bottom: var(--select-dark-option-selected-hover-border-bottom, var(--select-dark-option-selected-border-bottom, var(--select-option-selected-hover-border-bottom, var(--select-option-selected-border-bottom, var(--select-option-border-bottom, none)))));
|
|
2725
|
-
box-shadow: var(--select-dark-option-selected-hover-shadow, var(--select-dark-option-selected-shadow, var(--select-option-selected-hover-shadow, var(--select-option-selected-shadow, var(--select-option-shadow, none)))));
|
|
2726
|
-
transform: var(--select-dark-option-selected-hover-transform, var(--select-dark-option-selected-transform, var(--select-option-selected-hover-transform, var(--select-option-selected-transform, var(--select-option-transform, none)))));
|
|
2727
|
-
}
|
|
3801
|
+
--select-dropdown-bg: var(--select-dark-dropdown-bg, var(--select-surface));
|
|
2728
3802
|
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
background-color: var(--select-dark-group-header-bg, var(--select-group-header-bg, #374151));
|
|
2739
|
-
}
|
|
3803
|
+
--select-option-bg: var(--select-dark-option-bg, transparent);
|
|
3804
|
+
--select-option-color: var(--select-dark-option-color, var(--select-text));
|
|
3805
|
+
--select-option-hover-bg: var(--select-dark-option-hover-bg, var(--select-surface-elevated));
|
|
3806
|
+
--select-option-hover-color: var(--select-dark-option-hover-color, var(--select-text));
|
|
3807
|
+
--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%));
|
|
3808
|
+
--select-option-selected-color: var(--select-dark-option-selected-color, #a5b4fc);
|
|
3809
|
+
--select-option-selected-hover-bg: var(--select-dark-option-selected-hover-bg, var(--select-option-selected-bg));
|
|
3810
|
+
--select-option-selected-hover-color: var(--select-dark-option-selected-hover-color, var(--select-option-selected-color));
|
|
3811
|
+
}
|
|
2740
3812
|
|
|
2741
|
-
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
|
|
2750
|
-
|
|
3813
|
+
:host(.dark-mode) .input-container,
|
|
3814
|
+
:host([dark-mode]) .input-container,
|
|
3815
|
+
:host([darkmode]) .input-container,
|
|
3816
|
+
:host([data-theme="dark"]) .input-container,
|
|
3817
|
+
:host([theme="dark"]) .input-container,
|
|
3818
|
+
:host-context(.dark-mode) .input-container,
|
|
3819
|
+
:host-context(.dark) .input-container,
|
|
3820
|
+
:host-context([dark-mode]) .input-container,
|
|
3821
|
+
:host-context([darkmode]) .input-container,
|
|
3822
|
+
:host-context([data-theme="dark"]) .input-container,
|
|
3823
|
+
:host-context([theme="dark"]) .input-container {
|
|
3824
|
+
background: var(--select-surface);
|
|
3825
|
+
border-color: var(--select-border);
|
|
3826
|
+
}
|
|
2751
3827
|
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
|
|
3828
|
+
:host(.dark-mode) .input-container::after,
|
|
3829
|
+
:host([dark-mode]) .input-container::after,
|
|
3830
|
+
:host([darkmode]) .input-container::after,
|
|
3831
|
+
:host([data-theme="dark"]) .input-container::after,
|
|
3832
|
+
:host([theme="dark"]) .input-container::after,
|
|
3833
|
+
:host-context(.dark-mode) .input-container::after,
|
|
3834
|
+
:host-context(.dark) .input-container::after,
|
|
3835
|
+
:host-context([dark-mode]) .input-container::after,
|
|
3836
|
+
:host-context([darkmode]) .input-container::after,
|
|
3837
|
+
:host-context([data-theme="dark"]) .input-container::after,
|
|
3838
|
+
:host-context([theme="dark"]) .input-container::after {
|
|
3839
|
+
background: var(--select-separator-dark-bg);
|
|
3840
|
+
}
|
|
2756
3841
|
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
3842
|
+
:host(.dark-mode) .select-dropdown,
|
|
3843
|
+
:host([dark-mode]) .select-dropdown,
|
|
3844
|
+
:host([darkmode]) .select-dropdown,
|
|
3845
|
+
:host([data-theme="dark"]) .select-dropdown,
|
|
3846
|
+
:host([theme="dark"]) .select-dropdown,
|
|
3847
|
+
:host-context(.dark-mode) .select-dropdown,
|
|
3848
|
+
:host-context(.dark) .select-dropdown,
|
|
3849
|
+
:host-context([dark-mode]) .select-dropdown,
|
|
3850
|
+
:host-context([darkmode]) .select-dropdown,
|
|
3851
|
+
:host-context([data-theme="dark"]) .select-dropdown,
|
|
3852
|
+
:host-context([theme="dark"]) .select-dropdown {
|
|
3853
|
+
background: var(--select-dropdown-bg, var(--select-surface));
|
|
3854
|
+
border-color: var(--select-border);
|
|
3855
|
+
}
|
|
2761
3856
|
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
3857
|
+
:host(.dark-mode) .options-container,
|
|
3858
|
+
:host([dark-mode]) .options-container,
|
|
3859
|
+
:host([darkmode]) .options-container,
|
|
3860
|
+
:host([data-theme="dark"]) .options-container,
|
|
3861
|
+
:host([theme="dark"]) .options-container,
|
|
3862
|
+
:host-context(.dark-mode) .options-container,
|
|
3863
|
+
:host-context(.dark) .options-container,
|
|
3864
|
+
:host-context([dark-mode]) .options-container,
|
|
3865
|
+
:host-context([darkmode]) .options-container,
|
|
3866
|
+
:host-context([data-theme="dark"]) .options-container,
|
|
3867
|
+
:host-context([theme="dark"]) .options-container {
|
|
3868
|
+
background: var(--select-dropdown-bg, var(--select-surface));
|
|
3869
|
+
scrollbar-color: var(--select-border) transparent;
|
|
3870
|
+
}
|
|
2771
3871
|
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
|
|
2781
|
-
|
|
2782
|
-
|
|
2783
|
-
|
|
2784
|
-
}
|
|
3872
|
+
:host(.dark-mode) .selection-badge,
|
|
3873
|
+
:host([dark-mode]) .selection-badge,
|
|
3874
|
+
:host([darkmode]) .selection-badge,
|
|
3875
|
+
:host([data-theme="dark"]) .selection-badge,
|
|
3876
|
+
:host([theme="dark"]) .selection-badge,
|
|
3877
|
+
:host-context(.dark-mode) .selection-badge,
|
|
3878
|
+
:host-context(.dark) .selection-badge,
|
|
3879
|
+
:host-context([dark-mode]) .selection-badge,
|
|
3880
|
+
:host-context([darkmode]) .selection-badge,
|
|
3881
|
+
:host-context([data-theme="dark"]) .selection-badge,
|
|
3882
|
+
:host-context([theme="dark"]) .selection-badge {
|
|
3883
|
+
background: var(--select-badge-dark-bg);
|
|
2785
3884
|
}
|
|
2786
|
-
|
|
2787
|
-
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
|
|
2791
|
-
|
|
2792
|
-
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
|
|
3885
|
+
|
|
3886
|
+
:host(.dark-mode) .group-header:not(:first-child),
|
|
3887
|
+
:host([dark-mode]) .group-header:not(:first-child),
|
|
3888
|
+
:host([darkmode]) .group-header:not(:first-child),
|
|
3889
|
+
:host([data-theme="dark"]) .group-header:not(:first-child),
|
|
3890
|
+
:host([theme="dark"]) .group-header:not(:first-child),
|
|
3891
|
+
:host-context(.dark-mode) .group-header:not(:first-child),
|
|
3892
|
+
:host-context(.dark) .group-header:not(:first-child),
|
|
3893
|
+
:host-context([dark-mode]) .group-header:not(:first-child),
|
|
3894
|
+
:host-context([darkmode]) .group-header:not(:first-child),
|
|
3895
|
+
:host-context([data-theme="dark"]) .group-header:not(:first-child),
|
|
3896
|
+
:host-context([theme="dark"]) .group-header:not(:first-child) {
|
|
3897
|
+
border-top-color: var(--select-border);
|
|
2797
3898
|
}
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
.
|
|
2801
|
-
|
|
2802
|
-
|
|
3899
|
+
|
|
3900
|
+
:host(.dark-mode) .option.selected::before,
|
|
3901
|
+
:host([dark-mode]) .option.selected::before,
|
|
3902
|
+
:host([darkmode]) .option.selected::before,
|
|
3903
|
+
:host([data-theme="dark"]) .option.selected::before,
|
|
3904
|
+
:host([theme="dark"]) .option.selected::before,
|
|
3905
|
+
:host-context(.dark-mode) .option.selected::before,
|
|
3906
|
+
:host-context(.dark) .option.selected::before,
|
|
3907
|
+
:host-context([dark-mode]) .option.selected::before,
|
|
3908
|
+
:host-context([darkmode]) .option.selected::before,
|
|
3909
|
+
:host-context([data-theme="dark"]) .option.selected::before,
|
|
3910
|
+
:host-context([theme="dark"]) .option.selected::before {
|
|
3911
|
+
background: var(--select-accent);
|
|
2803
3912
|
}
|
|
2804
3913
|
`;
|
|
2805
3914
|
// Insert as first child to ensure styles are processed first
|
|
@@ -2819,10 +3928,10 @@
|
|
|
2819
3928
|
// delegate to the existing open/close helpers so we don't accidentally
|
|
2820
3929
|
// drift out of sync with the logic in those methods (focus, events,
|
|
2821
3930
|
// scroll-to-selected, etc.)
|
|
2822
|
-
if (this._state.isOpen) {
|
|
3931
|
+
if (this._state.isOpen && this._config.selection.toggleOnTriggerClick !== false) {
|
|
2823
3932
|
this._handleClose();
|
|
2824
3933
|
}
|
|
2825
|
-
else {
|
|
3934
|
+
else if (!this._state.isOpen) {
|
|
2826
3935
|
this._handleOpen();
|
|
2827
3936
|
}
|
|
2828
3937
|
};
|
|
@@ -2845,7 +3954,7 @@
|
|
|
2845
3954
|
this._inputContainer.addEventListener('pointerdown', (e) => {
|
|
2846
3955
|
// Prevent propagation to document click listener but do NOT preventDefault.
|
|
2847
3956
|
// Allow default so browser events (click) on newly opened options still fire.
|
|
2848
|
-
e.stopPropagation();
|
|
3957
|
+
// e.stopPropagation(); // BUG: By stopping propagation here, the document click listener doesn't see it, which is fine for not closing it. But be very careful.
|
|
2849
3958
|
const target = e.target;
|
|
2850
3959
|
if (!this._config.enabled)
|
|
2851
3960
|
return;
|
|
@@ -2853,21 +3962,38 @@
|
|
|
2853
3962
|
return;
|
|
2854
3963
|
if (target && target.closest('.clear-control-button'))
|
|
2855
3964
|
return;
|
|
3965
|
+
if (this._isPointerOnInputScrollbar(e)) {
|
|
3966
|
+
this._suppressNextOpenClick = true;
|
|
3967
|
+
return;
|
|
3968
|
+
}
|
|
3969
|
+
const isHorizontalMultiMode = this._config.selection.mode === 'multi'
|
|
3970
|
+
&& (this._config.multiSelectDisplay?.mode ?? 'wrap') === 'horizontal';
|
|
3971
|
+
const enableHorizontalDrag = this._canUseHorizontalMultiScroll(target);
|
|
3972
|
+
if (enableHorizontalDrag && e.button === 0) {
|
|
3973
|
+
this._beginMultiScrollDrag(e);
|
|
3974
|
+
this._suppressNextOpenClick = false;
|
|
3975
|
+
e.preventDefault();
|
|
3976
|
+
return;
|
|
3977
|
+
}
|
|
3978
|
+
// If we clicked the container, but not the input itself, we must prevent default
|
|
3979
|
+
// otherwise the browser moves focus from our input to the body, immediately triggering blur.
|
|
3980
|
+
if (target && !target.matches('.select-input')) {
|
|
3981
|
+
e.preventDefault();
|
|
3982
|
+
}
|
|
3983
|
+
const clickedInput = Boolean(target && target.matches('.select-input'));
|
|
3984
|
+
if (this._state.isOpen &&
|
|
3985
|
+
this._config.selection.toggleOnTriggerClick !== false &&
|
|
3986
|
+
!isHorizontalMultiMode &&
|
|
3987
|
+
!enableHorizontalDrag &&
|
|
3988
|
+
!(clickedInput && this._config.searchable)) {
|
|
3989
|
+
this._handleClose();
|
|
3990
|
+
return;
|
|
3991
|
+
}
|
|
2856
3992
|
const wasClosed = !this._state.isOpen;
|
|
2857
3993
|
if (wasClosed) {
|
|
2858
3994
|
this._handleOpen();
|
|
2859
3995
|
}
|
|
2860
|
-
|
|
2861
|
-
// Keep open while interacting directly with the input so users can
|
|
2862
|
-
// place cursor/type without accidental collapse.
|
|
2863
|
-
if (target === this._input) {
|
|
2864
|
-
this._input.focus();
|
|
2865
|
-
return;
|
|
2866
|
-
}
|
|
2867
|
-
// clicking other parts of the input container while open toggles close
|
|
2868
|
-
this._handleClose();
|
|
2869
|
-
}
|
|
2870
|
-
// Focus the input (do not prevent default behavior)
|
|
3996
|
+
// Focus the input (do not prevent default behavior for input itself)
|
|
2871
3997
|
this._input.focus();
|
|
2872
3998
|
// If we just opened the dropdown, transfer pointer capture to the
|
|
2873
3999
|
// options container so the subsequent pointerup lands there instead of
|
|
@@ -2881,6 +4007,47 @@
|
|
|
2881
4007
|
}
|
|
2882
4008
|
}
|
|
2883
4009
|
});
|
|
4010
|
+
this._inputContainer.addEventListener('click', (e) => {
|
|
4011
|
+
const target = e.target;
|
|
4012
|
+
const isHorizontalMultiMode = this._config.selection.mode === 'multi'
|
|
4013
|
+
&& (this._config.multiSelectDisplay?.mode ?? 'wrap') === 'horizontal';
|
|
4014
|
+
if (!this._config.enabled || !isHorizontalMultiMode) {
|
|
4015
|
+
this._suppressNextOpenClick = false;
|
|
4016
|
+
this._multiScrollDrag.moved = false;
|
|
4017
|
+
return;
|
|
4018
|
+
}
|
|
4019
|
+
if (target && target.closest('.dropdown-arrow-container, .clear-control-button')) {
|
|
4020
|
+
this._suppressNextOpenClick = false;
|
|
4021
|
+
this._multiScrollDrag.moved = false;
|
|
4022
|
+
return;
|
|
4023
|
+
}
|
|
4024
|
+
if (this._suppressNextOpenClick || this._multiScrollDrag.moved || this._isPointerOnInputScrollbar(e)) {
|
|
4025
|
+
this._suppressNextOpenClick = false;
|
|
4026
|
+
this._multiScrollDrag.moved = false;
|
|
4027
|
+
return;
|
|
4028
|
+
}
|
|
4029
|
+
this._suppressNextOpenClick = false;
|
|
4030
|
+
this._multiScrollDrag.moved = false;
|
|
4031
|
+
if (!this._state.isOpen) {
|
|
4032
|
+
this._handleOpen();
|
|
4033
|
+
}
|
|
4034
|
+
this._input.focus();
|
|
4035
|
+
});
|
|
4036
|
+
this._inputContent.addEventListener('pointermove', (e) => {
|
|
4037
|
+
this._updateMultiScrollDrag(e);
|
|
4038
|
+
});
|
|
4039
|
+
this._inputContent.addEventListener('pointerup', (e) => {
|
|
4040
|
+
this._endMultiScrollDrag(e.pointerId);
|
|
4041
|
+
});
|
|
4042
|
+
this._inputContent.addEventListener('pointercancel', (e) => {
|
|
4043
|
+
this._endMultiScrollDrag(e.pointerId);
|
|
4044
|
+
});
|
|
4045
|
+
this._inputContent.addEventListener('wheel', (e) => {
|
|
4046
|
+
if (this._config.selection.mode === 'multi'
|
|
4047
|
+
&& (this._config.multiSelectDisplay?.mode ?? 'wrap') === 'horizontal') {
|
|
4048
|
+
e.preventDefault();
|
|
4049
|
+
}
|
|
4050
|
+
}, { passive: false });
|
|
2884
4051
|
// Input container click - prevent event from reaching document listener
|
|
2885
4052
|
this._container.addEventListener('click', (e) => {
|
|
2886
4053
|
e.stopPropagation();
|
|
@@ -2909,7 +4076,7 @@
|
|
|
2909
4076
|
return;
|
|
2910
4077
|
}
|
|
2911
4078
|
this._handleClose();
|
|
2912
|
-
},
|
|
4079
|
+
}, 150);
|
|
2913
4080
|
});
|
|
2914
4081
|
// Input search
|
|
2915
4082
|
this._input.addEventListener('input', (e) => {
|
|
@@ -2926,7 +4093,7 @@
|
|
|
2926
4093
|
this._suppressBlurClose = true;
|
|
2927
4094
|
setTimeout(() => {
|
|
2928
4095
|
this._suppressBlurClose = false;
|
|
2929
|
-
},
|
|
4096
|
+
}, 150); // Increased timeout to ensure click finishes before blur checks
|
|
2930
4097
|
});
|
|
2931
4098
|
// Delegated click listener for improved event handling (robust across shadow DOM)
|
|
2932
4099
|
const handleOptionEvent = (e) => {
|
|
@@ -2957,9 +4124,6 @@
|
|
|
2957
4124
|
}
|
|
2958
4125
|
};
|
|
2959
4126
|
this._optionsContainer.addEventListener('click', handleOptionEvent);
|
|
2960
|
-
// also watch pointerup to catch cases where the pointerdown started outside
|
|
2961
|
-
// (e.g. on the input) and the click never fires
|
|
2962
|
-
this._optionsContainer.addEventListener('pointerup', handleOptionEvent);
|
|
2963
4127
|
// Keyboard navigation
|
|
2964
4128
|
this._input.addEventListener('keydown', (e) => this._handleKeydown(e));
|
|
2965
4129
|
// Click outside to close — robust detection across shadow DOM and custom renderers
|
|
@@ -3054,22 +4218,14 @@
|
|
|
3054
4218
|
this._input.focus();
|
|
3055
4219
|
this._markOpenStart();
|
|
3056
4220
|
this._state.isOpen = true;
|
|
4221
|
+
this.setAttribute('data-open', 'true');
|
|
4222
|
+
this._liftStackingAncestors();
|
|
3057
4223
|
this._dropdown.style.display = 'block';
|
|
3058
4224
|
this._input.setAttribute('aria-expanded', 'true');
|
|
3059
4225
|
this._updateArrowRotation();
|
|
3060
|
-
// Clear search query when opening to show all options
|
|
3061
|
-
// This ensures we can scroll to selected item
|
|
3062
|
-
if (this._config.searchable) {
|
|
3063
|
-
this._state.searchQuery = '';
|
|
3064
|
-
// Don't clear input value if it represents selection
|
|
3065
|
-
// But if we want to search, we might want to clear it?
|
|
3066
|
-
// Standard behavior: input keeps value (label), but dropdown shows all options
|
|
3067
|
-
// until user types.
|
|
3068
|
-
// However, our filtering logic uses _state.searchQuery.
|
|
3069
|
-
// So clearing it here resets the filter.
|
|
3070
|
-
}
|
|
3071
4226
|
// Render options when opening
|
|
3072
4227
|
this._renderOptions();
|
|
4228
|
+
this._syncDropdownPlacement();
|
|
3073
4229
|
this._setInitialActiveOption();
|
|
3074
4230
|
this._emit('open', {});
|
|
3075
4231
|
this._config.callbacks.onOpen?.();
|
|
@@ -3089,7 +4245,10 @@
|
|
|
3089
4245
|
if (!this._state.isOpen)
|
|
3090
4246
|
return;
|
|
3091
4247
|
this._state.isOpen = false;
|
|
4248
|
+
this.removeAttribute('data-open');
|
|
4249
|
+
this._restoreLiftedAncestors();
|
|
3092
4250
|
this._dropdown.style.display = 'none';
|
|
4251
|
+
this._dropdown.setAttribute('data-placement', this._resolvedDropdownPlacement);
|
|
3093
4252
|
this._input.setAttribute('aria-expanded', 'false');
|
|
3094
4253
|
this._input.removeAttribute('aria-activedescendant');
|
|
3095
4254
|
this._updateArrowRotation();
|
|
@@ -3099,14 +4258,76 @@
|
|
|
3099
4258
|
}
|
|
3100
4259
|
_updateDropdownVisibility() {
|
|
3101
4260
|
if (this._state.isOpen) {
|
|
4261
|
+
this.setAttribute('data-open', 'true');
|
|
4262
|
+
this._liftStackingAncestors();
|
|
3102
4263
|
this._dropdown.style.display = 'block';
|
|
4264
|
+
this._syncDropdownPlacement();
|
|
3103
4265
|
this._input.setAttribute('aria-expanded', 'true');
|
|
3104
4266
|
}
|
|
3105
4267
|
else {
|
|
4268
|
+
this.removeAttribute('data-open');
|
|
4269
|
+
this._restoreLiftedAncestors();
|
|
3106
4270
|
this._dropdown.style.display = 'none';
|
|
3107
4271
|
this._input.setAttribute('aria-expanded', 'false');
|
|
3108
4272
|
}
|
|
3109
4273
|
}
|
|
4274
|
+
_liftStackingAncestors() {
|
|
4275
|
+
this._restoreLiftedAncestors();
|
|
4276
|
+
let ancestor = this.parentElement;
|
|
4277
|
+
while (ancestor && ancestor !== document.body) {
|
|
4278
|
+
if (this._createsStackingContext(ancestor)) {
|
|
4279
|
+
const hadMarker = ancestor.hasAttribute('data-smilodon-open-ancestor');
|
|
4280
|
+
this._liftedAncestors.push({
|
|
4281
|
+
element: ancestor,
|
|
4282
|
+
position: ancestor.style.position,
|
|
4283
|
+
zIndex: ancestor.style.zIndex,
|
|
4284
|
+
hadMarker,
|
|
4285
|
+
});
|
|
4286
|
+
if (getComputedStyle(ancestor).position === 'static') {
|
|
4287
|
+
ancestor.style.position = 'relative';
|
|
4288
|
+
}
|
|
4289
|
+
ancestor.style.zIndex = 'var(--select-ancestor-open-z-index, var(--select-host-open-z-index, var(--select-dropdown-z-index, 1000)))';
|
|
4290
|
+
ancestor.setAttribute('data-smilodon-open-ancestor', 'true');
|
|
4291
|
+
}
|
|
4292
|
+
ancestor = ancestor.parentElement;
|
|
4293
|
+
}
|
|
4294
|
+
}
|
|
4295
|
+
_restoreLiftedAncestors() {
|
|
4296
|
+
for (const lifted of this._liftedAncestors) {
|
|
4297
|
+
lifted.element.style.position = lifted.position;
|
|
4298
|
+
lifted.element.style.zIndex = lifted.zIndex;
|
|
4299
|
+
if (!lifted.hadMarker) {
|
|
4300
|
+
lifted.element.removeAttribute('data-smilodon-open-ancestor');
|
|
4301
|
+
}
|
|
4302
|
+
}
|
|
4303
|
+
this._liftedAncestors = [];
|
|
4304
|
+
}
|
|
4305
|
+
_createsStackingContext(element) {
|
|
4306
|
+
const style = getComputedStyle(element);
|
|
4307
|
+
if (style.position === 'fixed' || style.position === 'sticky')
|
|
4308
|
+
return true;
|
|
4309
|
+
if (style.zIndex !== 'auto' && style.position !== 'static')
|
|
4310
|
+
return true;
|
|
4311
|
+
if (style.opacity !== '1')
|
|
4312
|
+
return true;
|
|
4313
|
+
if (style.transform !== 'none')
|
|
4314
|
+
return true;
|
|
4315
|
+
if (style.filter !== 'none')
|
|
4316
|
+
return true;
|
|
4317
|
+
if (style.backdropFilter && style.backdropFilter !== 'none')
|
|
4318
|
+
return true;
|
|
4319
|
+
if (style.perspective !== 'none')
|
|
4320
|
+
return true;
|
|
4321
|
+
if (style.mixBlendMode !== 'normal')
|
|
4322
|
+
return true;
|
|
4323
|
+
if (style.isolation === 'isolate')
|
|
4324
|
+
return true;
|
|
4325
|
+
if (style.contain.includes('paint') || style.contain.includes('layout'))
|
|
4326
|
+
return true;
|
|
4327
|
+
if (style.willChange.includes('transform') || style.willChange.includes('opacity') || style.willChange.includes('filter'))
|
|
4328
|
+
return true;
|
|
4329
|
+
return false;
|
|
4330
|
+
}
|
|
3110
4331
|
_updateArrowRotation() {
|
|
3111
4332
|
if (this._arrowContainer) {
|
|
3112
4333
|
const arrow = this._arrowContainer.querySelector('.dropdown-arrow');
|
|
@@ -3313,24 +4534,24 @@
|
|
|
3313
4534
|
}
|
|
3314
4535
|
}
|
|
3315
4536
|
_setActive(index) {
|
|
3316
|
-
const options = Array.from(this._optionsContainer.children);
|
|
3317
4537
|
// Clear previous active state
|
|
3318
|
-
if (this._state.activeIndex >= 0
|
|
3319
|
-
const prevOption =
|
|
3320
|
-
|
|
3321
|
-
|
|
3322
|
-
prevOption.setActive
|
|
3323
|
-
|
|
3324
|
-
|
|
3325
|
-
|
|
3326
|
-
|
|
3327
|
-
|
|
4538
|
+
if (this._state.activeIndex >= 0) {
|
|
4539
|
+
const prevOption = this._getOptionElementByIndex(this._state.activeIndex);
|
|
4540
|
+
if (prevOption) {
|
|
4541
|
+
// Check if it's a custom SelectOption or a lightweight DOM element
|
|
4542
|
+
if ('setActive' in prevOption && typeof prevOption.setActive === 'function') {
|
|
4543
|
+
prevOption.setActive(false);
|
|
4544
|
+
}
|
|
4545
|
+
else {
|
|
4546
|
+
// Lightweight option - remove active class
|
|
4547
|
+
prevOption.classList.remove('smilodon-option--active');
|
|
4548
|
+
}
|
|
3328
4549
|
}
|
|
3329
4550
|
}
|
|
3330
4551
|
this._state.activeIndex = index;
|
|
3331
4552
|
// Set new active state
|
|
3332
|
-
|
|
3333
|
-
|
|
4553
|
+
const option = this._getOptionElementByIndex(index);
|
|
4554
|
+
if (option) {
|
|
3334
4555
|
// Check if it's a custom SelectOption or a lightweight DOM element
|
|
3335
4556
|
if ('setActive' in option && typeof option.setActive === 'function') {
|
|
3336
4557
|
option.setActive(true);
|
|
@@ -3338,13 +4559,13 @@
|
|
|
3338
4559
|
else {
|
|
3339
4560
|
// Lightweight option - add active class
|
|
3340
4561
|
option.classList.add('smilodon-option--active');
|
|
3341
|
-
option.setAttribute('aria-selected', 'true');
|
|
3342
4562
|
}
|
|
3343
4563
|
if (typeof option.scrollIntoView === 'function') {
|
|
4564
|
+
// Don't scroll wildly when just opening with pre-selections
|
|
3344
4565
|
option.scrollIntoView({ block: 'nearest', behavior: 'smooth' });
|
|
3345
4566
|
}
|
|
3346
4567
|
// Announce position for screen readers
|
|
3347
|
-
const total =
|
|
4568
|
+
const total = this._state.loadedItems.length;
|
|
3348
4569
|
this._announce(`Item ${index + 1} of ${total}`);
|
|
3349
4570
|
// Update aria-activedescendant using the actual option id when available
|
|
3350
4571
|
const optionId = option.id || `${this._uniqueId}-option-${index}`;
|
|
@@ -3467,9 +4688,9 @@
|
|
|
3467
4688
|
// FIX: Do not rely on this._optionsContainer.children[index] because filtering changes the children
|
|
3468
4689
|
// Instead, use the index to update state directly
|
|
3469
4690
|
const item = this._state.loadedItems[index];
|
|
3470
|
-
|
|
3471
|
-
if (!item)
|
|
4691
|
+
if (!item) {
|
|
3472
4692
|
return;
|
|
4693
|
+
}
|
|
3473
4694
|
const isCurrentlySelected = this._state.selectedIndices.has(index);
|
|
3474
4695
|
// Keep active/focus styling aligned with the most recently interacted option.
|
|
3475
4696
|
// Without this, a previously selected item may retain active classes/styles
|
|
@@ -3480,7 +4701,7 @@
|
|
|
3480
4701
|
const wasSelected = this._state.selectedIndices.has(index);
|
|
3481
4702
|
this._state.selectedIndices.clear();
|
|
3482
4703
|
this._state.selectedItems.clear();
|
|
3483
|
-
if (!wasSelected) {
|
|
4704
|
+
if (!wasSelected || !this._config.selection.allowDeselect) {
|
|
3484
4705
|
// Select this option
|
|
3485
4706
|
this._state.selectedIndices.add(index);
|
|
3486
4707
|
this._state.selectedItems.set(index, item);
|
|
@@ -3542,16 +4763,34 @@
|
|
|
3542
4763
|
});
|
|
3543
4764
|
}
|
|
3544
4765
|
_handleOptionRemove(index) {
|
|
4766
|
+
const item = this._state.selectedItems.get(index);
|
|
3545
4767
|
const option = this._getOptionElementByIndex(index);
|
|
3546
|
-
if (!option)
|
|
3547
|
-
return;
|
|
3548
4768
|
this._state.selectedIndices.delete(index);
|
|
3549
4769
|
this._state.selectedItems.delete(index);
|
|
3550
|
-
option.setSelected
|
|
4770
|
+
if (option && 'setSelected' in option && typeof option.setSelected === 'function') {
|
|
4771
|
+
option.setSelected(false);
|
|
4772
|
+
}
|
|
4773
|
+
else if (option) {
|
|
4774
|
+
option.classList.remove('selected', 'sm-selected', 'smilodon-option--selected');
|
|
4775
|
+
option.setAttribute('aria-selected', 'false');
|
|
4776
|
+
const stateTokens = (option.dataset.smState || '')
|
|
4777
|
+
.split(' ')
|
|
4778
|
+
.map(token => token.trim())
|
|
4779
|
+
.filter(token => token && token !== 'selected');
|
|
4780
|
+
if (stateTokens.length > 0) {
|
|
4781
|
+
option.dataset.smState = stateTokens.join(' ');
|
|
4782
|
+
}
|
|
4783
|
+
else {
|
|
4784
|
+
delete option.dataset.smState;
|
|
4785
|
+
}
|
|
4786
|
+
}
|
|
3551
4787
|
this._updateInputDisplay();
|
|
4788
|
+
this._renderOptions();
|
|
3552
4789
|
this._emitChange();
|
|
3553
|
-
const config = option.getConfig
|
|
3554
|
-
|
|
4790
|
+
const config = option && 'getConfig' in option && typeof option.getConfig === 'function'
|
|
4791
|
+
? option.getConfig()
|
|
4792
|
+
: undefined;
|
|
4793
|
+
this._emit('remove', { item: config?.item ?? item, index });
|
|
3555
4794
|
}
|
|
3556
4795
|
_updateInputDisplay() {
|
|
3557
4796
|
const selectedItems = Array.from(this._state.selectedItems.values());
|
|
@@ -3560,7 +4799,7 @@
|
|
|
3560
4799
|
this._input.value = '';
|
|
3561
4800
|
this._input.placeholder = this._config.placeholder || 'Select an option...';
|
|
3562
4801
|
// Clear any badges
|
|
3563
|
-
const existingBadges = this.
|
|
4802
|
+
const existingBadges = this._inputContent.querySelectorAll('.selection-badge');
|
|
3564
4803
|
existingBadges.forEach(badge => badge.remove());
|
|
3565
4804
|
}
|
|
3566
4805
|
else if (this._config.selection.mode === 'single') {
|
|
@@ -3571,31 +4810,55 @@
|
|
|
3571
4810
|
this._input.value = '';
|
|
3572
4811
|
this._input.placeholder = '';
|
|
3573
4812
|
// Clear existing badges
|
|
3574
|
-
const existingBadges = this.
|
|
4813
|
+
const existingBadges = this._inputContent.querySelectorAll('.selection-badge');
|
|
3575
4814
|
existingBadges.forEach(badge => badge.remove());
|
|
3576
4815
|
// Create badges for each selected item
|
|
3577
4816
|
const selectedEntries = Array.from(this._state.selectedItems.entries());
|
|
3578
4817
|
selectedEntries.forEach(([index, item]) => {
|
|
3579
4818
|
const badge = document.createElement('span');
|
|
3580
4819
|
badge.className = 'selection-badge';
|
|
4820
|
+
if (this._config.styles.classNames?.badge) {
|
|
4821
|
+
badge.classList.add(...this._config.styles.classNames.badge.split(' ').filter(Boolean));
|
|
4822
|
+
}
|
|
3581
4823
|
badge.setAttribute('part', 'chip');
|
|
3582
|
-
|
|
4824
|
+
const badgeLabel = document.createElement('span');
|
|
4825
|
+
badgeLabel.className = 'selection-badge-label';
|
|
4826
|
+
if (this._config.styles.classNames?.badgeLabel) {
|
|
4827
|
+
badgeLabel.classList.add(...this._config.styles.classNames.badgeLabel.split(' ').filter(Boolean));
|
|
4828
|
+
}
|
|
4829
|
+
badgeLabel.setAttribute('part', 'chip-label');
|
|
4830
|
+
badgeLabel.textContent = getLabel(item);
|
|
4831
|
+
badge.appendChild(badgeLabel);
|
|
3583
4832
|
// Add remove button to badge
|
|
3584
|
-
|
|
3585
|
-
|
|
3586
|
-
|
|
3587
|
-
|
|
3588
|
-
|
|
3589
|
-
|
|
3590
|
-
|
|
3591
|
-
this.
|
|
3592
|
-
|
|
3593
|
-
|
|
3594
|
-
|
|
3595
|
-
|
|
3596
|
-
|
|
3597
|
-
|
|
3598
|
-
|
|
4833
|
+
if (this._config.selection.showRemoveButton !== false) {
|
|
4834
|
+
const removeBtn = document.createElement('button');
|
|
4835
|
+
removeBtn.type = 'button';
|
|
4836
|
+
removeBtn.className = 'badge-remove';
|
|
4837
|
+
if (this._config.styles.classNames?.removeButton) {
|
|
4838
|
+
removeBtn.classList.add(...this._config.styles.classNames.removeButton.split(' ').filter(Boolean));
|
|
4839
|
+
}
|
|
4840
|
+
if (this._config.styles.classNames?.badgeRemove) {
|
|
4841
|
+
removeBtn.classList.add(...this._config.styles.classNames.badgeRemove.split(' ').filter(Boolean));
|
|
4842
|
+
}
|
|
4843
|
+
removeBtn.setAttribute('part', 'chip-remove');
|
|
4844
|
+
removeBtn.setAttribute('aria-label', `Remove ${getLabel(item)}`);
|
|
4845
|
+
const removeIcon = document.createElement('span');
|
|
4846
|
+
removeIcon.className = 'badge-remove-icon';
|
|
4847
|
+
removeIcon.setAttribute('part', 'chip-remove-icon');
|
|
4848
|
+
this._setIconContent(removeIcon, this._config.selection.removeButtonIcon, '×');
|
|
4849
|
+
removeBtn.appendChild(removeIcon);
|
|
4850
|
+
removeBtn.addEventListener('pointerdown', (e) => {
|
|
4851
|
+
e.stopPropagation();
|
|
4852
|
+
e.preventDefault();
|
|
4853
|
+
});
|
|
4854
|
+
removeBtn.addEventListener('click', (e) => {
|
|
4855
|
+
e.stopPropagation();
|
|
4856
|
+
e.preventDefault();
|
|
4857
|
+
this._handleOptionRemove(index);
|
|
4858
|
+
});
|
|
4859
|
+
badge.appendChild(removeBtn);
|
|
4860
|
+
}
|
|
4861
|
+
this._inputContent.insertBefore(badge, this._input);
|
|
3599
4862
|
});
|
|
3600
4863
|
}
|
|
3601
4864
|
this._syncClearControlState();
|
|
@@ -3646,10 +4909,12 @@
|
|
|
3646
4909
|
const option = this._getOptionElementByIndex(targetIndex);
|
|
3647
4910
|
if (option) {
|
|
3648
4911
|
// Use smooth scrolling with center alignment for better UX
|
|
3649
|
-
option.scrollIntoView
|
|
3650
|
-
|
|
3651
|
-
|
|
3652
|
-
|
|
4912
|
+
if (typeof option.scrollIntoView === 'function') {
|
|
4913
|
+
option.scrollIntoView({
|
|
4914
|
+
block: this._config.scrollToSelected.block || 'center',
|
|
4915
|
+
behavior: 'smooth',
|
|
4916
|
+
});
|
|
4917
|
+
}
|
|
3653
4918
|
// Also set it as active for keyboard navigation
|
|
3654
4919
|
this._setActive(targetIndex);
|
|
3655
4920
|
}
|
|
@@ -3861,7 +5126,6 @@
|
|
|
3861
5126
|
const getValue = this._config.serverSide.getValueFromItem || ((item) => item?.value ?? item);
|
|
3862
5127
|
const selectedValues = selectedItems.map(getValue);
|
|
3863
5128
|
const selectedIndices = Array.from(this._state.selectedIndices);
|
|
3864
|
-
// Debug: log change payload
|
|
3865
5129
|
this._emit('change', { selectedItems, selectedValues, selectedIndices });
|
|
3866
5130
|
this._config.callbacks.onChange?.(selectedItems, selectedValues);
|
|
3867
5131
|
}
|
|
@@ -4065,8 +5329,9 @@
|
|
|
4065
5329
|
this._clearControl.setAttribute('aria-label', this._config.clearControl.ariaLabel || 'Clear selection and search');
|
|
4066
5330
|
}
|
|
4067
5331
|
if (this._clearControlIcon) {
|
|
4068
|
-
this._clearControlIcon.
|
|
5332
|
+
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>`;
|
|
4069
5333
|
}
|
|
5334
|
+
this._syncStyleConfigVariables();
|
|
4070
5335
|
if (this._dropdown) {
|
|
4071
5336
|
if (this._config.selection.mode === 'multi') {
|
|
4072
5337
|
this._dropdown.setAttribute('aria-multiselectable', 'true');
|
|
@@ -4075,9 +5340,14 @@
|
|
|
4075
5340
|
this._dropdown.removeAttribute('aria-multiselectable');
|
|
4076
5341
|
}
|
|
4077
5342
|
}
|
|
5343
|
+
this._syncDirectionConfig();
|
|
5344
|
+
this._syncInputContainerMode();
|
|
5345
|
+
this._syncMultiSelectDisplayConfig();
|
|
5346
|
+
this._syncDropdownPlacement();
|
|
4078
5347
|
// Re-initialize observers in case infinite scroll was enabled/disabled
|
|
4079
5348
|
this._initializeObservers();
|
|
4080
5349
|
this._syncClearControlState();
|
|
5350
|
+
this._updateInputDisplay();
|
|
4081
5351
|
this._renderOptions();
|
|
4082
5352
|
}
|
|
4083
5353
|
_mergeConfig(target, source) {
|
|
@@ -4180,6 +5450,8 @@
|
|
|
4180
5450
|
* Render options based on current state
|
|
4181
5451
|
*/
|
|
4182
5452
|
_renderOptions() {
|
|
5453
|
+
this._renderCycleId += 1;
|
|
5454
|
+
const renderCycleId = this._renderCycleId;
|
|
4183
5455
|
// Cleanup observer
|
|
4184
5456
|
if (this._loadMoreTrigger && this._intersectionObserver) {
|
|
4185
5457
|
this._intersectionObserver.unobserve(this._loadMoreTrigger);
|
|
@@ -4231,6 +5503,9 @@
|
|
|
4231
5503
|
header.textContent = group.label;
|
|
4232
5504
|
}
|
|
4233
5505
|
header.classList.add('group-header');
|
|
5506
|
+
if (this._config.styles.classNames?.groupHeader) {
|
|
5507
|
+
header.classList.add(...this._config.styles.classNames.groupHeader.split(' ').filter(Boolean));
|
|
5508
|
+
}
|
|
4234
5509
|
header.setAttribute('part', 'group-header');
|
|
4235
5510
|
this._optionsContainer.appendChild(header);
|
|
4236
5511
|
group.options.forEach(item => {
|
|
@@ -4244,23 +5519,21 @@
|
|
|
4244
5519
|
}
|
|
4245
5520
|
else {
|
|
4246
5521
|
// Normal rendering (flat list or filtered)
|
|
4247
|
-
|
|
5522
|
+
const filteredIndices = [];
|
|
4248
5523
|
this._state.loadedItems.forEach((item, index) => {
|
|
4249
|
-
// Apply filter if query exists
|
|
4250
5524
|
if (query) {
|
|
4251
5525
|
try {
|
|
4252
5526
|
const label = String(getLabel(item)).toLowerCase();
|
|
4253
5527
|
if (!label.includes(query))
|
|
4254
5528
|
return;
|
|
4255
5529
|
}
|
|
4256
|
-
catch (
|
|
5530
|
+
catch (_e) {
|
|
4257
5531
|
return;
|
|
4258
5532
|
}
|
|
4259
5533
|
}
|
|
4260
|
-
|
|
4261
|
-
this._renderSingleOption(item, index, getValue, getLabel);
|
|
5534
|
+
filteredIndices.push(index);
|
|
4262
5535
|
});
|
|
4263
|
-
if (
|
|
5536
|
+
if (filteredIndices.length === 0 && !this._state.isBusy) {
|
|
4264
5537
|
const empty = document.createElement('div');
|
|
4265
5538
|
empty.setAttribute('part', 'no-results');
|
|
4266
5539
|
empty.className = 'empty-state';
|
|
@@ -4272,6 +5545,54 @@
|
|
|
4272
5545
|
}
|
|
4273
5546
|
this._optionsContainer.appendChild(empty);
|
|
4274
5547
|
}
|
|
5548
|
+
else {
|
|
5549
|
+
const shouldIncrementalRender = this._config.virtualize !== false
|
|
5550
|
+
&& this._state.groupedItems.length === 0
|
|
5551
|
+
&& filteredIndices.length > 300;
|
|
5552
|
+
if (shouldIncrementalRender) {
|
|
5553
|
+
const chunkSize = 80;
|
|
5554
|
+
let cursor = 0;
|
|
5555
|
+
let maxRenderTarget = 0;
|
|
5556
|
+
if (this._state.selectedIndices.size > 0 && this._config.scrollToSelected.enabled) {
|
|
5557
|
+
const indices = Array.from(this._state.selectedIndices).sort((a, b) => a - b);
|
|
5558
|
+
const targetIndex = this._config.scrollToSelected.multiSelectTarget === 'first' ? indices[0] : indices[indices.length - 1];
|
|
5559
|
+
const filteredPos = filteredIndices.indexOf(targetIndex);
|
|
5560
|
+
if (filteredPos !== -1) {
|
|
5561
|
+
maxRenderTarget = filteredPos + 20; // Ensure we render up to the selection
|
|
5562
|
+
}
|
|
5563
|
+
}
|
|
5564
|
+
const renderChunk = () => {
|
|
5565
|
+
if (renderCycleId !== this._renderCycleId)
|
|
5566
|
+
return;
|
|
5567
|
+
const fragment = document.createDocumentFragment();
|
|
5568
|
+
const chunkEnd = Math.min(Math.max(cursor + chunkSize, maxRenderTarget), filteredIndices.length);
|
|
5569
|
+
maxRenderTarget = 0; // Reset after fast-forwarding
|
|
5570
|
+
for (; cursor < chunkEnd; cursor += 1) {
|
|
5571
|
+
const itemIndex = filteredIndices[cursor];
|
|
5572
|
+
const item = this._state.loadedItems[itemIndex];
|
|
5573
|
+
this._renderSingleOption(item, itemIndex, getValue, getLabel, fragment);
|
|
5574
|
+
}
|
|
5575
|
+
this._optionsContainer.appendChild(fragment);
|
|
5576
|
+
if (cursor < filteredIndices.length) {
|
|
5577
|
+
requestAnimationFrame(renderChunk);
|
|
5578
|
+
}
|
|
5579
|
+
else {
|
|
5580
|
+
if (renderCycleId !== this._renderCycleId)
|
|
5581
|
+
return;
|
|
5582
|
+
if (!this._state.isBusy && (this._config.loadMore.enabled || this._config.infiniteScroll.enabled) && this._state.loadedItems.length > 0) {
|
|
5583
|
+
this._addLoadMoreTrigger();
|
|
5584
|
+
}
|
|
5585
|
+
this._finalizePerfMarks();
|
|
5586
|
+
}
|
|
5587
|
+
};
|
|
5588
|
+
renderChunk();
|
|
5589
|
+
return;
|
|
5590
|
+
}
|
|
5591
|
+
filteredIndices.forEach((itemIndex) => {
|
|
5592
|
+
const item = this._state.loadedItems[itemIndex];
|
|
5593
|
+
this._renderSingleOption(item, itemIndex, getValue, getLabel);
|
|
5594
|
+
});
|
|
5595
|
+
}
|
|
4275
5596
|
}
|
|
4276
5597
|
// Append Busy Indicator if busy
|
|
4277
5598
|
if (this._state.isBusy && this._config.busyBucket.enabled) {
|
|
@@ -4296,7 +5617,7 @@
|
|
|
4296
5617
|
}
|
|
4297
5618
|
this._finalizePerfMarks();
|
|
4298
5619
|
}
|
|
4299
|
-
_renderSingleOption(item, index, getValue, getLabel) {
|
|
5620
|
+
_renderSingleOption(item, index, getValue, getLabel, targetContainer = this._optionsContainer) {
|
|
4300
5621
|
const isSelected = this._state.selectedIndices.has(index);
|
|
4301
5622
|
const isDisabled = Boolean(item?.disabled);
|
|
4302
5623
|
const optionId = `${this._uniqueId}-option-${index}`;
|
|
@@ -4312,7 +5633,8 @@
|
|
|
4312
5633
|
disabled: isDisabled,
|
|
4313
5634
|
id: optionId,
|
|
4314
5635
|
});
|
|
4315
|
-
this.
|
|
5636
|
+
optionElement.setAttribute('dir', this._config.direction ?? 'ltr');
|
|
5637
|
+
targetContainer.appendChild(optionElement);
|
|
4316
5638
|
return;
|
|
4317
5639
|
}
|
|
4318
5640
|
const option = new SelectOption({
|
|
@@ -4325,8 +5647,23 @@
|
|
|
4325
5647
|
getValue,
|
|
4326
5648
|
getLabel,
|
|
4327
5649
|
showRemoveButton: this._config.selection.mode === 'multi' && this._config.selection.showRemoveButton,
|
|
5650
|
+
removeButtonIcon: this._config.selection.removeButtonIcon,
|
|
4328
5651
|
classMap: this.classMap,
|
|
5652
|
+
className: this._config.styles.classNames?.option,
|
|
4329
5653
|
});
|
|
5654
|
+
if (this._config.styles.classNames?.option) {
|
|
5655
|
+
option.classList.add(...this._config.styles.classNames.option.split(' ').filter(Boolean));
|
|
5656
|
+
}
|
|
5657
|
+
option.setAttribute('dir', this._config.direction ?? 'ltr');
|
|
5658
|
+
if (isSelected && this._config.styles.classNames?.selectedOption) {
|
|
5659
|
+
option.classList.add(...this._config.styles.classNames.selectedOption.split(' ').filter(Boolean));
|
|
5660
|
+
}
|
|
5661
|
+
if (this._state.activeIndex === index && this._config.styles.classNames?.activeOption) {
|
|
5662
|
+
option.classList.add(...this._config.styles.classNames.activeOption.split(' ').filter(Boolean));
|
|
5663
|
+
}
|
|
5664
|
+
if (isDisabled && this._config.styles.classNames?.disabledOption) {
|
|
5665
|
+
option.classList.add(...this._config.styles.classNames.disabledOption.split(' ').filter(Boolean));
|
|
5666
|
+
}
|
|
4330
5667
|
// Valid part attribute on the web component host itself
|
|
4331
5668
|
option.setAttribute('part', 'option');
|
|
4332
5669
|
option.dataset.index = String(index);
|
|
@@ -4341,20 +5678,16 @@
|
|
|
4341
5678
|
option.dataset.smValue = String(val);
|
|
4342
5679
|
}
|
|
4343
5680
|
option.id = option.id || optionId;
|
|
4344
|
-
|
|
4345
|
-
|
|
4346
|
-
|
|
4347
|
-
|
|
4348
|
-
shiftKey: mouseEvent.shiftKey,
|
|
4349
|
-
toggleKey: mouseEvent.ctrlKey || mouseEvent.metaKey,
|
|
4350
|
-
});
|
|
4351
|
-
});
|
|
5681
|
+
// Do NOT bind a native click listener here for SelectOption elements.
|
|
5682
|
+
// Like custom rendered options, they are fully handled by the `handleOptionEvent` delegator
|
|
5683
|
+
// on `this._optionsContainer` (line 1221).
|
|
5684
|
+
// Adding this listener causes the double-click toggle bug since both fire on selection!
|
|
4352
5685
|
option.addEventListener('optionRemove', (event) => {
|
|
4353
5686
|
const detail = event.detail;
|
|
4354
5687
|
const targetIndex = detail?.index ?? index;
|
|
4355
5688
|
this._handleOptionRemove(targetIndex);
|
|
4356
5689
|
});
|
|
4357
|
-
|
|
5690
|
+
targetContainer.appendChild(option);
|
|
4358
5691
|
}
|
|
4359
5692
|
_normalizeCustomOptionElement(element, meta) {
|
|
4360
5693
|
const optionEl = element instanceof HTMLElement ? element : document.createElement('div');
|
|
@@ -4364,6 +5697,9 @@
|
|
|
4364
5697
|
}
|
|
4365
5698
|
// Add both semantic namespaced classes and the legacy internal classes that CSS uses
|
|
4366
5699
|
optionEl.classList.add('smilodon-option', 'option');
|
|
5700
|
+
if (this._config.styles.classNames?.option) {
|
|
5701
|
+
optionEl.classList.add(...this._config.styles.classNames.option.split(' ').filter(Boolean));
|
|
5702
|
+
}
|
|
4367
5703
|
// Toggle state classes using classMap if available
|
|
4368
5704
|
const isSelected = meta.selected;
|
|
4369
5705
|
const isActive = meta.active;
|
|
@@ -4375,26 +5711,44 @@
|
|
|
4375
5711
|
if (isSelected) {
|
|
4376
5712
|
optionEl.classList.add(...selectedClasses);
|
|
4377
5713
|
optionEl.classList.add('smilodon-option--selected');
|
|
5714
|
+
if (this._config.styles.classNames?.selectedOption) {
|
|
5715
|
+
optionEl.classList.add(...this._config.styles.classNames.selectedOption.split(' ').filter(Boolean));
|
|
5716
|
+
}
|
|
4378
5717
|
}
|
|
4379
5718
|
else {
|
|
4380
5719
|
optionEl.classList.remove(...selectedClasses);
|
|
4381
5720
|
optionEl.classList.remove('smilodon-option--selected');
|
|
5721
|
+
if (this._config.styles.classNames?.selectedOption) {
|
|
5722
|
+
optionEl.classList.remove(...this._config.styles.classNames.selectedOption.split(' ').filter(Boolean));
|
|
5723
|
+
}
|
|
4382
5724
|
}
|
|
4383
5725
|
if (isActive) {
|
|
4384
5726
|
optionEl.classList.add(...activeClasses);
|
|
4385
5727
|
optionEl.classList.add('smilodon-option--active');
|
|
5728
|
+
if (this._config.styles.classNames?.activeOption) {
|
|
5729
|
+
optionEl.classList.add(...this._config.styles.classNames.activeOption.split(' ').filter(Boolean));
|
|
5730
|
+
}
|
|
4386
5731
|
}
|
|
4387
5732
|
else {
|
|
4388
5733
|
optionEl.classList.remove(...activeClasses);
|
|
4389
5734
|
optionEl.classList.remove('smilodon-option--active');
|
|
5735
|
+
if (this._config.styles.classNames?.activeOption) {
|
|
5736
|
+
optionEl.classList.remove(...this._config.styles.classNames.activeOption.split(' ').filter(Boolean));
|
|
5737
|
+
}
|
|
4390
5738
|
}
|
|
4391
5739
|
if (isDisabled) {
|
|
4392
5740
|
optionEl.classList.add(...disabledClasses);
|
|
4393
5741
|
optionEl.classList.add('smilodon-option--disabled');
|
|
5742
|
+
if (this._config.styles.classNames?.disabledOption) {
|
|
5743
|
+
optionEl.classList.add(...this._config.styles.classNames.disabledOption.split(' ').filter(Boolean));
|
|
5744
|
+
}
|
|
4394
5745
|
}
|
|
4395
5746
|
else {
|
|
4396
5747
|
optionEl.classList.remove(...disabledClasses);
|
|
4397
5748
|
optionEl.classList.remove('smilodon-option--disabled');
|
|
5749
|
+
if (this._config.styles.classNames?.disabledOption) {
|
|
5750
|
+
optionEl.classList.remove(...this._config.styles.classNames.disabledOption.split(' ').filter(Boolean));
|
|
5751
|
+
}
|
|
4398
5752
|
}
|
|
4399
5753
|
// Data Attributes Contract
|
|
4400
5754
|
const state = [];
|
|
@@ -4441,35 +5795,9 @@
|
|
|
4441
5795
|
optionEl.tabIndex = -1;
|
|
4442
5796
|
}
|
|
4443
5797
|
if (!this._customOptionBoundElements.has(optionEl)) {
|
|
4444
|
-
|
|
4445
|
-
|
|
4446
|
-
|
|
4447
|
-
if (current.getAttribute('aria-disabled') === 'true')
|
|
4448
|
-
return;
|
|
4449
|
-
const parsedIndex = Number(current.dataset.index);
|
|
4450
|
-
if (!Number.isFinite(parsedIndex))
|
|
4451
|
-
return;
|
|
4452
|
-
const mouseEvent = e;
|
|
4453
|
-
this._selectOption(parsedIndex, {
|
|
4454
|
-
shiftKey: mouseEvent.shiftKey,
|
|
4455
|
-
toggleKey: mouseEvent.ctrlKey || mouseEvent.metaKey,
|
|
4456
|
-
});
|
|
4457
|
-
});
|
|
4458
|
-
optionEl.addEventListener('keydown', (e) => {
|
|
4459
|
-
if (e.key !== 'Enter' && e.key !== ' ')
|
|
4460
|
-
return;
|
|
4461
|
-
const current = e.currentTarget;
|
|
4462
|
-
if (current.getAttribute('aria-disabled') === 'true')
|
|
4463
|
-
return;
|
|
4464
|
-
const parsedIndex = Number(current.dataset.index);
|
|
4465
|
-
if (!Number.isFinite(parsedIndex))
|
|
4466
|
-
return;
|
|
4467
|
-
e.preventDefault();
|
|
4468
|
-
this._selectOption(parsedIndex, {
|
|
4469
|
-
shiftKey: e.shiftKey,
|
|
4470
|
-
toggleKey: e.ctrlKey || e.metaKey,
|
|
4471
|
-
});
|
|
4472
|
-
});
|
|
5798
|
+
// Intentionally NOT binding native option click listeners for custom options!
|
|
5799
|
+
// All option interactions are globally handled by _optionsContainer.addEventListener('click', handleOptionEvent);
|
|
5800
|
+
// Re-attaching here causes the double-click toggle bug if a child component fails to stopPropagation.
|
|
4473
5801
|
this._customOptionBoundElements.add(optionEl);
|
|
4474
5802
|
}
|
|
4475
5803
|
return optionEl;
|