@smilodon/core 1.4.11 → 1.4.13
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 +20 -15
- package/dist/index.cjs +1134 -454
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1134 -454
- 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 +1134 -454
- 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 +16 -1
- package/dist/types/src/config/global-config.d.ts +27 -0
- package/dist/types/src/types.d.ts +58 -0
- package/dist/types/tests/capabilities-tracking.spec.d.ts +1 -0
- package/package.json +1 -1
package/dist/index.umd.js
CHANGED
|
@@ -1355,6 +1355,7 @@
|
|
|
1355
1355
|
maxSelections: 0,
|
|
1356
1356
|
showRemoveButton: true,
|
|
1357
1357
|
closeOnSelect: true,
|
|
1358
|
+
toggleOnTriggerClick: true,
|
|
1358
1359
|
},
|
|
1359
1360
|
scrollToSelected: {
|
|
1360
1361
|
enabled: true,
|
|
@@ -1407,6 +1408,18 @@
|
|
|
1407
1408
|
icon: '×',
|
|
1408
1409
|
},
|
|
1409
1410
|
callbacks: {},
|
|
1411
|
+
tracking: {
|
|
1412
|
+
enabled: false,
|
|
1413
|
+
events: true,
|
|
1414
|
+
styling: true,
|
|
1415
|
+
limitations: true,
|
|
1416
|
+
emitDiagnostics: false,
|
|
1417
|
+
maxEntries: 200,
|
|
1418
|
+
},
|
|
1419
|
+
limitations: {
|
|
1420
|
+
policies: {},
|
|
1421
|
+
autoMitigateRuntimeModeSwitch: true,
|
|
1422
|
+
},
|
|
1410
1423
|
enabled: true,
|
|
1411
1424
|
searchable: false,
|
|
1412
1425
|
placeholder: 'Select an option...',
|
|
@@ -1875,6 +1888,8 @@
|
|
|
1875
1888
|
* Enhanced Select Component
|
|
1876
1889
|
* Implements all advanced features: infinite scroll, load more, busy state,
|
|
1877
1890
|
* server-side selection, and full customization
|
|
1891
|
+
*
|
|
1892
|
+
* ✨ Redesigned with formal elegance, refined microinteractions, and polished UX
|
|
1878
1893
|
*/
|
|
1879
1894
|
class EnhancedSelect extends HTMLElement {
|
|
1880
1895
|
get classMap() {
|
|
@@ -1883,6 +1898,10 @@
|
|
|
1883
1898
|
set classMap(map) {
|
|
1884
1899
|
this._classMap = map;
|
|
1885
1900
|
this._setGlobalStylesMirroring(Boolean(this._optionRenderer || map || this._groupHeaderRenderer));
|
|
1901
|
+
this._track('style', 'classMapChanged', {
|
|
1902
|
+
hasClassMap: Boolean(map),
|
|
1903
|
+
keys: map ? Object.keys(map) : [],
|
|
1904
|
+
});
|
|
1886
1905
|
if (!this.isConnected)
|
|
1887
1906
|
return;
|
|
1888
1907
|
this._renderOptions();
|
|
@@ -1898,6 +1917,7 @@
|
|
|
1898
1917
|
set groupHeaderRenderer(renderer) {
|
|
1899
1918
|
this._groupHeaderRenderer = renderer;
|
|
1900
1919
|
this._setGlobalStylesMirroring(Boolean(this._optionRenderer || this._classMap || renderer));
|
|
1920
|
+
this._track('style', 'groupHeaderRendererChanged', { enabled: Boolean(renderer) });
|
|
1901
1921
|
if (!this.isConnected)
|
|
1902
1922
|
return;
|
|
1903
1923
|
this._renderOptions();
|
|
@@ -1916,6 +1936,9 @@
|
|
|
1916
1936
|
this._mirrorGlobalStylesForCustomOptions = false;
|
|
1917
1937
|
this._globalStylesObserver = null;
|
|
1918
1938
|
this._globalStylesContainer = null;
|
|
1939
|
+
this._tracking = { events: [], styles: [], limitations: [] };
|
|
1940
|
+
this._suppressBlurClose = false;
|
|
1941
|
+
this._renderCycleId = 0;
|
|
1919
1942
|
this._shadow = this.attachShadow({ mode: 'open' });
|
|
1920
1943
|
this._uniqueId = `enhanced-select-${Math.random().toString(36).substr(2, 9)}`;
|
|
1921
1944
|
this._rendererHelpers = this._buildRendererHelpers();
|
|
@@ -1990,6 +2013,7 @@
|
|
|
1990
2013
|
if (this._boundArrowClick && this._arrowContainer) {
|
|
1991
2014
|
this._arrowContainer.removeEventListener('click', this._boundArrowClick);
|
|
1992
2015
|
}
|
|
2016
|
+
this._renderCycleId += 1;
|
|
1993
2017
|
this._teardownGlobalStylesMirroring();
|
|
1994
2018
|
}
|
|
1995
2019
|
_setGlobalStylesMirroring(enabled) {
|
|
@@ -2000,6 +2024,7 @@
|
|
|
2000
2024
|
return;
|
|
2001
2025
|
}
|
|
2002
2026
|
this._mirrorGlobalStylesForCustomOptions = enabled;
|
|
2027
|
+
this._track('style', 'globalStylesMirroringChanged', { enabled });
|
|
2003
2028
|
if (enabled) {
|
|
2004
2029
|
this._setupGlobalStylesMirroring();
|
|
2005
2030
|
}
|
|
@@ -2092,8 +2117,48 @@
|
|
|
2092
2117
|
const container = document.createElement('div');
|
|
2093
2118
|
container.className = 'input-container';
|
|
2094
2119
|
container.setAttribute('part', 'button');
|
|
2120
|
+
const inputStyles = this._config.styles.input;
|
|
2121
|
+
if (inputStyles && !this._config.styles.container) {
|
|
2122
|
+
const shellStyleKeys = [
|
|
2123
|
+
'background',
|
|
2124
|
+
'backgroundColor',
|
|
2125
|
+
'border',
|
|
2126
|
+
'borderColor',
|
|
2127
|
+
'borderStyle',
|
|
2128
|
+
'borderWidth',
|
|
2129
|
+
'borderRadius',
|
|
2130
|
+
'boxShadow',
|
|
2131
|
+
'padding',
|
|
2132
|
+
'height',
|
|
2133
|
+
'minHeight',
|
|
2134
|
+
'maxHeight',
|
|
2135
|
+
];
|
|
2136
|
+
for (const key of shellStyleKeys) {
|
|
2137
|
+
const value = inputStyles[key];
|
|
2138
|
+
if (value != null && value !== '') {
|
|
2139
|
+
container.style[key] = value;
|
|
2140
|
+
}
|
|
2141
|
+
}
|
|
2142
|
+
}
|
|
2095
2143
|
return container;
|
|
2096
2144
|
}
|
|
2145
|
+
_syncInputContainerMode() {
|
|
2146
|
+
if (!this._inputContainer || !this._input)
|
|
2147
|
+
return;
|
|
2148
|
+
const isMulti = this._config.selection.mode === 'multi';
|
|
2149
|
+
this._inputContainer.classList.toggle('input-container--multi', isMulti);
|
|
2150
|
+
this._inputContainer.classList.toggle('input-container--single', !isMulti);
|
|
2151
|
+
if (isMulti) {
|
|
2152
|
+
this._input.style.flex = '1 0 var(--select-multi-input-min-width, 96px)';
|
|
2153
|
+
this._input.style.width = 'auto';
|
|
2154
|
+
this._input.style.minWidth = 'var(--select-multi-input-min-width, 96px)';
|
|
2155
|
+
}
|
|
2156
|
+
else {
|
|
2157
|
+
this._input.style.flex = '1 1 auto';
|
|
2158
|
+
this._input.style.width = '100%';
|
|
2159
|
+
this._input.style.minWidth = '0';
|
|
2160
|
+
}
|
|
2161
|
+
}
|
|
2097
2162
|
_createInput() {
|
|
2098
2163
|
const input = document.createElement('input');
|
|
2099
2164
|
input.setAttribute('part', 'input');
|
|
@@ -2103,6 +2168,35 @@
|
|
|
2103
2168
|
input.placeholder = this._config.placeholder || 'Select an option...';
|
|
2104
2169
|
input.disabled = !this._config.enabled;
|
|
2105
2170
|
input.readOnly = !this._config.searchable;
|
|
2171
|
+
// Apply a direct inline reset so the input is only the writable text layer,
|
|
2172
|
+
// while the `.input-container` remains the sole visible control shell.
|
|
2173
|
+
input.style.all = 'unset';
|
|
2174
|
+
input.style.display = 'block';
|
|
2175
|
+
input.style.flex = '1 1 auto';
|
|
2176
|
+
input.style.width = '100%';
|
|
2177
|
+
input.style.maxWidth = '100%';
|
|
2178
|
+
input.style.minWidth = '0';
|
|
2179
|
+
input.style.minInlineSize = '0';
|
|
2180
|
+
input.style.minHeight = '0';
|
|
2181
|
+
input.style.padding = '0';
|
|
2182
|
+
input.style.margin = '0';
|
|
2183
|
+
input.style.border = '0';
|
|
2184
|
+
input.style.background = 'transparent';
|
|
2185
|
+
input.style.boxSizing = 'border-box';
|
|
2186
|
+
input.style.outline = 'none';
|
|
2187
|
+
input.style.font = 'inherit';
|
|
2188
|
+
input.style.fontFamily = 'inherit';
|
|
2189
|
+
input.style.lineHeight = 'inherit';
|
|
2190
|
+
input.style.color = 'inherit';
|
|
2191
|
+
input.style.alignSelf = 'center';
|
|
2192
|
+
input.style.appearance = 'none';
|
|
2193
|
+
input.style.webkitAppearance = 'none';
|
|
2194
|
+
input.style.boxShadow = 'none';
|
|
2195
|
+
input.style.borderRadius = '0';
|
|
2196
|
+
input.style.overflow = 'hidden';
|
|
2197
|
+
input.style.textOverflow = 'ellipsis';
|
|
2198
|
+
input.style.whiteSpace = 'nowrap';
|
|
2199
|
+
input.style.cursor = this._config.searchable ? 'text' : 'default';
|
|
2106
2200
|
// Update readonly when input is focused if searchable
|
|
2107
2201
|
input.addEventListener('focus', () => {
|
|
2108
2202
|
if (this._config.searchable) {
|
|
@@ -2113,7 +2207,22 @@
|
|
|
2113
2207
|
input.className += ' ' + this._config.styles.classNames.input;
|
|
2114
2208
|
}
|
|
2115
2209
|
if (this._config.styles.input) {
|
|
2116
|
-
|
|
2210
|
+
const inputStyles = { ...this._config.styles.input };
|
|
2211
|
+
// Route shell-like styling to .input-container so the control appears as
|
|
2212
|
+
// a single styled input instead of two visually separate layers.
|
|
2213
|
+
delete inputStyles.background;
|
|
2214
|
+
delete inputStyles.backgroundColor;
|
|
2215
|
+
delete inputStyles.border;
|
|
2216
|
+
delete inputStyles.borderColor;
|
|
2217
|
+
delete inputStyles.borderStyle;
|
|
2218
|
+
delete inputStyles.borderWidth;
|
|
2219
|
+
delete inputStyles.borderRadius;
|
|
2220
|
+
delete inputStyles.boxShadow;
|
|
2221
|
+
delete inputStyles.padding;
|
|
2222
|
+
delete inputStyles.height;
|
|
2223
|
+
delete inputStyles.minHeight;
|
|
2224
|
+
delete inputStyles.maxHeight;
|
|
2225
|
+
Object.assign(input.style, inputStyles);
|
|
2117
2226
|
}
|
|
2118
2227
|
input.setAttribute('role', 'combobox');
|
|
2119
2228
|
input.setAttribute('aria-expanded', 'false');
|
|
@@ -2157,7 +2266,7 @@
|
|
|
2157
2266
|
container.className = 'dropdown-arrow-container';
|
|
2158
2267
|
container.innerHTML = `
|
|
2159
2268
|
<svg class="dropdown-arrow" part="arrow" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2160
|
-
<path d="M4 6L8 10L12 6" stroke="currentColor" stroke-width="
|
|
2269
|
+
<path d="M4 6L8 10L12 6" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
|
2161
2270
|
</svg>
|
|
2162
2271
|
`;
|
|
2163
2272
|
return container;
|
|
@@ -2170,7 +2279,7 @@
|
|
|
2170
2279
|
const icon = document.createElement('span');
|
|
2171
2280
|
icon.className = 'clear-control-icon';
|
|
2172
2281
|
icon.setAttribute('part', 'clear-icon');
|
|
2173
|
-
icon.
|
|
2282
|
+
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>`;
|
|
2174
2283
|
button.setAttribute('aria-label', this._config.clearControl.ariaLabel || 'Clear selection and search');
|
|
2175
2284
|
button.appendChild(icon);
|
|
2176
2285
|
this._clearControlIcon = icon;
|
|
@@ -2196,18 +2305,229 @@
|
|
|
2196
2305
|
this._dropdown.id = listboxId;
|
|
2197
2306
|
this._input.setAttribute('aria-controls', listboxId);
|
|
2198
2307
|
this._input.setAttribute('aria-owns', listboxId);
|
|
2308
|
+
this._syncInputContainerMode();
|
|
2199
2309
|
this._syncClearControlState();
|
|
2200
2310
|
}
|
|
2201
2311
|
_initializeStyles() {
|
|
2202
2312
|
const style = document.createElement('style');
|
|
2203
2313
|
style.textContent = `
|
|
2314
|
+
/* ═══════════════════════════════════════════════════════════════════════════
|
|
2315
|
+
ELEGANT SELECT COMPONENT — Refined Design System
|
|
2316
|
+
Formal aesthetics with sophisticated microinteractions
|
|
2317
|
+
═══════════════════════════════════════════════════════════════════════════ */
|
|
2318
|
+
|
|
2204
2319
|
:host {
|
|
2320
|
+
--select-primary: #1a1a2e;
|
|
2321
|
+
--select-primary-light: #16213e;
|
|
2322
|
+
--select-accent: #0f3460;
|
|
2323
|
+
--select-accent-hover: #e94560;
|
|
2324
|
+
--select-surface: #ffffff;
|
|
2325
|
+
--select-surface-elevated: #fafbfc;
|
|
2326
|
+
--select-border: #e1e5eb;
|
|
2327
|
+
--select-border-focus: #0f3460;
|
|
2328
|
+
--select-text: #1a1a2e;
|
|
2329
|
+
--select-text-muted: #6b7280;
|
|
2330
|
+
--select-text-placeholder: #9ca3af;
|
|
2331
|
+
--select-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.04);
|
|
2332
|
+
--select-shadow-md: 0 4px 12px rgba(0, 0, 0, 0.08);
|
|
2333
|
+
--select-shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.12);
|
|
2334
|
+
--select-shadow-focus: 0 0 0 3px rgba(15, 52, 96, 0.12);
|
|
2335
|
+
--select-radius-sm: 6px;
|
|
2336
|
+
--select-radius-md: 10px;
|
|
2337
|
+
--select-radius-lg: 14px;
|
|
2338
|
+
--select-transition-fast: 150ms cubic-bezier(0.4, 0, 0.2, 1);
|
|
2339
|
+
--select-transition-smooth: 250ms cubic-bezier(0.4, 0, 0.2, 1);
|
|
2340
|
+
--select-transition-bounce: 350ms cubic-bezier(0.34, 1.56, 0.64, 1);
|
|
2341
|
+
--select-badge-animation: badgeEnter 300ms cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
|
|
2342
|
+
--select-badge-enter-from-opacity: 0;
|
|
2343
|
+
--select-badge-enter-from-transform: scale(0.8) translateY(-4px);
|
|
2344
|
+
--select-badge-enter-to-opacity: 1;
|
|
2345
|
+
--select-badge-enter-to-transform: scale(1) translateY(0);
|
|
2346
|
+
--select-badge-hover-transform: scale(1.02);
|
|
2347
|
+
--select-badge-letter-spacing: 0.01em;
|
|
2348
|
+
--select-badge-hover-shadow: var(--select-shadow-md), inset 0 1px 0 rgba(255, 255, 255, 0.15);
|
|
2349
|
+
--select-badge-remove-focus-outline: 2px solid rgba(255, 255, 255, 0.5);
|
|
2350
|
+
--select-badge-remove-focus-offset: 1px;
|
|
2351
|
+
--select-badge-remove-hover-transform: scale(1.15) rotate(90deg);
|
|
2352
|
+
--select-badge-remove-active-transform: scale(0.95) rotate(90deg);
|
|
2353
|
+
--select-input-hover-border: var(--select-border-focus);
|
|
2354
|
+
--select-input-hover-shadow: var(--select-shadow-sm), 0 0 0 1px rgba(15, 52, 96, 0.05);
|
|
2355
|
+
--select-input-font-weight: 450;
|
|
2356
|
+
--select-input-letter-spacing: 0.01em;
|
|
2357
|
+
--select-input-disabled-opacity: 0.6;
|
|
2358
|
+
--select-separator-opacity: 0.6;
|
|
2359
|
+
--select-separator-active-opacity: 1;
|
|
2360
|
+
--select-separator-dark-bg: linear-gradient(
|
|
2361
|
+
to bottom,
|
|
2362
|
+
transparent 0%,
|
|
2363
|
+
var(--select-border) 20%,
|
|
2364
|
+
var(--select-border) 80%,
|
|
2365
|
+
transparent 100%
|
|
2366
|
+
);
|
|
2367
|
+
--select-arrow-open-transform: rotate(180deg);
|
|
2368
|
+
--select-clear-button-hover-transform: translateY(-50%) scale(1.1);
|
|
2369
|
+
--select-clear-button-active-transform: translateY(-50%) scale(0.95);
|
|
2370
|
+
--select-clear-button-focus-offset: 2px;
|
|
2371
|
+
--select-clear-icon-size: 14px;
|
|
2372
|
+
--select-dropdown-top: calc(100% + 6px);
|
|
2373
|
+
--select-dropdown-animation: dropdownEnter 200ms cubic-bezier(0.4, 0, 0.2, 1) forwards;
|
|
2374
|
+
--select-dropdown-enter-from-opacity: 0;
|
|
2375
|
+
--select-dropdown-enter-from-transform: translateY(-8px) scale(0.98);
|
|
2376
|
+
--select-dropdown-enter-to-opacity: 1;
|
|
2377
|
+
--select-dropdown-enter-to-transform: translateY(0) scale(1);
|
|
2378
|
+
--select-dropdown-scroll-behavior: smooth;
|
|
2379
|
+
--select-dropdown-transform-origin: top center;
|
|
2380
|
+
--select-scrollbar-width: 6px;
|
|
2381
|
+
--select-scrollbar-thumb-radius: 3px;
|
|
2382
|
+
--select-option-hover-transform: translateX(2px);
|
|
2383
|
+
--select-option-font-weight: 450;
|
|
2384
|
+
--select-option-margin: 2px 0;
|
|
2385
|
+
--select-option-active-outline-offset: -2px;
|
|
2386
|
+
--select-option-selected-active-outline-offset: -2px;
|
|
2387
|
+
--select-option-selected-indicator-width: 3px;
|
|
2388
|
+
--select-option-selected-indicator-height: 60%;
|
|
2389
|
+
--select-option-selected-indicator-bg: var(--select-accent);
|
|
2390
|
+
--select-option-selected-indicator-radius: 0 2px 2px 0;
|
|
2391
|
+
--select-option-selected-indicator-left: 0;
|
|
2392
|
+
--select-option-selected-indicator-top: 50%;
|
|
2393
|
+
--select-option-selected-indicator-transform: translateY(-50%);
|
|
2394
|
+
--select-option-selected-indicator-animation: selectedIndicator 200ms cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
|
|
2395
|
+
--select-option-selected-indicator-from-height: 0;
|
|
2396
|
+
--select-option-selected-indicator-to-height: 60%;
|
|
2397
|
+
--select-option-selected-indicator-from-opacity: 0;
|
|
2398
|
+
--select-option-selected-indicator-to-opacity: 1;
|
|
2399
|
+
--select-option-pressed-transform: translateX(2px) scale(0.99);
|
|
2400
|
+
--select-option-selected-pressed-transform: scale(0.99);
|
|
2401
|
+
--select-button-hover-transform: translateY(-1px);
|
|
2402
|
+
--select-button-active-transform: translateY(0) scale(0.98);
|
|
2403
|
+
--select-button-font-weight: 550;
|
|
2404
|
+
--select-button-letter-spacing: 0.02em;
|
|
2405
|
+
--select-spinner-animation: spin 0.8s cubic-bezier(0.4, 0, 0.2, 1) infinite;
|
|
2406
|
+
--select-searching-spinner-active-color: var(--select-accent);
|
|
2407
|
+
--select-badge-remove-margin-left: 2px;
|
|
2408
|
+
--select-badge-remove-radius: 50%;
|
|
2409
|
+
--select-badge-remove-font-weight: 600;
|
|
2410
|
+
--select-empty-gap: 8px;
|
|
2411
|
+
--select-searching-gap: 8px;
|
|
2412
|
+
--select-searching-spinner-size: 24px;
|
|
2413
|
+
--select-searching-spinner-border: 2px solid var(--select-border);
|
|
2414
|
+
--select-searching-spinner-animation: var(--select-spinner-animation);
|
|
2415
|
+
--select-group-header-separator-margin-top: 8px;
|
|
2416
|
+
--select-group-header-separator-padding-top: 14px;
|
|
2417
|
+
--select-group-header-separator-border-top: 1px solid var(--select-border);
|
|
2418
|
+
--select-reduced-motion-duration: 0.01ms;
|
|
2419
|
+
--select-reduced-motion-iteration-count: 1;
|
|
2420
|
+
--select-high-contrast-border-width: 2px;
|
|
2421
|
+
--select-high-contrast-indicator-width: 4px;
|
|
2422
|
+
--select-high-contrast-focus-outline-width: 3px;
|
|
2423
|
+
--select-high-contrast-focus-outline-color: Highlight;
|
|
2424
|
+
--select-touch-target-min-height: 44px;
|
|
2425
|
+
--select-badge-dark-bg: linear-gradient(135deg, var(--select-accent) 0%, #4f46e5 100%);
|
|
2426
|
+
|
|
2205
2427
|
display: block;
|
|
2206
2428
|
position: relative;
|
|
2207
2429
|
width: var(--select-width, 100%);
|
|
2208
2430
|
height: var(--select-height, auto);
|
|
2431
|
+
font-family: var(--select-font-family, 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif);
|
|
2432
|
+
}
|
|
2433
|
+
|
|
2434
|
+
/* ─────────────────────────────────────────────────────────────────────────
|
|
2435
|
+
Selection Badges — Refined pill design with elegant interactions
|
|
2436
|
+
───────────────────────────────────────────────────────────────────────── */
|
|
2437
|
+
|
|
2438
|
+
.selection-badge {
|
|
2439
|
+
display: inline-flex;
|
|
2440
|
+
align-items: center;
|
|
2441
|
+
gap: var(--select-badge-gap, 6px);
|
|
2442
|
+
flex: 0 1 auto;
|
|
2443
|
+
min-height: var(--select-badge-min-height, 26px);
|
|
2444
|
+
padding: var(--select-badge-padding, 4px 10px 4px 12px);
|
|
2445
|
+
margin: var(--select-badge-margin, 3px);
|
|
2446
|
+
background: var(--select-badge-bg, linear-gradient(135deg, var(--select-accent) 0%, var(--select-primary-light) 100%));
|
|
2447
|
+
color: var(--select-badge-color, #ffffff);
|
|
2448
|
+
border: var(--select-badge-border, none);
|
|
2449
|
+
border-radius: var(--select-badge-border-radius, 999px);
|
|
2450
|
+
box-shadow: var(--select-badge-shadow, var(--select-shadow-sm), inset 0 1px 0 rgba(255, 255, 255, 0.1));
|
|
2451
|
+
box-sizing: border-box;
|
|
2452
|
+
font-size: var(--select-badge-font-size, 13px);
|
|
2453
|
+
font-weight: var(--select-badge-font-weight, 500);
|
|
2454
|
+
line-height: var(--select-badge-line-height, 1.2);
|
|
2455
|
+
letter-spacing: var(--select-badge-letter-spacing);
|
|
2456
|
+
max-width: var(--select-badge-max-width, 100%);
|
|
2457
|
+
overflow: hidden;
|
|
2458
|
+
transform: scale(1);
|
|
2459
|
+
transition:
|
|
2460
|
+
transform var(--select-transition-bounce),
|
|
2461
|
+
box-shadow var(--select-transition-fast),
|
|
2462
|
+
background var(--select-transition-fast);
|
|
2463
|
+
animation: var(--select-badge-animation);
|
|
2209
2464
|
}
|
|
2210
2465
|
|
|
2466
|
+
@keyframes badgeEnter {
|
|
2467
|
+
0% {
|
|
2468
|
+
opacity: var(--select-badge-enter-from-opacity);
|
|
2469
|
+
transform: var(--select-badge-enter-from-transform);
|
|
2470
|
+
}
|
|
2471
|
+
100% {
|
|
2472
|
+
opacity: var(--select-badge-enter-to-opacity);
|
|
2473
|
+
transform: var(--select-badge-enter-to-transform);
|
|
2474
|
+
}
|
|
2475
|
+
}
|
|
2476
|
+
|
|
2477
|
+
.selection-badge:hover {
|
|
2478
|
+
box-shadow: var(--select-badge-hover-shadow);
|
|
2479
|
+
transform: var(--select-badge-hover-transform);
|
|
2480
|
+
}
|
|
2481
|
+
|
|
2482
|
+
.selection-badge-label {
|
|
2483
|
+
display: block;
|
|
2484
|
+
min-width: 0;
|
|
2485
|
+
overflow: hidden;
|
|
2486
|
+
text-overflow: ellipsis;
|
|
2487
|
+
white-space: nowrap;
|
|
2488
|
+
line-height: var(--select-badge-line-height, 1.2);
|
|
2489
|
+
}
|
|
2490
|
+
|
|
2491
|
+
.badge-remove {
|
|
2492
|
+
display: inline-flex;
|
|
2493
|
+
align-items: center;
|
|
2494
|
+
justify-content: center;
|
|
2495
|
+
width: var(--select-badge-remove-size, 18px);
|
|
2496
|
+
height: var(--select-badge-remove-size, 18px);
|
|
2497
|
+
padding: 0;
|
|
2498
|
+
margin-left: var(--select-badge-remove-margin-left);
|
|
2499
|
+
background: var(--select-badge-remove-bg, rgba(255, 255, 255, 0.2));
|
|
2500
|
+
border: var(--select-badge-remove-border, none);
|
|
2501
|
+
border-radius: var(--select-badge-remove-radius);
|
|
2502
|
+
color: var(--select-badge-remove-color, #ffffff);
|
|
2503
|
+
font-size: var(--select-badge-remove-font-size, 11px);
|
|
2504
|
+
font-weight: var(--select-badge-remove-font-weight);
|
|
2505
|
+
line-height: 1;
|
|
2506
|
+
cursor: pointer;
|
|
2507
|
+
flex: 0 0 auto;
|
|
2508
|
+
transition:
|
|
2509
|
+
background var(--select-transition-fast),
|
|
2510
|
+
transform var(--select-transition-bounce);
|
|
2511
|
+
}
|
|
2512
|
+
|
|
2513
|
+
.badge-remove:hover {
|
|
2514
|
+
background: var(--select-badge-remove-hover-bg, rgba(233, 69, 96, 0.9));
|
|
2515
|
+
transform: var(--select-badge-remove-hover-transform);
|
|
2516
|
+
}
|
|
2517
|
+
|
|
2518
|
+
.badge-remove:focus-visible {
|
|
2519
|
+
outline: var(--select-badge-remove-focus-outline);
|
|
2520
|
+
outline-offset: var(--select-badge-remove-focus-offset);
|
|
2521
|
+
}
|
|
2522
|
+
|
|
2523
|
+
.badge-remove:active {
|
|
2524
|
+
transform: var(--select-badge-remove-active-transform);
|
|
2525
|
+
}
|
|
2526
|
+
|
|
2527
|
+
/* ─────────────────────────────────────────────────────────────────────────
|
|
2528
|
+
Input Container — Sophisticated control shell
|
|
2529
|
+
───────────��───────────────────────────────────────────────────────────── */
|
|
2530
|
+
|
|
2211
2531
|
.select-container {
|
|
2212
2532
|
position: relative;
|
|
2213
2533
|
width: 100%;
|
|
@@ -2218,102 +2538,143 @@
|
|
|
2218
2538
|
width: 100%;
|
|
2219
2539
|
display: flex;
|
|
2220
2540
|
align-items: center;
|
|
2221
|
-
flex-wrap:
|
|
2541
|
+
flex-wrap: nowrap;
|
|
2222
2542
|
gap: var(--select-input-gap, 6px);
|
|
2223
|
-
padding: var(--select-input-padding,
|
|
2543
|
+
padding: var(--select-input-padding, 10px 52px 10px 14px);
|
|
2224
2544
|
height: var(--select-input-height, auto);
|
|
2225
|
-
min-height: var(--select-input-min-height,
|
|
2545
|
+
min-height: var(--select-input-min-height, 48px);
|
|
2226
2546
|
max-height: var(--select-input-max-height, 160px);
|
|
2227
2547
|
overflow-y: var(--select-input-overflow-y, auto);
|
|
2228
|
-
align-content:
|
|
2229
|
-
background: var(--select-input-bg, var(--select-
|
|
2230
|
-
border: var(--select-input-border,
|
|
2231
|
-
border-radius: var(--select-input-border-radius,
|
|
2548
|
+
align-content: center;
|
|
2549
|
+
background: var(--select-input-bg, var(--select-surface));
|
|
2550
|
+
border: var(--select-input-border, 1.5px solid var(--select-border));
|
|
2551
|
+
border-radius: var(--select-input-border-radius, var(--select-radius-md));
|
|
2552
|
+
box-shadow: var(--select-shadow-sm);
|
|
2232
2553
|
box-sizing: border-box;
|
|
2233
|
-
transition:
|
|
2554
|
+
transition:
|
|
2555
|
+
border-color var(--select-transition-fast),
|
|
2556
|
+
box-shadow var(--select-transition-smooth),
|
|
2557
|
+
transform var(--select-transition-fast);
|
|
2558
|
+
}
|
|
2559
|
+
|
|
2560
|
+
.input-container:hover {
|
|
2561
|
+
border-color: var(--select-input-hover-border);
|
|
2562
|
+
box-shadow: var(--select-input-hover-shadow);
|
|
2563
|
+
}
|
|
2564
|
+
|
|
2565
|
+
.input-container.input-container--single {
|
|
2566
|
+
flex-wrap: nowrap;
|
|
2567
|
+
align-content: center;
|
|
2568
|
+
}
|
|
2569
|
+
|
|
2570
|
+
.input-container.input-container--multi {
|
|
2571
|
+
flex-wrap: wrap;
|
|
2572
|
+
align-content: flex-start;
|
|
2234
2573
|
}
|
|
2235
2574
|
|
|
2236
2575
|
.input-container:focus-within {
|
|
2237
|
-
border-color: var(--select-input-focus-border, var(--select-border-focus
|
|
2238
|
-
box-shadow: var(--select-
|
|
2576
|
+
border-color: var(--select-input-focus-border, var(--select-border-focus));
|
|
2577
|
+
box-shadow: var(--select-shadow-focus), var(--select-shadow-sm);
|
|
2239
2578
|
}
|
|
2240
2579
|
|
|
2241
|
-
/*
|
|
2580
|
+
/* Elegant separator line before arrow */
|
|
2242
2581
|
.input-container::after {
|
|
2243
2582
|
content: '';
|
|
2244
2583
|
position: absolute;
|
|
2245
2584
|
top: 50%;
|
|
2246
|
-
right: var(--select-separator-position,
|
|
2585
|
+
right: var(--select-separator-position, 42px);
|
|
2247
2586
|
transform: translateY(-50%);
|
|
2248
|
-
width: var(--select-separator-width,
|
|
2249
|
-
height: var(--select-separator-height,
|
|
2250
|
-
background: var(--select-separator-bg,
|
|
2587
|
+
width: var(--select-separator-width, 1px);
|
|
2588
|
+
height: var(--select-separator-height, 50%);
|
|
2589
|
+
background: var(--select-separator-bg, linear-gradient(
|
|
2251
2590
|
to bottom,
|
|
2252
2591
|
transparent 0%,
|
|
2253
|
-
|
|
2254
|
-
|
|
2592
|
+
var(--select-border) 20%,
|
|
2593
|
+
var(--select-border) 80%,
|
|
2255
2594
|
transparent 100%
|
|
2256
|
-
))
|
|
2595
|
+
));
|
|
2257
2596
|
pointer-events: none;
|
|
2258
2597
|
z-index: 1;
|
|
2598
|
+
opacity: var(--select-separator-opacity);
|
|
2599
|
+
transition: opacity var(--select-transition-fast);
|
|
2259
2600
|
}
|
|
2260
2601
|
|
|
2602
|
+
.input-container:hover::after,
|
|
2603
|
+
.input-container:focus-within::after {
|
|
2604
|
+
opacity: var(--select-separator-active-opacity);
|
|
2605
|
+
}
|
|
2606
|
+
|
|
2607
|
+
/* ─────────────────────────────────────────────────────────────────────────
|
|
2608
|
+
Dropdown Arrow — Smooth rotation with refined styling
|
|
2609
|
+
───────────────────────────────────────────────────────────────────────── */
|
|
2610
|
+
|
|
2261
2611
|
.dropdown-arrow-container {
|
|
2262
2612
|
position: absolute;
|
|
2263
2613
|
top: 0;
|
|
2264
2614
|
right: 0;
|
|
2265
2615
|
bottom: 0;
|
|
2266
|
-
width: var(--select-arrow-width,
|
|
2267
|
-
/* allow explicit height override even though container normally stretches */
|
|
2616
|
+
width: var(--select-arrow-width, 42px);
|
|
2268
2617
|
height: var(--select-arrow-height, auto);
|
|
2269
2618
|
display: flex;
|
|
2270
2619
|
align-items: center;
|
|
2271
2620
|
justify-content: center;
|
|
2272
2621
|
cursor: pointer;
|
|
2273
|
-
|
|
2274
|
-
border-radius: var(--select-arrow-border-radius, 0 4px 4px 0);
|
|
2622
|
+
border-radius: var(--select-arrow-border-radius, 0 var(--select-radius-md) var(--select-radius-md) 0);
|
|
2275
2623
|
z-index: 2;
|
|
2624
|
+
transition: background-color var(--select-transition-fast);
|
|
2276
2625
|
}
|
|
2277
2626
|
|
|
2278
2627
|
.input-container.has-clear-control {
|
|
2279
|
-
padding: var(--select-input-padding-with-clear,
|
|
2628
|
+
padding: var(--select-input-padding-with-clear, 10px 84px 10px 14px);
|
|
2280
2629
|
}
|
|
2281
2630
|
|
|
2282
2631
|
.input-container.has-clear-control::after {
|
|
2283
|
-
right: var(--select-separator-position-with-clear,
|
|
2632
|
+
right: var(--select-separator-position-with-clear, 74px);
|
|
2284
2633
|
}
|
|
2285
2634
|
|
|
2286
2635
|
.dropdown-arrow-container.with-clear-control {
|
|
2287
|
-
right: var(--select-arrow-right-with-clear,
|
|
2636
|
+
right: var(--select-arrow-right-with-clear, 34px);
|
|
2288
2637
|
}
|
|
2289
2638
|
|
|
2639
|
+
/* ─────────────────────────────────────────────────────────────────────────
|
|
2640
|
+
Clear Control — Minimal and elegant dismiss button
|
|
2641
|
+
───────────────────────────────────────────────────────────────────────── */
|
|
2642
|
+
|
|
2290
2643
|
.clear-control-button {
|
|
2291
2644
|
position: absolute;
|
|
2292
2645
|
top: 50%;
|
|
2293
|
-
right: var(--select-clear-button-right,
|
|
2646
|
+
right: var(--select-clear-button-right, 8px);
|
|
2294
2647
|
transform: translateY(-50%);
|
|
2295
|
-
width: var(--select-clear-button-size,
|
|
2296
|
-
height: var(--select-clear-button-size,
|
|
2648
|
+
width: var(--select-clear-button-size, 26px);
|
|
2649
|
+
height: var(--select-clear-button-size, 26px);
|
|
2297
2650
|
border: var(--select-clear-button-border, none);
|
|
2298
|
-
border-radius: var(--select-clear-button-radius,
|
|
2651
|
+
border-radius: var(--select-clear-button-radius, 50%);
|
|
2299
2652
|
background: var(--select-clear-button-bg, transparent);
|
|
2300
|
-
color: var(--select-clear-button-color,
|
|
2653
|
+
color: var(--select-clear-button-color, var(--select-text-muted));
|
|
2301
2654
|
display: inline-flex;
|
|
2302
2655
|
align-items: center;
|
|
2303
2656
|
justify-content: center;
|
|
2304
2657
|
cursor: pointer;
|
|
2305
2658
|
z-index: 3;
|
|
2306
|
-
transition:
|
|
2659
|
+
transition:
|
|
2660
|
+
background var(--select-transition-fast),
|
|
2661
|
+
color var(--select-transition-fast),
|
|
2662
|
+
transform var(--select-transition-bounce);
|
|
2307
2663
|
}
|
|
2308
2664
|
|
|
2309
2665
|
.clear-control-button:hover {
|
|
2310
|
-
background: var(--select-clear-button-hover-bg, rgba(
|
|
2311
|
-
color: var(--select-clear-button-hover-color,
|
|
2666
|
+
background: var(--select-clear-button-hover-bg, rgba(233, 69, 96, 0.1));
|
|
2667
|
+
color: var(--select-clear-button-hover-color, var(--select-accent-hover));
|
|
2668
|
+
transform: var(--select-clear-button-hover-transform);
|
|
2669
|
+
}
|
|
2670
|
+
|
|
2671
|
+
.clear-control-button:active {
|
|
2672
|
+
transform: var(--select-clear-button-active-transform);
|
|
2312
2673
|
}
|
|
2313
2674
|
|
|
2314
2675
|
.clear-control-button:focus-visible {
|
|
2315
|
-
outline: var(--select-clear-button-focus-outline, 2px solid
|
|
2316
|
-
outline-offset:
|
|
2676
|
+
outline: var(--select-clear-button-focus-outline, 2px solid var(--select-border-focus));
|
|
2677
|
+
outline-offset: var(--select-clear-button-focus-offset);
|
|
2317
2678
|
}
|
|
2318
2679
|
|
|
2319
2680
|
.clear-control-button[hidden] {
|
|
@@ -2321,260 +2682,332 @@
|
|
|
2321
2682
|
}
|
|
2322
2683
|
|
|
2323
2684
|
.clear-control-icon {
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
font-weight: var(--select-clear-icon-weight, 500);
|
|
2685
|
+
width: var(--select-clear-icon-size);
|
|
2686
|
+
height: var(--select-clear-icon-size);
|
|
2327
2687
|
pointer-events: none;
|
|
2328
2688
|
}
|
|
2329
2689
|
|
|
2330
|
-
.
|
|
2331
|
-
|
|
2690
|
+
.clear-control-icon svg {
|
|
2691
|
+
width: 100%;
|
|
2692
|
+
height: 100%;
|
|
2332
2693
|
}
|
|
2333
2694
|
|
|
2334
|
-
.dropdown-arrow:hover {
|
|
2335
|
-
|
|
2336
|
-
color: var(--select-arrow-hover, var(--select-arrow-hover-color, #667eea));
|
|
2695
|
+
.dropdown-arrow-container:hover {
|
|
2696
|
+
background-color: var(--select-arrow-hover-bg, rgba(15, 52, 96, 0.05));
|
|
2337
2697
|
}
|
|
2338
2698
|
|
|
2339
2699
|
.dropdown-arrow {
|
|
2340
|
-
width: var(--select-arrow-
|
|
2341
|
-
height: var(--select-arrow-
|
|
2342
|
-
color: var(--select-arrow-color,
|
|
2343
|
-
transition:
|
|
2344
|
-
|
|
2700
|
+
width: var(--select-arrow-size, 18px);
|
|
2701
|
+
height: var(--select-arrow-size, 18px);
|
|
2702
|
+
color: var(--select-arrow-color, var(--select-text-muted));
|
|
2703
|
+
transition:
|
|
2704
|
+
transform var(--select-transition-smooth),
|
|
2705
|
+
color var(--select-transition-fast);
|
|
2706
|
+
transform-origin: center;
|
|
2345
2707
|
}
|
|
2346
2708
|
|
|
2347
2709
|
.dropdown-arrow path {
|
|
2348
|
-
stroke-width: var(--select-arrow-stroke-width,
|
|
2710
|
+
stroke-width: var(--select-arrow-stroke-width, 1.5);
|
|
2349
2711
|
}
|
|
2350
2712
|
|
|
2351
2713
|
.dropdown-arrow-container:hover .dropdown-arrow {
|
|
2352
|
-
color: var(--select-arrow-hover-color,
|
|
2714
|
+
color: var(--select-arrow-hover-color, var(--select-accent));
|
|
2353
2715
|
}
|
|
2354
2716
|
|
|
2355
2717
|
.dropdown-arrow.open {
|
|
2356
|
-
transform:
|
|
2718
|
+
transform: var(--select-arrow-open-transform);
|
|
2357
2719
|
}
|
|
2358
2720
|
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2721
|
+
/* ─────────────────────────────────────────────────────────────────────────
|
|
2722
|
+
Input Field — Clean text entry
|
|
2723
|
+
───────────────────────────────────────────────────────────────────────── */
|
|
2724
|
+
|
|
2725
|
+
.input-container > .select-input,
|
|
2726
|
+
input.select-input,
|
|
2727
|
+
.select-input[type="text"] {
|
|
2728
|
+
display: block;
|
|
2729
|
+
flex: 1 1 auto;
|
|
2730
|
+
width: var(--select-input-width, 100%);
|
|
2731
|
+
max-width: 100%;
|
|
2732
|
+
min-width: var(--select-input-min-width, 0);
|
|
2733
|
+
min-inline-size: 0;
|
|
2734
|
+
min-height: 0;
|
|
2735
|
+
padding: var(--select-input-field-padding, 0) !important;
|
|
2736
|
+
margin: 0 !important;
|
|
2737
|
+
border: 0 !important;
|
|
2738
|
+
font-size: var(--select-input-font-size, 15px);
|
|
2366
2739
|
line-height: var(--select-input-line-height, 1.5);
|
|
2367
|
-
color: var(--select-input-color, var(--select-text
|
|
2368
|
-
background: transparent;
|
|
2740
|
+
color: var(--select-input-color, var(--select-text));
|
|
2741
|
+
background: transparent !important;
|
|
2369
2742
|
box-sizing: border-box;
|
|
2370
|
-
outline: none;
|
|
2371
|
-
font-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
.selection-badge {
|
|
2379
|
-
display: inline-flex;
|
|
2380
|
-
align-items: center;
|
|
2381
|
-
gap: var(--select-badge-gap, 4px);
|
|
2382
|
-
padding: var(--select-badge-padding, 4px 8px);
|
|
2383
|
-
margin: var(--select-badge-margin, 2px);
|
|
2384
|
-
background: var(--select-badge-bg, #667eea);
|
|
2385
|
-
color: var(--select-badge-color, white);
|
|
2386
|
-
border-radius: var(--select-badge-border-radius, 4px);
|
|
2387
|
-
font-size: var(--select-badge-font-size, 13px);
|
|
2388
|
-
line-height: 1;
|
|
2389
|
-
max-width: var(--select-badge-max-width, 100%);
|
|
2390
|
-
white-space: nowrap;
|
|
2743
|
+
outline: none !important;
|
|
2744
|
+
font-weight: var(--select-input-font-weight);
|
|
2745
|
+
letter-spacing: var(--select-input-letter-spacing);
|
|
2746
|
+
align-self: center;
|
|
2747
|
+
appearance: none !important;
|
|
2748
|
+
-webkit-appearance: none !important;
|
|
2749
|
+
box-shadow: none !important;
|
|
2750
|
+
border-radius: 0 !important;
|
|
2391
2751
|
overflow: hidden;
|
|
2392
2752
|
text-overflow: ellipsis;
|
|
2753
|
+
white-space: nowrap;
|
|
2393
2754
|
}
|
|
2394
2755
|
|
|
2395
|
-
.
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
justify-content: center;
|
|
2399
|
-
width: var(--select-badge-remove-size, 16px);
|
|
2400
|
-
height: var(--select-badge-remove-size, 16px);
|
|
2401
|
-
padding: 0;
|
|
2402
|
-
margin-left: 4px;
|
|
2403
|
-
background: var(--select-badge-remove-bg, rgba(255, 255, 255, 0.3));
|
|
2404
|
-
border: none;
|
|
2405
|
-
border-radius: 50%;
|
|
2406
|
-
color: var(--select-badge-remove-color, white);
|
|
2407
|
-
font-size: var(--select-badge-remove-font-size, 16px);
|
|
2408
|
-
line-height: 1;
|
|
2409
|
-
cursor: pointer;
|
|
2410
|
-
transition: background 0.2s;
|
|
2756
|
+
.select-input::placeholder {
|
|
2757
|
+
color: var(--select-input-placeholder-color, var(--select-text-placeholder));
|
|
2758
|
+
font-weight: 400;
|
|
2411
2759
|
}
|
|
2412
|
-
|
|
2413
|
-
.
|
|
2414
|
-
|
|
2760
|
+
|
|
2761
|
+
.input-container.input-container--multi > .select-input,
|
|
2762
|
+
.input-container.input-container--multi > input.select-input,
|
|
2763
|
+
.input-container.input-container--multi > .select-input[type="text"] {
|
|
2764
|
+
width: auto;
|
|
2765
|
+
min-width: var(--select-multi-input-min-width, 96px);
|
|
2766
|
+
flex: 1 0 var(--select-multi-input-min-width, 96px);
|
|
2415
2767
|
}
|
|
2416
2768
|
|
|
2417
|
-
.
|
|
2418
|
-
|
|
2419
|
-
|
|
2769
|
+
.input-container.input-container--single > .select-input,
|
|
2770
|
+
.input-container.input-container--single > input.select-input,
|
|
2771
|
+
.input-container.input-container--single > .select-input[type="text"] {
|
|
2772
|
+
width: var(--select-input-width, 100%);
|
|
2773
|
+
min-width: 0;
|
|
2774
|
+
flex: 1 1 auto;
|
|
2420
2775
|
}
|
|
2421
2776
|
|
|
2422
2777
|
.select-input:disabled {
|
|
2423
2778
|
background-color: var(--select-disabled-bg, #f5f5f5);
|
|
2424
2779
|
cursor: not-allowed;
|
|
2780
|
+
opacity: var(--select-input-disabled-opacity);
|
|
2425
2781
|
}
|
|
2426
2782
|
|
|
2783
|
+
/* ─────────────────────────────────────────────────────────────────────────
|
|
2784
|
+
Dropdown Panel — Elegant floating container
|
|
2785
|
+
───────────────────────────────────────────────────────────────────────── */
|
|
2786
|
+
|
|
2427
2787
|
.select-dropdown {
|
|
2428
2788
|
position: absolute;
|
|
2429
|
-
scroll-behavior:
|
|
2430
|
-
top:
|
|
2789
|
+
scroll-behavior: var(--select-dropdown-scroll-behavior);
|
|
2790
|
+
top: var(--select-dropdown-top);
|
|
2431
2791
|
left: 0;
|
|
2432
2792
|
right: 0;
|
|
2433
|
-
|
|
2434
|
-
max-height: var(--select-dropdown-max-height, 300px);
|
|
2793
|
+
max-height: var(--select-dropdown-max-height, 320px);
|
|
2435
2794
|
overflow: hidden;
|
|
2436
|
-
background: var(--select-dropdown-bg, var(--select-
|
|
2437
|
-
border: 1px solid var(--select-dropdown-border,
|
|
2438
|
-
border-radius: var(--select-dropdown-border-radius,
|
|
2439
|
-
box-shadow: var(--select-dropdown-shadow,
|
|
2795
|
+
background: var(--select-dropdown-bg, var(--select-surface));
|
|
2796
|
+
border: 1px solid var(--select-dropdown-border, var(--select-border));
|
|
2797
|
+
border-radius: var(--select-dropdown-border-radius, var(--select-radius-lg));
|
|
2798
|
+
box-shadow: var(--select-dropdown-shadow, var(--select-shadow-lg));
|
|
2440
2799
|
z-index: var(--select-dropdown-z-index, 1000);
|
|
2800
|
+
transform-origin: var(--select-dropdown-transform-origin);
|
|
2801
|
+
animation: var(--select-dropdown-animation);
|
|
2802
|
+
}
|
|
2803
|
+
|
|
2804
|
+
@keyframes dropdownEnter {
|
|
2805
|
+
0% {
|
|
2806
|
+
opacity: var(--select-dropdown-enter-from-opacity);
|
|
2807
|
+
transform: var(--select-dropdown-enter-from-transform);
|
|
2808
|
+
}
|
|
2809
|
+
100% {
|
|
2810
|
+
opacity: var(--select-dropdown-enter-to-opacity);
|
|
2811
|
+
transform: var(--select-dropdown-enter-to-transform);
|
|
2812
|
+
}
|
|
2441
2813
|
}
|
|
2442
2814
|
|
|
2443
2815
|
.options-container {
|
|
2444
2816
|
position: relative;
|
|
2445
|
-
max-height: var(--select-options-max-height,
|
|
2817
|
+
max-height: var(--select-options-max-height, 320px);
|
|
2446
2818
|
overflow: auto;
|
|
2447
|
-
|
|
2448
|
-
background: var(--select-options-bg, var(--select-
|
|
2819
|
+
padding: var(--select-options-padding, 6px);
|
|
2820
|
+
background: var(--select-options-bg, var(--select-surface));
|
|
2821
|
+
|
|
2822
|
+
/* Custom scrollbar styling */
|
|
2823
|
+
scrollbar-width: thin;
|
|
2824
|
+
scrollbar-color: var(--select-border) transparent;
|
|
2825
|
+
}
|
|
2826
|
+
|
|
2827
|
+
.options-container::-webkit-scrollbar {
|
|
2828
|
+
width: var(--select-scrollbar-width);
|
|
2449
2829
|
}
|
|
2830
|
+
|
|
2831
|
+
.options-container::-webkit-scrollbar-track {
|
|
2832
|
+
background: transparent;
|
|
2833
|
+
}
|
|
2834
|
+
|
|
2835
|
+
.options-container::-webkit-scrollbar-thumb {
|
|
2836
|
+
background: var(--select-border);
|
|
2837
|
+
border-radius: var(--select-scrollbar-thumb-radius);
|
|
2838
|
+
}
|
|
2839
|
+
|
|
2840
|
+
.options-container::-webkit-scrollbar-thumb:hover {
|
|
2841
|
+
background: var(--select-text-muted);
|
|
2842
|
+
}
|
|
2843
|
+
|
|
2844
|
+
/* ─────────────────────────────────────────────────────────────────────────
|
|
2845
|
+
Group Headers — Refined section dividers
|
|
2846
|
+
───────────────────────────────────────────────────────────────────────── */
|
|
2450
2847
|
|
|
2451
2848
|
.group-header {
|
|
2452
|
-
padding: var(--select-group-header-padding,
|
|
2849
|
+
padding: var(--select-group-header-padding, 10px 12px 6px);
|
|
2453
2850
|
font-weight: var(--select-group-header-weight, 600);
|
|
2454
|
-
color: var(--select-group-header-color,
|
|
2455
|
-
background-color: var(--select-group-header-bg,
|
|
2851
|
+
color: var(--select-group-header-color, var(--select-text-muted));
|
|
2852
|
+
background-color: var(--select-group-header-bg, var(--select-surface));
|
|
2456
2853
|
text-align: var(--select-group-header-text-align, left);
|
|
2457
|
-
font-size: var(--select-group-header-font-size,
|
|
2854
|
+
font-size: var(--select-group-header-font-size, 11px);
|
|
2458
2855
|
text-transform: var(--select-group-header-text-transform, uppercase);
|
|
2459
|
-
letter-spacing: var(--select-group-header-letter-spacing, 0.
|
|
2856
|
+
letter-spacing: var(--select-group-header-letter-spacing, 0.08em);
|
|
2460
2857
|
position: sticky;
|
|
2461
2858
|
top: 0;
|
|
2462
2859
|
z-index: 1;
|
|
2463
|
-
border-bottom: var(--select-group-header-border-bottom,
|
|
2860
|
+
border-bottom: var(--select-group-header-border-bottom, none);
|
|
2861
|
+
}
|
|
2862
|
+
|
|
2863
|
+
.group-header:not(:first-child) {
|
|
2864
|
+
margin-top: var(--select-group-header-separator-margin-top);
|
|
2865
|
+
padding-top: var(--select-group-header-separator-padding-top);
|
|
2866
|
+
border-top: var(--select-group-header-separator-border-top);
|
|
2464
2867
|
}
|
|
2465
2868
|
|
|
2869
|
+
/* ─────────────────────────────────────────────────────────────────────────
|
|
2870
|
+
Options — Elegant hover and selection states
|
|
2871
|
+
───────────────────────────────────────────────────────────────────────── */
|
|
2872
|
+
|
|
2466
2873
|
.option {
|
|
2467
|
-
|
|
2874
|
+
position: relative;
|
|
2875
|
+
padding: var(--select-option-padding, 10px 14px);
|
|
2468
2876
|
cursor: pointer;
|
|
2469
|
-
color: var(--select-option-color, var(--select-text
|
|
2470
|
-
background: var(--select-option-bg,
|
|
2471
|
-
transition:
|
|
2877
|
+
color: var(--select-option-color, var(--select-text));
|
|
2878
|
+
background: var(--select-option-bg, transparent);
|
|
2879
|
+
transition:
|
|
2880
|
+
background var(--select-transition-fast),
|
|
2881
|
+
color var(--select-transition-fast),
|
|
2882
|
+
transform var(--select-transition-fast),
|
|
2883
|
+
box-shadow var(--select-transition-fast);
|
|
2472
2884
|
user-select: none;
|
|
2473
2885
|
font-size: var(--select-option-font-size, 14px);
|
|
2886
|
+
font-weight: var(--select-option-font-weight);
|
|
2474
2887
|
line-height: var(--select-option-line-height, 1.5);
|
|
2475
|
-
border: var(--select-option-border,
|
|
2476
|
-
|
|
2477
|
-
border-radius: var(--select-option-border-radius, 0);
|
|
2478
|
-
box-shadow: var(--select-option-shadow, none);
|
|
2479
|
-
transform: var(--select-option-transform, none);
|
|
2888
|
+
border-radius: var(--select-option-border-radius, var(--select-radius-sm));
|
|
2889
|
+
margin: var(--select-option-margin);
|
|
2480
2890
|
}
|
|
2481
2891
|
|
|
2482
2892
|
.option:hover {
|
|
2483
|
-
background: var(--select-option-hover-bg,
|
|
2484
|
-
color: var(--select-option-hover-color,
|
|
2893
|
+
background: var(--select-option-hover-bg, var(--select-surface-elevated));
|
|
2894
|
+
color: var(--select-option-hover-color, var(--select-text));
|
|
2895
|
+
transform: var(--select-option-hover-transform);
|
|
2485
2896
|
}
|
|
2486
2897
|
|
|
2487
2898
|
.option.selected {
|
|
2488
|
-
background: var(--select-option-selected-bg,
|
|
2489
|
-
color: var(--select-option-selected-color,
|
|
2490
|
-
font-weight: var(--select-option-selected-weight,
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2899
|
+
background: var(--select-option-selected-bg, linear-gradient(135deg, rgba(15, 52, 96, 0.08) 0%, rgba(15, 52, 96, 0.04) 100%));
|
|
2900
|
+
color: var(--select-option-selected-color, var(--select-accent));
|
|
2901
|
+
font-weight: var(--select-option-selected-weight, 550);
|
|
2902
|
+
}
|
|
2903
|
+
|
|
2904
|
+
.option.selected::before {
|
|
2905
|
+
content: '';
|
|
2906
|
+
position: absolute;
|
|
2907
|
+
left: var(--select-option-selected-indicator-left);
|
|
2908
|
+
top: var(--select-option-selected-indicator-top);
|
|
2909
|
+
transform: var(--select-option-selected-indicator-transform);
|
|
2910
|
+
width: var(--select-option-selected-indicator-width);
|
|
2911
|
+
height: var(--select-option-selected-indicator-height);
|
|
2912
|
+
background: var(--select-option-selected-indicator-bg);
|
|
2913
|
+
border-radius: var(--select-option-selected-indicator-radius);
|
|
2914
|
+
animation: var(--select-option-selected-indicator-animation);
|
|
2915
|
+
}
|
|
2916
|
+
|
|
2917
|
+
@keyframes selectedIndicator {
|
|
2918
|
+
0% {
|
|
2919
|
+
height: var(--select-option-selected-indicator-from-height);
|
|
2920
|
+
opacity: var(--select-option-selected-indicator-from-opacity);
|
|
2921
|
+
}
|
|
2922
|
+
100% {
|
|
2923
|
+
height: var(--select-option-selected-indicator-to-height);
|
|
2924
|
+
opacity: var(--select-option-selected-indicator-to-opacity);
|
|
2925
|
+
}
|
|
2496
2926
|
}
|
|
2497
2927
|
|
|
2498
2928
|
.option.selected:hover {
|
|
2499
|
-
background: var(--select-option-selected-hover-bg,
|
|
2500
|
-
color: var(--select-option-selected-hover-color, var(--select-option-selected-color, #4338ca));
|
|
2501
|
-
border: var(--select-option-selected-hover-border, var(--select-option-selected-border, var(--select-option-border, none)));
|
|
2502
|
-
border-bottom: var(--select-option-selected-hover-border-bottom, var(--select-option-selected-border-bottom, var(--select-option-border-bottom, none)));
|
|
2503
|
-
box-shadow: var(--select-option-selected-hover-shadow, var(--select-option-selected-shadow, var(--select-option-shadow, none)));
|
|
2504
|
-
transform: var(--select-option-selected-hover-transform, var(--select-option-selected-transform, var(--select-option-transform, none)));
|
|
2929
|
+
background: var(--select-option-selected-hover-bg, linear-gradient(135deg, rgba(15, 52, 96, 0.12) 0%, rgba(15, 52, 96, 0.06) 100%));
|
|
2505
2930
|
}
|
|
2506
2931
|
|
|
2507
2932
|
.option.active:not(.selected) {
|
|
2508
|
-
background: var(--select-option-active-bg,
|
|
2509
|
-
|
|
2510
|
-
outline: var(--select-option-active-outline
|
|
2511
|
-
outline-offset: -2px;
|
|
2933
|
+
background: var(--select-option-active-bg, var(--select-surface-elevated));
|
|
2934
|
+
outline: var(--select-option-active-outline, 2px solid rgba(15, 52, 96, 0.3));
|
|
2935
|
+
outline-offset: var(--select-option-active-outline-offset);
|
|
2512
2936
|
}
|
|
2513
2937
|
|
|
2514
2938
|
.option.selected.active {
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
border: var(--select-option-selected-active-border, var(--select-option-selected-border, var(--select-option-border, none)));
|
|
2518
|
-
border-bottom: var(--select-option-selected-active-border-bottom, var(--select-option-selected-border-bottom, var(--select-option-border-bottom, none)));
|
|
2519
|
-
box-shadow: var(--select-option-selected-active-shadow, var(--select-option-selected-shadow, var(--select-option-shadow, none)));
|
|
2520
|
-
transform: var(--select-option-selected-active-transform, var(--select-option-selected-transform, var(--select-option-transform, none)));
|
|
2521
|
-
outline: var(--select-option-selected-active-outline, var(--select-option-active-outline, 2px solid rgba(99, 102, 241, 0.45)));
|
|
2522
|
-
outline-offset: -2px;
|
|
2939
|
+
outline: var(--select-option-selected-active-outline, 2px solid rgba(15, 52, 96, 0.4));
|
|
2940
|
+
outline-offset: var(--select-option-selected-active-outline-offset);
|
|
2523
2941
|
}
|
|
2524
2942
|
|
|
2525
2943
|
.option:active:not(.selected) {
|
|
2526
|
-
background: var(--select-option-pressed-bg,
|
|
2944
|
+
background: var(--select-option-pressed-bg, rgba(15, 52, 96, 0.08));
|
|
2945
|
+
transform: var(--select-option-pressed-transform);
|
|
2527
2946
|
}
|
|
2528
2947
|
|
|
2529
2948
|
.option.selected:active {
|
|
2530
|
-
|
|
2949
|
+
transform: var(--select-option-selected-pressed-transform);
|
|
2531
2950
|
}
|
|
2532
2951
|
|
|
2952
|
+
/* ─────────────────────────────────────────────────────────────────────────
|
|
2953
|
+
Load More & Busy States — Refined feedback indicators
|
|
2954
|
+
───────────────────────────────────────────────────────────────────────── */
|
|
2955
|
+
|
|
2533
2956
|
.load-more-container {
|
|
2534
2957
|
padding: var(--select-load-more-padding, 12px);
|
|
2535
2958
|
text-align: center;
|
|
2536
|
-
border-top: var(--select-divider-border, 1px solid #e0e0e0);
|
|
2537
|
-
background: var(--select-load-more-bg, white);
|
|
2538
2959
|
}
|
|
2539
2960
|
|
|
2540
2961
|
.load-more-button {
|
|
2541
|
-
padding: var(--select-button-padding,
|
|
2542
|
-
border: var(--select-button-border,
|
|
2543
|
-
background: var(--select-button-bg,
|
|
2544
|
-
color: var(--select-button-color,
|
|
2545
|
-
border-radius: var(--select-button-border-radius,
|
|
2962
|
+
padding: var(--select-button-padding, 10px 20px);
|
|
2963
|
+
border: var(--select-button-border, 1.5px solid var(--select-border));
|
|
2964
|
+
background: var(--select-button-bg, transparent);
|
|
2965
|
+
color: var(--select-button-color, var(--select-accent));
|
|
2966
|
+
border-radius: var(--select-button-border-radius, var(--select-radius-md));
|
|
2546
2967
|
cursor: pointer;
|
|
2547
|
-
font-size: var(--select-button-font-size,
|
|
2548
|
-
font-
|
|
2549
|
-
|
|
2968
|
+
font-size: var(--select-button-font-size, 13px);
|
|
2969
|
+
font-weight: var(--select-button-font-weight);
|
|
2970
|
+
letter-spacing: var(--select-button-letter-spacing);
|
|
2971
|
+
transition:
|
|
2972
|
+
background var(--select-transition-fast),
|
|
2973
|
+
border-color var(--select-transition-fast),
|
|
2974
|
+
color var(--select-transition-fast),
|
|
2975
|
+
transform var(--select-transition-bounce);
|
|
2550
2976
|
}
|
|
2551
2977
|
|
|
2552
2978
|
.load-more-button:hover {
|
|
2553
|
-
background: var(--select-button-hover-bg,
|
|
2979
|
+
background: var(--select-button-hover-bg, var(--select-accent));
|
|
2980
|
+
border-color: var(--select-accent);
|
|
2554
2981
|
color: var(--select-button-hover-color, white);
|
|
2982
|
+
transform: var(--select-button-hover-transform);
|
|
2983
|
+
}
|
|
2984
|
+
|
|
2985
|
+
.load-more-button:active {
|
|
2986
|
+
transform: var(--select-button-active-transform);
|
|
2555
2987
|
}
|
|
2556
2988
|
|
|
2557
2989
|
.load-more-button:disabled {
|
|
2558
2990
|
opacity: var(--select-button-disabled-opacity, 0.5);
|
|
2559
2991
|
cursor: not-allowed;
|
|
2992
|
+
transform: none;
|
|
2560
2993
|
}
|
|
2561
2994
|
|
|
2562
2995
|
.busy-bucket {
|
|
2563
|
-
padding: var(--select-busy-padding,
|
|
2996
|
+
padding: var(--select-busy-padding, 20px);
|
|
2564
2997
|
text-align: center;
|
|
2565
|
-
color: var(--select-busy-color,
|
|
2566
|
-
background: var(--select-busy-bg,
|
|
2567
|
-
font-size: var(--select-busy-font-size,
|
|
2998
|
+
color: var(--select-busy-color, var(--select-text-muted));
|
|
2999
|
+
background: var(--select-busy-bg, transparent);
|
|
3000
|
+
font-size: var(--select-busy-font-size, 13px);
|
|
2568
3001
|
}
|
|
2569
3002
|
|
|
2570
3003
|
.spinner {
|
|
2571
3004
|
display: inline-block;
|
|
2572
|
-
width: var(--select-spinner-size,
|
|
2573
|
-
height: var(--select-spinner-size,
|
|
2574
|
-
border: var(--select-spinner-border, 2px solid
|
|
2575
|
-
border-top-color: var(--select-spinner-active-color,
|
|
3005
|
+
width: var(--select-spinner-size, 22px);
|
|
3006
|
+
height: var(--select-spinner-size, 22px);
|
|
3007
|
+
border: var(--select-spinner-border, 2px solid var(--select-border));
|
|
3008
|
+
border-top-color: var(--select-spinner-active-color, var(--select-accent));
|
|
2576
3009
|
border-radius: 50%;
|
|
2577
|
-
animation:
|
|
3010
|
+
animation: var(--select-spinner-animation);
|
|
2578
3011
|
}
|
|
2579
3012
|
|
|
2580
3013
|
@keyframes spin {
|
|
@@ -2582,61 +3015,97 @@
|
|
|
2582
3015
|
}
|
|
2583
3016
|
|
|
2584
3017
|
.empty-state {
|
|
2585
|
-
padding: var(--select-empty-padding, 24px);
|
|
3018
|
+
padding: var(--select-empty-padding, 32px 24px);
|
|
2586
3019
|
text-align: center;
|
|
2587
|
-
color: var(--select-empty-color,
|
|
3020
|
+
color: var(--select-empty-color, var(--select-text-muted));
|
|
2588
3021
|
font-size: var(--select-empty-font-size, 14px);
|
|
2589
|
-
background: var(--select-empty-bg,
|
|
3022
|
+
background: var(--select-empty-bg, transparent);
|
|
2590
3023
|
display: flex;
|
|
2591
3024
|
flex-direction: column;
|
|
2592
3025
|
align-items: center;
|
|
2593
3026
|
justify-content: center;
|
|
2594
|
-
gap:
|
|
2595
|
-
min-height: var(--select-empty-min-height, 72px);
|
|
3027
|
+
gap: var(--select-empty-gap);
|
|
2596
3028
|
}
|
|
2597
3029
|
|
|
2598
3030
|
.searching-state {
|
|
2599
|
-
padding: var(--select-searching-padding, 24px);
|
|
3031
|
+
padding: var(--select-searching-padding, 32px 24px);
|
|
2600
3032
|
text-align: center;
|
|
2601
|
-
color: var(--select-searching-color,
|
|
3033
|
+
color: var(--select-searching-color, var(--select-accent));
|
|
2602
3034
|
font-size: var(--select-searching-font-size, 14px);
|
|
2603
|
-
|
|
2604
|
-
background: var(--select-searching-bg, white);
|
|
2605
|
-
animation: pulse 1.5s ease-in-out infinite;
|
|
3035
|
+
background: var(--select-searching-bg, transparent);
|
|
2606
3036
|
display: flex;
|
|
2607
3037
|
flex-direction: column;
|
|
2608
3038
|
align-items: center;
|
|
2609
3039
|
justify-content: center;
|
|
2610
|
-
gap:
|
|
2611
|
-
min-height: var(--select-searching-min-height, 72px);
|
|
3040
|
+
gap: var(--select-searching-gap);
|
|
2612
3041
|
}
|
|
2613
3042
|
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
3043
|
+
.searching-state::before {
|
|
3044
|
+
content: '';
|
|
3045
|
+
width: var(--select-searching-spinner-size);
|
|
3046
|
+
height: var(--select-searching-spinner-size);
|
|
3047
|
+
border: var(--select-searching-spinner-border);
|
|
3048
|
+
border-top-color: var(--select-searching-spinner-active-color);
|
|
3049
|
+
border-radius: 50%;
|
|
3050
|
+
animation: var(--select-searching-spinner-animation);
|
|
2617
3051
|
}
|
|
2618
3052
|
|
|
2619
|
-
/*
|
|
3053
|
+
/* ─────────────────────────────────────────────────────────────────────────
|
|
3054
|
+
Error States — Clear visual feedback
|
|
3055
|
+
───────────────────────────────────────────────────────────────────────── */
|
|
3056
|
+
|
|
2620
3057
|
.select-input[aria-invalid="true"] {
|
|
2621
|
-
border-color: var(--select-error-border, #
|
|
3058
|
+
border-color: var(--select-error-border, #e94560);
|
|
2622
3059
|
}
|
|
2623
3060
|
|
|
2624
3061
|
.select-input[aria-invalid="true"]:focus {
|
|
2625
|
-
border-color: var(--select-error-border, #
|
|
2626
|
-
box-shadow: 0 0 0
|
|
2627
|
-
outline-color: var(--select-error-border, #dc2626);
|
|
3062
|
+
border-color: var(--select-error-border, #e94560);
|
|
3063
|
+
box-shadow: 0 0 0 3px var(--select-error-shadow, rgba(233, 69, 96, 0.15));
|
|
2628
3064
|
}
|
|
2629
3065
|
|
|
2630
|
-
/*
|
|
3066
|
+
/* ──────────────────────────────────────────────────��──────────────────────
|
|
3067
|
+
Accessibility — Reduced motion & High contrast
|
|
3068
|
+
───────────────────────────────────────────────────────────────────────── */
|
|
3069
|
+
|
|
2631
3070
|
@media (prefers-reduced-motion: reduce) {
|
|
2632
|
-
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
3071
|
+
*,
|
|
3072
|
+
*::before,
|
|
3073
|
+
*::after {
|
|
3074
|
+
animation-duration: var(--select-reduced-motion-duration) !important;
|
|
3075
|
+
animation-iteration-count: var(--select-reduced-motion-iteration-count) !important;
|
|
3076
|
+
transition-duration: var(--select-reduced-motion-duration) !important;
|
|
3077
|
+
}
|
|
3078
|
+
|
|
3079
|
+
.dropdown-arrow.open {
|
|
3080
|
+
transform: var(--select-arrow-open-transform);
|
|
3081
|
+
}
|
|
3082
|
+
}
|
|
3083
|
+
|
|
3084
|
+
@media (prefers-contrast: high) {
|
|
3085
|
+
.select-input:focus {
|
|
3086
|
+
outline-width: var(--select-high-contrast-focus-outline-width);
|
|
3087
|
+
outline-color: var(--select-high-contrast-focus-outline-color);
|
|
3088
|
+
}
|
|
3089
|
+
|
|
3090
|
+
.input-container {
|
|
3091
|
+
border-width: var(--select-high-contrast-border-width);
|
|
3092
|
+
}
|
|
3093
|
+
|
|
3094
|
+
.option.selected::before {
|
|
3095
|
+
width: var(--select-high-contrast-indicator-width);
|
|
2636
3096
|
}
|
|
2637
3097
|
}
|
|
2638
3098
|
|
|
2639
|
-
/*
|
|
3099
|
+
/* Touch targets (WCAG 2.5.5) */
|
|
3100
|
+
.load-more-button,
|
|
3101
|
+
select-option {
|
|
3102
|
+
min-height: var(--select-touch-target-min-height);
|
|
3103
|
+
}
|
|
3104
|
+
|
|
3105
|
+
/* ─────────────────────────────────────────────────────────────────────────
|
|
3106
|
+
Dark Mode — Elegant dark theme
|
|
3107
|
+
───────────────────────────────────────────────────────────────────────── */
|
|
3108
|
+
|
|
2640
3109
|
:host(.dark-mode),
|
|
2641
3110
|
:host([dark-mode]),
|
|
2642
3111
|
:host([darkmode]),
|
|
@@ -2648,139 +3117,129 @@
|
|
|
2648
3117
|
:host-context([darkmode]),
|
|
2649
3118
|
:host-context([data-theme="dark"]),
|
|
2650
3119
|
:host-context([theme="dark"]) {
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
--select-
|
|
2654
|
-
--select-
|
|
2655
|
-
--select-
|
|
2656
|
-
--select-
|
|
2657
|
-
--select-
|
|
2658
|
-
--select-
|
|
2659
|
-
|
|
2660
|
-
|
|
2661
|
-
|
|
2662
|
-
|
|
2663
|
-
|
|
2664
|
-
|
|
2665
|
-
|
|
2666
|
-
color: var(--select-dark-text, #f9fafb);
|
|
2667
|
-
}
|
|
2668
|
-
|
|
2669
|
-
.select-input::placeholder {
|
|
2670
|
-
color: var(--select-dark-placeholder, #6b7280);
|
|
2671
|
-
}
|
|
2672
|
-
|
|
2673
|
-
.select-dropdown {
|
|
2674
|
-
background: var(--select-dark-dropdown-bg, #1f2937);
|
|
2675
|
-
border-color: var(--select-dark-dropdown-border, #4b5563);
|
|
2676
|
-
}
|
|
2677
|
-
|
|
2678
|
-
.options-container {
|
|
2679
|
-
background: var(--select-dark-options-bg, #1f2937);
|
|
2680
|
-
}
|
|
2681
|
-
|
|
2682
|
-
.option {
|
|
2683
|
-
color: var(--select-dark-option-color, #f9fafb);
|
|
2684
|
-
background: var(--select-dark-option-bg, #1f2937);
|
|
2685
|
-
}
|
|
3120
|
+
--select-primary: #e5e5e5;
|
|
3121
|
+
--select-primary-light: #2a2a3e;
|
|
3122
|
+
--select-accent: #6366f1;
|
|
3123
|
+
--select-accent-hover: #f43f5e;
|
|
3124
|
+
--select-surface: #1a1a2e;
|
|
3125
|
+
--select-surface-elevated: #252540;
|
|
3126
|
+
--select-border: #3f3f5a;
|
|
3127
|
+
--select-border-focus: #6366f1;
|
|
3128
|
+
--select-text: #f5f5f5;
|
|
3129
|
+
--select-text-muted: #9ca3af;
|
|
3130
|
+
--select-text-placeholder: #6b7280;
|
|
3131
|
+
--select-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.2);
|
|
3132
|
+
--select-shadow-md: 0 4px 12px rgba(0, 0, 0, 0.3);
|
|
3133
|
+
--select-shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.4);
|
|
3134
|
+
--select-shadow-focus: 0 0 0 3px rgba(99, 102, 241, 0.25);
|
|
2686
3135
|
|
|
2687
|
-
|
|
2688
|
-
|
|
2689
|
-
|
|
2690
|
-
|
|
2691
|
-
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
color: var(--select-dark-option-selected-text, #e0e7ff);
|
|
2695
|
-
border: var(--select-dark-option-selected-border, var(--select-option-selected-border, var(--select-option-border, none)));
|
|
2696
|
-
border-bottom: var(--select-dark-option-selected-border-bottom, var(--select-option-selected-border-bottom, var(--select-option-border-bottom, none)));
|
|
2697
|
-
box-shadow: var(--select-dark-option-selected-shadow, var(--select-option-selected-shadow, var(--select-option-shadow, none)));
|
|
2698
|
-
transform: var(--select-dark-option-selected-transform, var(--select-option-selected-transform, var(--select-option-transform, none)));
|
|
2699
|
-
}
|
|
2700
|
-
|
|
2701
|
-
.option.selected:hover {
|
|
2702
|
-
background: var(--select-dark-option-selected-hover-bg, var(--select-dark-option-selected-bg, #3730a3));
|
|
2703
|
-
color: var(--select-dark-option-selected-hover-color, var(--select-dark-option-selected-text, #e0e7ff));
|
|
2704
|
-
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)))));
|
|
2705
|
-
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)))));
|
|
2706
|
-
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)))));
|
|
2707
|
-
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)))));
|
|
2708
|
-
}
|
|
2709
|
-
|
|
2710
|
-
.option.active:not(.selected) {
|
|
2711
|
-
background-color: var(--select-dark-option-active-bg, #374151);
|
|
2712
|
-
color: var(--select-dark-option-active-color, #f9fafb);
|
|
2713
|
-
outline: var(--select-dark-option-active-outline, 2px solid rgba(129, 140, 248, 0.55));
|
|
2714
|
-
}
|
|
2715
|
-
|
|
2716
|
-
/* Group header in dark mode */
|
|
2717
|
-
.group-header {
|
|
2718
|
-
color: var(--select-dark-group-header-color, var(--select-group-header-color, #6b7280));
|
|
2719
|
-
background-color: var(--select-dark-group-header-bg, var(--select-group-header-bg, #374151));
|
|
2720
|
-
}
|
|
3136
|
+
--select-option-bg: transparent;
|
|
3137
|
+
--select-option-color: var(--select-text);
|
|
3138
|
+
--select-option-hover-bg: var(--select-surface-elevated);
|
|
3139
|
+
--select-option-hover-color: var(--select-text);
|
|
3140
|
+
--select-option-selected-bg: linear-gradient(135deg, rgba(99, 102, 241, 0.15) 0%, rgba(99, 102, 241, 0.08) 100%);
|
|
3141
|
+
--select-option-selected-color: #a5b4fc;
|
|
3142
|
+
}
|
|
2721
3143
|
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
3144
|
+
:host(.dark-mode) .input-container,
|
|
3145
|
+
:host([dark-mode]) .input-container,
|
|
3146
|
+
:host([darkmode]) .input-container,
|
|
3147
|
+
:host([data-theme="dark"]) .input-container,
|
|
3148
|
+
:host([theme="dark"]) .input-container,
|
|
3149
|
+
:host-context(.dark-mode) .input-container,
|
|
3150
|
+
:host-context(.dark) .input-container,
|
|
3151
|
+
:host-context([dark-mode]) .input-container,
|
|
3152
|
+
:host-context([darkmode]) .input-container,
|
|
3153
|
+
:host-context([data-theme="dark"]) .input-container,
|
|
3154
|
+
:host-context([theme="dark"]) .input-container {
|
|
3155
|
+
background: var(--select-surface);
|
|
3156
|
+
border-color: var(--select-border);
|
|
3157
|
+
}
|
|
2732
3158
|
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
|
|
3159
|
+
:host(.dark-mode) .input-container::after,
|
|
3160
|
+
:host([dark-mode]) .input-container::after,
|
|
3161
|
+
:host([darkmode]) .input-container::after,
|
|
3162
|
+
:host([data-theme="dark"]) .input-container::after,
|
|
3163
|
+
:host([theme="dark"]) .input-container::after,
|
|
3164
|
+
:host-context(.dark-mode) .input-container::after,
|
|
3165
|
+
:host-context(.dark) .input-container::after,
|
|
3166
|
+
:host-context([dark-mode]) .input-container::after,
|
|
3167
|
+
:host-context([darkmode]) .input-container::after,
|
|
3168
|
+
:host-context([data-theme="dark"]) .input-container::after,
|
|
3169
|
+
:host-context([theme="dark"]) .input-container::after {
|
|
3170
|
+
background: var(--select-separator-dark-bg);
|
|
3171
|
+
}
|
|
2737
3172
|
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
3173
|
+
:host(.dark-mode) .select-dropdown,
|
|
3174
|
+
:host([dark-mode]) .select-dropdown,
|
|
3175
|
+
:host([darkmode]) .select-dropdown,
|
|
3176
|
+
:host([data-theme="dark"]) .select-dropdown,
|
|
3177
|
+
:host([theme="dark"]) .select-dropdown,
|
|
3178
|
+
:host-context(.dark-mode) .select-dropdown,
|
|
3179
|
+
:host-context(.dark) .select-dropdown,
|
|
3180
|
+
:host-context([dark-mode]) .select-dropdown,
|
|
3181
|
+
:host-context([darkmode]) .select-dropdown,
|
|
3182
|
+
:host-context([data-theme="dark"]) .select-dropdown,
|
|
3183
|
+
:host-context([theme="dark"]) .select-dropdown {
|
|
3184
|
+
background: var(--select-surface);
|
|
3185
|
+
border-color: var(--select-border);
|
|
3186
|
+
}
|
|
2742
3187
|
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
|
|
2750
|
-
|
|
2751
|
-
|
|
3188
|
+
:host(.dark-mode) .options-container,
|
|
3189
|
+
:host([dark-mode]) .options-container,
|
|
3190
|
+
:host([darkmode]) .options-container,
|
|
3191
|
+
:host([data-theme="dark"]) .options-container,
|
|
3192
|
+
:host([theme="dark"]) .options-container,
|
|
3193
|
+
:host-context(.dark-mode) .options-container,
|
|
3194
|
+
:host-context(.dark) .options-container,
|
|
3195
|
+
:host-context([dark-mode]) .options-container,
|
|
3196
|
+
:host-context([darkmode]) .options-container,
|
|
3197
|
+
:host-context([data-theme="dark"]) .options-container,
|
|
3198
|
+
:host-context([theme="dark"]) .options-container {
|
|
3199
|
+
background: var(--select-surface);
|
|
3200
|
+
scrollbar-color: var(--select-border) transparent;
|
|
3201
|
+
}
|
|
2752
3202
|
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
}
|
|
3203
|
+
:host(.dark-mode) .selection-badge,
|
|
3204
|
+
:host([dark-mode]) .selection-badge,
|
|
3205
|
+
:host([darkmode]) .selection-badge,
|
|
3206
|
+
:host([data-theme="dark"]) .selection-badge,
|
|
3207
|
+
:host([theme="dark"]) .selection-badge,
|
|
3208
|
+
:host-context(.dark-mode) .selection-badge,
|
|
3209
|
+
:host-context(.dark) .selection-badge,
|
|
3210
|
+
:host-context([dark-mode]) .selection-badge,
|
|
3211
|
+
:host-context([darkmode]) .selection-badge,
|
|
3212
|
+
:host-context([data-theme="dark"]) .selection-badge,
|
|
3213
|
+
:host-context([theme="dark"]) .selection-badge {
|
|
3214
|
+
background: var(--select-badge-dark-bg);
|
|
2766
3215
|
}
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
|
|
3216
|
+
|
|
3217
|
+
:host(.dark-mode) .group-header:not(:first-child),
|
|
3218
|
+
:host([dark-mode]) .group-header:not(:first-child),
|
|
3219
|
+
:host([darkmode]) .group-header:not(:first-child),
|
|
3220
|
+
:host([data-theme="dark"]) .group-header:not(:first-child),
|
|
3221
|
+
:host([theme="dark"]) .group-header:not(:first-child),
|
|
3222
|
+
:host-context(.dark-mode) .group-header:not(:first-child),
|
|
3223
|
+
:host-context(.dark) .group-header:not(:first-child),
|
|
3224
|
+
:host-context([dark-mode]) .group-header:not(:first-child),
|
|
3225
|
+
:host-context([darkmode]) .group-header:not(:first-child),
|
|
3226
|
+
:host-context([data-theme="dark"]) .group-header:not(:first-child),
|
|
3227
|
+
:host-context([theme="dark"]) .group-header:not(:first-child) {
|
|
3228
|
+
border-top-color: var(--select-border);
|
|
2778
3229
|
}
|
|
2779
|
-
|
|
2780
|
-
|
|
2781
|
-
.
|
|
2782
|
-
|
|
2783
|
-
|
|
3230
|
+
|
|
3231
|
+
:host(.dark-mode) .option.selected::before,
|
|
3232
|
+
:host([dark-mode]) .option.selected::before,
|
|
3233
|
+
:host([darkmode]) .option.selected::before,
|
|
3234
|
+
:host([data-theme="dark"]) .option.selected::before,
|
|
3235
|
+
:host([theme="dark"]) .option.selected::before,
|
|
3236
|
+
:host-context(.dark-mode) .option.selected::before,
|
|
3237
|
+
:host-context(.dark) .option.selected::before,
|
|
3238
|
+
:host-context([dark-mode]) .option.selected::before,
|
|
3239
|
+
:host-context([darkmode]) .option.selected::before,
|
|
3240
|
+
:host-context([data-theme="dark"]) .option.selected::before,
|
|
3241
|
+
:host-context([theme="dark"]) .option.selected::before {
|
|
3242
|
+
background: var(--select-accent);
|
|
2784
3243
|
}
|
|
2785
3244
|
`;
|
|
2786
3245
|
// Insert as first child to ensure styles are processed first
|
|
@@ -2800,10 +3259,10 @@
|
|
|
2800
3259
|
// delegate to the existing open/close helpers so we don't accidentally
|
|
2801
3260
|
// drift out of sync with the logic in those methods (focus, events,
|
|
2802
3261
|
// scroll-to-selected, etc.)
|
|
2803
|
-
if (this._state.isOpen) {
|
|
3262
|
+
if (this._state.isOpen && this._config.selection.toggleOnTriggerClick !== false) {
|
|
2804
3263
|
this._handleClose();
|
|
2805
3264
|
}
|
|
2806
|
-
else {
|
|
3265
|
+
else if (!this._state.isOpen) {
|
|
2807
3266
|
this._handleOpen();
|
|
2808
3267
|
}
|
|
2809
3268
|
};
|
|
@@ -2826,7 +3285,7 @@
|
|
|
2826
3285
|
this._inputContainer.addEventListener('pointerdown', (e) => {
|
|
2827
3286
|
// Prevent propagation to document click listener but do NOT preventDefault.
|
|
2828
3287
|
// Allow default so browser events (click) on newly opened options still fire.
|
|
2829
|
-
e.stopPropagation();
|
|
3288
|
+
// 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.
|
|
2830
3289
|
const target = e.target;
|
|
2831
3290
|
if (!this._config.enabled)
|
|
2832
3291
|
return;
|
|
@@ -2834,21 +3293,23 @@
|
|
|
2834
3293
|
return;
|
|
2835
3294
|
if (target && target.closest('.clear-control-button'))
|
|
2836
3295
|
return;
|
|
3296
|
+
// If we clicked the container, but not the input itself, we must prevent default
|
|
3297
|
+
// otherwise the browser moves focus from our input to the body, immediately triggering blur.
|
|
3298
|
+
if (target && !target.matches('.select-input')) {
|
|
3299
|
+
e.preventDefault();
|
|
3300
|
+
}
|
|
3301
|
+
const clickedInput = Boolean(target && target.matches('.select-input'));
|
|
3302
|
+
if (this._state.isOpen &&
|
|
3303
|
+
this._config.selection.toggleOnTriggerClick !== false &&
|
|
3304
|
+
!(clickedInput && this._config.searchable)) {
|
|
3305
|
+
this._handleClose();
|
|
3306
|
+
return;
|
|
3307
|
+
}
|
|
2837
3308
|
const wasClosed = !this._state.isOpen;
|
|
2838
3309
|
if (wasClosed) {
|
|
2839
3310
|
this._handleOpen();
|
|
2840
3311
|
}
|
|
2841
|
-
|
|
2842
|
-
// Keep open while interacting directly with the input so users can
|
|
2843
|
-
// place cursor/type without accidental collapse.
|
|
2844
|
-
if (target === this._input) {
|
|
2845
|
-
this._input.focus();
|
|
2846
|
-
return;
|
|
2847
|
-
}
|
|
2848
|
-
// clicking other parts of the input container while open toggles close
|
|
2849
|
-
this._handleClose();
|
|
2850
|
-
}
|
|
2851
|
-
// Focus the input (do not prevent default behavior)
|
|
3312
|
+
// Focus the input (do not prevent default behavior for input itself)
|
|
2852
3313
|
this._input.focus();
|
|
2853
3314
|
// If we just opened the dropdown, transfer pointer capture to the
|
|
2854
3315
|
// options container so the subsequent pointerup lands there instead of
|
|
@@ -2890,7 +3351,7 @@
|
|
|
2890
3351
|
return;
|
|
2891
3352
|
}
|
|
2892
3353
|
this._handleClose();
|
|
2893
|
-
},
|
|
3354
|
+
}, 150);
|
|
2894
3355
|
});
|
|
2895
3356
|
// Input search
|
|
2896
3357
|
this._input.addEventListener('input', (e) => {
|
|
@@ -2907,7 +3368,7 @@
|
|
|
2907
3368
|
this._suppressBlurClose = true;
|
|
2908
3369
|
setTimeout(() => {
|
|
2909
3370
|
this._suppressBlurClose = false;
|
|
2910
|
-
},
|
|
3371
|
+
}, 150); // Increased timeout to ensure click finishes before blur checks
|
|
2911
3372
|
});
|
|
2912
3373
|
// Delegated click listener for improved event handling (robust across shadow DOM)
|
|
2913
3374
|
const handleOptionEvent = (e) => {
|
|
@@ -2938,9 +3399,6 @@
|
|
|
2938
3399
|
}
|
|
2939
3400
|
};
|
|
2940
3401
|
this._optionsContainer.addEventListener('click', handleOptionEvent);
|
|
2941
|
-
// also watch pointerup to catch cases where the pointerdown started outside
|
|
2942
|
-
// (e.g. on the input) and the click never fires
|
|
2943
|
-
this._optionsContainer.addEventListener('pointerup', handleOptionEvent);
|
|
2944
3402
|
// Keyboard navigation
|
|
2945
3403
|
this._input.addEventListener('keydown', (e) => this._handleKeydown(e));
|
|
2946
3404
|
// Click outside to close — robust detection across shadow DOM and custom renderers
|
|
@@ -3038,17 +3496,6 @@
|
|
|
3038
3496
|
this._dropdown.style.display = 'block';
|
|
3039
3497
|
this._input.setAttribute('aria-expanded', 'true');
|
|
3040
3498
|
this._updateArrowRotation();
|
|
3041
|
-
// Clear search query when opening to show all options
|
|
3042
|
-
// This ensures we can scroll to selected item
|
|
3043
|
-
if (this._config.searchable) {
|
|
3044
|
-
this._state.searchQuery = '';
|
|
3045
|
-
// Don't clear input value if it represents selection
|
|
3046
|
-
// But if we want to search, we might want to clear it?
|
|
3047
|
-
// Standard behavior: input keeps value (label), but dropdown shows all options
|
|
3048
|
-
// until user types.
|
|
3049
|
-
// However, our filtering logic uses _state.searchQuery.
|
|
3050
|
-
// So clearing it here resets the filter.
|
|
3051
|
-
}
|
|
3052
3499
|
// Render options when opening
|
|
3053
3500
|
this._renderOptions();
|
|
3054
3501
|
this._setInitialActiveOption();
|
|
@@ -3294,24 +3741,24 @@
|
|
|
3294
3741
|
}
|
|
3295
3742
|
}
|
|
3296
3743
|
_setActive(index) {
|
|
3297
|
-
const options = Array.from(this._optionsContainer.children);
|
|
3298
3744
|
// Clear previous active state
|
|
3299
|
-
if (this._state.activeIndex >= 0
|
|
3300
|
-
const prevOption =
|
|
3301
|
-
|
|
3302
|
-
|
|
3303
|
-
prevOption.setActive
|
|
3304
|
-
|
|
3305
|
-
|
|
3306
|
-
|
|
3307
|
-
|
|
3308
|
-
|
|
3745
|
+
if (this._state.activeIndex >= 0) {
|
|
3746
|
+
const prevOption = this._getOptionElementByIndex(this._state.activeIndex);
|
|
3747
|
+
if (prevOption) {
|
|
3748
|
+
// Check if it's a custom SelectOption or a lightweight DOM element
|
|
3749
|
+
if ('setActive' in prevOption && typeof prevOption.setActive === 'function') {
|
|
3750
|
+
prevOption.setActive(false);
|
|
3751
|
+
}
|
|
3752
|
+
else {
|
|
3753
|
+
// Lightweight option - remove active class
|
|
3754
|
+
prevOption.classList.remove('smilodon-option--active');
|
|
3755
|
+
}
|
|
3309
3756
|
}
|
|
3310
3757
|
}
|
|
3311
3758
|
this._state.activeIndex = index;
|
|
3312
3759
|
// Set new active state
|
|
3313
|
-
|
|
3314
|
-
|
|
3760
|
+
const option = this._getOptionElementByIndex(index);
|
|
3761
|
+
if (option) {
|
|
3315
3762
|
// Check if it's a custom SelectOption or a lightweight DOM element
|
|
3316
3763
|
if ('setActive' in option && typeof option.setActive === 'function') {
|
|
3317
3764
|
option.setActive(true);
|
|
@@ -3319,13 +3766,13 @@
|
|
|
3319
3766
|
else {
|
|
3320
3767
|
// Lightweight option - add active class
|
|
3321
3768
|
option.classList.add('smilodon-option--active');
|
|
3322
|
-
option.setAttribute('aria-selected', 'true');
|
|
3323
3769
|
}
|
|
3324
3770
|
if (typeof option.scrollIntoView === 'function') {
|
|
3771
|
+
// Don't scroll wildly when just opening with pre-selections
|
|
3325
3772
|
option.scrollIntoView({ block: 'nearest', behavior: 'smooth' });
|
|
3326
3773
|
}
|
|
3327
3774
|
// Announce position for screen readers
|
|
3328
|
-
const total =
|
|
3775
|
+
const total = this._state.loadedItems.length;
|
|
3329
3776
|
this._announce(`Item ${index + 1} of ${total}`);
|
|
3330
3777
|
// Update aria-activedescendant using the actual option id when available
|
|
3331
3778
|
const optionId = option.id || `${this._uniqueId}-option-${index}`;
|
|
@@ -3448,9 +3895,9 @@
|
|
|
3448
3895
|
// FIX: Do not rely on this._optionsContainer.children[index] because filtering changes the children
|
|
3449
3896
|
// Instead, use the index to update state directly
|
|
3450
3897
|
const item = this._state.loadedItems[index];
|
|
3451
|
-
|
|
3452
|
-
if (!item)
|
|
3898
|
+
if (!item) {
|
|
3453
3899
|
return;
|
|
3900
|
+
}
|
|
3454
3901
|
const isCurrentlySelected = this._state.selectedIndices.has(index);
|
|
3455
3902
|
// Keep active/focus styling aligned with the most recently interacted option.
|
|
3456
3903
|
// Without this, a previously selected item may retain active classes/styles
|
|
@@ -3461,7 +3908,7 @@
|
|
|
3461
3908
|
const wasSelected = this._state.selectedIndices.has(index);
|
|
3462
3909
|
this._state.selectedIndices.clear();
|
|
3463
3910
|
this._state.selectedItems.clear();
|
|
3464
|
-
if (!wasSelected) {
|
|
3911
|
+
if (!wasSelected || !this._config.selection.allowDeselect) {
|
|
3465
3912
|
// Select this option
|
|
3466
3913
|
this._state.selectedIndices.add(index);
|
|
3467
3914
|
this._state.selectedItems.set(index, item);
|
|
@@ -3523,16 +3970,34 @@
|
|
|
3523
3970
|
});
|
|
3524
3971
|
}
|
|
3525
3972
|
_handleOptionRemove(index) {
|
|
3973
|
+
const item = this._state.selectedItems.get(index);
|
|
3526
3974
|
const option = this._getOptionElementByIndex(index);
|
|
3527
|
-
if (!option)
|
|
3528
|
-
return;
|
|
3529
3975
|
this._state.selectedIndices.delete(index);
|
|
3530
3976
|
this._state.selectedItems.delete(index);
|
|
3531
|
-
option.setSelected
|
|
3977
|
+
if (option && 'setSelected' in option && typeof option.setSelected === 'function') {
|
|
3978
|
+
option.setSelected(false);
|
|
3979
|
+
}
|
|
3980
|
+
else if (option) {
|
|
3981
|
+
option.classList.remove('selected', 'sm-selected', 'smilodon-option--selected');
|
|
3982
|
+
option.setAttribute('aria-selected', 'false');
|
|
3983
|
+
const stateTokens = (option.dataset.smState || '')
|
|
3984
|
+
.split(' ')
|
|
3985
|
+
.map(token => token.trim())
|
|
3986
|
+
.filter(token => token && token !== 'selected');
|
|
3987
|
+
if (stateTokens.length > 0) {
|
|
3988
|
+
option.dataset.smState = stateTokens.join(' ');
|
|
3989
|
+
}
|
|
3990
|
+
else {
|
|
3991
|
+
delete option.dataset.smState;
|
|
3992
|
+
}
|
|
3993
|
+
}
|
|
3532
3994
|
this._updateInputDisplay();
|
|
3995
|
+
this._renderOptions();
|
|
3533
3996
|
this._emitChange();
|
|
3534
|
-
const config = option.getConfig
|
|
3535
|
-
|
|
3997
|
+
const config = option && 'getConfig' in option && typeof option.getConfig === 'function'
|
|
3998
|
+
? option.getConfig()
|
|
3999
|
+
: undefined;
|
|
4000
|
+
this._emit('remove', { item: config?.item ?? item, index });
|
|
3536
4001
|
}
|
|
3537
4002
|
_updateInputDisplay() {
|
|
3538
4003
|
const selectedItems = Array.from(this._state.selectedItems.values());
|
|
@@ -3560,22 +4025,29 @@
|
|
|
3560
4025
|
const badge = document.createElement('span');
|
|
3561
4026
|
badge.className = 'selection-badge';
|
|
3562
4027
|
badge.setAttribute('part', 'chip');
|
|
3563
|
-
|
|
4028
|
+
const badgeLabel = document.createElement('span');
|
|
4029
|
+
badgeLabel.className = 'selection-badge-label';
|
|
4030
|
+
badgeLabel.textContent = getLabel(item);
|
|
4031
|
+
badge.appendChild(badgeLabel);
|
|
3564
4032
|
// Add remove button to badge
|
|
3565
|
-
|
|
3566
|
-
|
|
3567
|
-
|
|
3568
|
-
|
|
3569
|
-
|
|
3570
|
-
|
|
3571
|
-
|
|
3572
|
-
|
|
3573
|
-
|
|
3574
|
-
|
|
3575
|
-
|
|
3576
|
-
|
|
3577
|
-
|
|
3578
|
-
|
|
4033
|
+
if (this._config.selection.showRemoveButton !== false) {
|
|
4034
|
+
const removeBtn = document.createElement('button');
|
|
4035
|
+
removeBtn.type = 'button';
|
|
4036
|
+
removeBtn.className = 'badge-remove';
|
|
4037
|
+
removeBtn.setAttribute('part', 'chip-remove');
|
|
4038
|
+
removeBtn.innerHTML = '×';
|
|
4039
|
+
removeBtn.setAttribute('aria-label', `Remove ${getLabel(item)}`);
|
|
4040
|
+
removeBtn.addEventListener('pointerdown', (e) => {
|
|
4041
|
+
e.stopPropagation();
|
|
4042
|
+
e.preventDefault();
|
|
4043
|
+
});
|
|
4044
|
+
removeBtn.addEventListener('click', (e) => {
|
|
4045
|
+
e.stopPropagation();
|
|
4046
|
+
e.preventDefault();
|
|
4047
|
+
this._handleOptionRemove(index);
|
|
4048
|
+
});
|
|
4049
|
+
badge.appendChild(removeBtn);
|
|
4050
|
+
}
|
|
3579
4051
|
this._inputContainer.insertBefore(badge, this._input);
|
|
3580
4052
|
});
|
|
3581
4053
|
}
|
|
@@ -3627,10 +4099,12 @@
|
|
|
3627
4099
|
const option = this._getOptionElementByIndex(targetIndex);
|
|
3628
4100
|
if (option) {
|
|
3629
4101
|
// Use smooth scrolling with center alignment for better UX
|
|
3630
|
-
option.scrollIntoView
|
|
3631
|
-
|
|
3632
|
-
|
|
3633
|
-
|
|
4102
|
+
if (typeof option.scrollIntoView === 'function') {
|
|
4103
|
+
option.scrollIntoView({
|
|
4104
|
+
block: this._config.scrollToSelected.block || 'center',
|
|
4105
|
+
behavior: 'smooth',
|
|
4106
|
+
});
|
|
4107
|
+
}
|
|
3634
4108
|
// Also set it as active for keyboard navigation
|
|
3635
4109
|
this._setActive(targetIndex);
|
|
3636
4110
|
}
|
|
@@ -3680,13 +4154,168 @@
|
|
|
3680
4154
|
}
|
|
3681
4155
|
_emit(name, detail) {
|
|
3682
4156
|
this.dispatchEvent(new CustomEvent(name, { detail, bubbles: true, composed: true }));
|
|
4157
|
+
if (name !== 'diagnostic') {
|
|
4158
|
+
this._track('event', String(name), detail);
|
|
4159
|
+
}
|
|
4160
|
+
}
|
|
4161
|
+
_track(source, name, detail) {
|
|
4162
|
+
const cfg = this._config.tracking;
|
|
4163
|
+
if (!cfg?.enabled)
|
|
4164
|
+
return;
|
|
4165
|
+
if (source === 'event' && !cfg.events)
|
|
4166
|
+
return;
|
|
4167
|
+
if (source === 'style' && !cfg.styling)
|
|
4168
|
+
return;
|
|
4169
|
+
if (source === 'limitation' && !cfg.limitations)
|
|
4170
|
+
return;
|
|
4171
|
+
const entry = {
|
|
4172
|
+
timestamp: Date.now(),
|
|
4173
|
+
source,
|
|
4174
|
+
name,
|
|
4175
|
+
detail,
|
|
4176
|
+
};
|
|
4177
|
+
const bucket = source === 'event'
|
|
4178
|
+
? this._tracking.events
|
|
4179
|
+
: source === 'style'
|
|
4180
|
+
? this._tracking.styles
|
|
4181
|
+
: this._tracking.limitations;
|
|
4182
|
+
bucket.push(entry);
|
|
4183
|
+
const maxEntries = Math.max(10, cfg.maxEntries || 200);
|
|
4184
|
+
if (bucket.length > maxEntries) {
|
|
4185
|
+
bucket.splice(0, bucket.length - maxEntries);
|
|
4186
|
+
}
|
|
4187
|
+
if (cfg.emitDiagnostics) {
|
|
4188
|
+
this.dispatchEvent(new CustomEvent('diagnostic', {
|
|
4189
|
+
detail: entry,
|
|
4190
|
+
bubbles: true,
|
|
4191
|
+
composed: true,
|
|
4192
|
+
}));
|
|
4193
|
+
}
|
|
4194
|
+
}
|
|
4195
|
+
_getKnownLimitationDefinitions() {
|
|
4196
|
+
return [
|
|
4197
|
+
{
|
|
4198
|
+
id: 'variableItemHeight',
|
|
4199
|
+
title: 'Variable item height',
|
|
4200
|
+
description: 'Virtualization assumes fixed or estimated item heights; fully dynamic heights are not yet supported.',
|
|
4201
|
+
workaround: 'Use consistent item heights or set estimatedItemHeight to your dominant row size.',
|
|
4202
|
+
},
|
|
4203
|
+
{
|
|
4204
|
+
id: 'builtInFetchPaginationApi',
|
|
4205
|
+
title: 'Built-in fetch/pagination API',
|
|
4206
|
+
description: 'Core does not include a built-in fetchUrl/searchUrl pagination transport.',
|
|
4207
|
+
workaround: 'Use onSearch/onLoadMore callbacks and update data via setItems().',
|
|
4208
|
+
},
|
|
4209
|
+
{
|
|
4210
|
+
id: 'virtualizationOverheadSmallLists',
|
|
4211
|
+
title: 'Virtualization overhead for small lists',
|
|
4212
|
+
description: 'Virtualization can add slight overhead on very small lists.',
|
|
4213
|
+
workaround: 'Disable virtualization for tiny datasets when micro-latency is critical.',
|
|
4214
|
+
},
|
|
4215
|
+
{
|
|
4216
|
+
id: 'runtimeModeSwitching',
|
|
4217
|
+
title: 'Runtime single/multi mode switching',
|
|
4218
|
+
description: 'Switching between single and multi mode can require state reset for consistency.',
|
|
4219
|
+
workaround: 'Enable autoMitigateRuntimeModeSwitch or recreate/reset component state when toggling modes.',
|
|
4220
|
+
},
|
|
4221
|
+
{
|
|
4222
|
+
id: 'legacyBrowserSupport',
|
|
4223
|
+
title: 'Legacy browser support',
|
|
4224
|
+
description: 'Official support targets modern evergreen browsers.',
|
|
4225
|
+
},
|
|
4226
|
+
{
|
|
4227
|
+
id: 'webkitArchLinux',
|
|
4228
|
+
title: 'Playwright WebKit on Arch-based Linux',
|
|
4229
|
+
description: 'Native WebKit Playwright bundle depends on unavailable legacy system libraries on Arch-based distros.',
|
|
4230
|
+
workaround: 'Run WebKit E2E tests via Playwright Docker image.',
|
|
4231
|
+
},
|
|
4232
|
+
];
|
|
4233
|
+
}
|
|
4234
|
+
_evaluateLimitationStatus(id) {
|
|
4235
|
+
const policyMode = this._config.limitations?.policies?.[id]?.mode ?? 'default';
|
|
4236
|
+
if (policyMode === 'suppress')
|
|
4237
|
+
return 'suppressed';
|
|
4238
|
+
if (id === 'runtimeModeSwitching' && this._config.limitations?.autoMitigateRuntimeModeSwitch) {
|
|
4239
|
+
return 'mitigated';
|
|
4240
|
+
}
|
|
4241
|
+
return 'active';
|
|
4242
|
+
}
|
|
4243
|
+
getKnownLimitations() {
|
|
4244
|
+
return this._getKnownLimitationDefinitions().map((limitation) => {
|
|
4245
|
+
const mode = this._config.limitations?.policies?.[limitation.id]?.mode ?? 'default';
|
|
4246
|
+
return {
|
|
4247
|
+
...limitation,
|
|
4248
|
+
mode,
|
|
4249
|
+
status: this._evaluateLimitationStatus(limitation.id),
|
|
4250
|
+
};
|
|
4251
|
+
});
|
|
4252
|
+
}
|
|
4253
|
+
setLimitationPolicies(policies) {
|
|
4254
|
+
const next = {
|
|
4255
|
+
...(this._config.limitations?.policies || {}),
|
|
4256
|
+
...policies,
|
|
4257
|
+
};
|
|
4258
|
+
this.updateConfig({
|
|
4259
|
+
limitations: {
|
|
4260
|
+
...(this._config.limitations || { autoMitigateRuntimeModeSwitch: true, policies: {} }),
|
|
4261
|
+
policies: next,
|
|
4262
|
+
},
|
|
4263
|
+
});
|
|
4264
|
+
this._track('limitation', 'policiesUpdated', { policies: next });
|
|
4265
|
+
}
|
|
4266
|
+
getTrackingSnapshot() {
|
|
4267
|
+
return {
|
|
4268
|
+
events: [...this._tracking.events],
|
|
4269
|
+
styles: [...this._tracking.styles],
|
|
4270
|
+
limitations: [...this._tracking.limitations],
|
|
4271
|
+
};
|
|
4272
|
+
}
|
|
4273
|
+
clearTracking(source) {
|
|
4274
|
+
if (!source || source === 'all') {
|
|
4275
|
+
this._tracking.events = [];
|
|
4276
|
+
this._tracking.styles = [];
|
|
4277
|
+
this._tracking.limitations = [];
|
|
4278
|
+
return;
|
|
4279
|
+
}
|
|
4280
|
+
if (source === 'event')
|
|
4281
|
+
this._tracking.events = [];
|
|
4282
|
+
if (source === 'style')
|
|
4283
|
+
this._tracking.styles = [];
|
|
4284
|
+
if (source === 'limitation')
|
|
4285
|
+
this._tracking.limitations = [];
|
|
4286
|
+
}
|
|
4287
|
+
getCapabilities() {
|
|
4288
|
+
return {
|
|
4289
|
+
styling: {
|
|
4290
|
+
classMap: true,
|
|
4291
|
+
optionRenderer: true,
|
|
4292
|
+
groupHeaderRenderer: true,
|
|
4293
|
+
cssCustomProperties: true,
|
|
4294
|
+
shadowParts: true,
|
|
4295
|
+
globalStyleMirroring: true,
|
|
4296
|
+
},
|
|
4297
|
+
events: {
|
|
4298
|
+
emitted: ['select', 'open', 'close', 'search', 'change', 'loadMore', 'remove', 'clear', 'error', 'diagnostic'],
|
|
4299
|
+
diagnosticEvent: true,
|
|
4300
|
+
},
|
|
4301
|
+
functionality: {
|
|
4302
|
+
multiSelect: true,
|
|
4303
|
+
searchable: true,
|
|
4304
|
+
infiniteScroll: true,
|
|
4305
|
+
loadMore: true,
|
|
4306
|
+
clearControl: true,
|
|
4307
|
+
groupedItems: true,
|
|
4308
|
+
serverSideSelection: true,
|
|
4309
|
+
runtimeModeSwitchMitigation: Boolean(this._config.limitations?.autoMitigateRuntimeModeSwitch),
|
|
4310
|
+
},
|
|
4311
|
+
limitations: this.getKnownLimitations(),
|
|
4312
|
+
};
|
|
3683
4313
|
}
|
|
3684
4314
|
_emitChange() {
|
|
3685
4315
|
const selectedItems = Array.from(this._state.selectedItems.values());
|
|
3686
4316
|
const getValue = this._config.serverSide.getValueFromItem || ((item) => item?.value ?? item);
|
|
3687
4317
|
const selectedValues = selectedItems.map(getValue);
|
|
3688
4318
|
const selectedIndices = Array.from(this._state.selectedIndices);
|
|
3689
|
-
// Debug: log change payload
|
|
3690
4319
|
this._emit('change', { selectedItems, selectedValues, selectedIndices });
|
|
3691
4320
|
this._config.callbacks.onChange?.(selectedItems, selectedValues);
|
|
3692
4321
|
}
|
|
@@ -3697,6 +4326,7 @@
|
|
|
3697
4326
|
set optionRenderer(renderer) {
|
|
3698
4327
|
this._optionRenderer = renderer;
|
|
3699
4328
|
this._setGlobalStylesMirroring(Boolean(renderer || this._classMap));
|
|
4329
|
+
this._track('style', 'optionRendererChanged', { enabled: Boolean(renderer) });
|
|
3700
4330
|
this._renderOptions();
|
|
3701
4331
|
}
|
|
3702
4332
|
/**
|
|
@@ -3861,7 +4491,22 @@
|
|
|
3861
4491
|
* Update component configuration
|
|
3862
4492
|
*/
|
|
3863
4493
|
updateConfig(config) {
|
|
3864
|
-
|
|
4494
|
+
const previousMode = this._config.selection.mode;
|
|
4495
|
+
this._config = this._mergeConfig(this._config, config);
|
|
4496
|
+
if (previousMode !== this._config.selection.mode &&
|
|
4497
|
+
this._config.limitations?.autoMitigateRuntimeModeSwitch) {
|
|
4498
|
+
this.clear();
|
|
4499
|
+
this._track('limitation', 'runtimeModeSwitchMitigated', {
|
|
4500
|
+
from: previousMode,
|
|
4501
|
+
to: this._config.selection.mode,
|
|
4502
|
+
});
|
|
4503
|
+
}
|
|
4504
|
+
else if (previousMode !== this._config.selection.mode) {
|
|
4505
|
+
this._track('limitation', 'runtimeModeSwitchDetected', {
|
|
4506
|
+
from: previousMode,
|
|
4507
|
+
to: this._config.selection.mode,
|
|
4508
|
+
});
|
|
4509
|
+
}
|
|
3865
4510
|
// Update input state based on new config
|
|
3866
4511
|
if (this._input) {
|
|
3867
4512
|
this._input.readOnly = !this._config.searchable;
|
|
@@ -3874,7 +4519,7 @@
|
|
|
3874
4519
|
this._clearControl.setAttribute('aria-label', this._config.clearControl.ariaLabel || 'Clear selection and search');
|
|
3875
4520
|
}
|
|
3876
4521
|
if (this._clearControlIcon) {
|
|
3877
|
-
this._clearControlIcon.
|
|
4522
|
+
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>`;
|
|
3878
4523
|
}
|
|
3879
4524
|
if (this._dropdown) {
|
|
3880
4525
|
if (this._config.selection.mode === 'multi') {
|
|
@@ -3884,11 +4529,28 @@
|
|
|
3884
4529
|
this._dropdown.removeAttribute('aria-multiselectable');
|
|
3885
4530
|
}
|
|
3886
4531
|
}
|
|
4532
|
+
this._syncInputContainerMode();
|
|
3887
4533
|
// Re-initialize observers in case infinite scroll was enabled/disabled
|
|
3888
4534
|
this._initializeObservers();
|
|
3889
4535
|
this._syncClearControlState();
|
|
3890
4536
|
this._renderOptions();
|
|
3891
4537
|
}
|
|
4538
|
+
_mergeConfig(target, source) {
|
|
4539
|
+
const result = { ...target };
|
|
4540
|
+
for (const key in source) {
|
|
4541
|
+
if (!Object.prototype.hasOwnProperty.call(source, key))
|
|
4542
|
+
continue;
|
|
4543
|
+
const sourceValue = source[key];
|
|
4544
|
+
const targetValue = result[key];
|
|
4545
|
+
if (sourceValue && typeof sourceValue === 'object' && !Array.isArray(sourceValue)) {
|
|
4546
|
+
result[key] = this._mergeConfig(targetValue && typeof targetValue === 'object' ? targetValue : {}, sourceValue);
|
|
4547
|
+
}
|
|
4548
|
+
else {
|
|
4549
|
+
result[key] = sourceValue;
|
|
4550
|
+
}
|
|
4551
|
+
}
|
|
4552
|
+
return result;
|
|
4553
|
+
}
|
|
3892
4554
|
_handleClearControlClick() {
|
|
3893
4555
|
const shouldClearSelection = this._config.clearControl.clearSelection !== false;
|
|
3894
4556
|
const shouldClearSearch = this._config.clearControl.clearSearch !== false;
|
|
@@ -3973,6 +4635,8 @@
|
|
|
3973
4635
|
* Render options based on current state
|
|
3974
4636
|
*/
|
|
3975
4637
|
_renderOptions() {
|
|
4638
|
+
this._renderCycleId += 1;
|
|
4639
|
+
const renderCycleId = this._renderCycleId;
|
|
3976
4640
|
// Cleanup observer
|
|
3977
4641
|
if (this._loadMoreTrigger && this._intersectionObserver) {
|
|
3978
4642
|
this._intersectionObserver.unobserve(this._loadMoreTrigger);
|
|
@@ -4037,23 +4701,21 @@
|
|
|
4037
4701
|
}
|
|
4038
4702
|
else {
|
|
4039
4703
|
// Normal rendering (flat list or filtered)
|
|
4040
|
-
|
|
4704
|
+
const filteredIndices = [];
|
|
4041
4705
|
this._state.loadedItems.forEach((item, index) => {
|
|
4042
|
-
// Apply filter if query exists
|
|
4043
4706
|
if (query) {
|
|
4044
4707
|
try {
|
|
4045
4708
|
const label = String(getLabel(item)).toLowerCase();
|
|
4046
4709
|
if (!label.includes(query))
|
|
4047
4710
|
return;
|
|
4048
4711
|
}
|
|
4049
|
-
catch (
|
|
4712
|
+
catch (_e) {
|
|
4050
4713
|
return;
|
|
4051
4714
|
}
|
|
4052
4715
|
}
|
|
4053
|
-
|
|
4054
|
-
this._renderSingleOption(item, index, getValue, getLabel);
|
|
4716
|
+
filteredIndices.push(index);
|
|
4055
4717
|
});
|
|
4056
|
-
if (
|
|
4718
|
+
if (filteredIndices.length === 0 && !this._state.isBusy) {
|
|
4057
4719
|
const empty = document.createElement('div');
|
|
4058
4720
|
empty.setAttribute('part', 'no-results');
|
|
4059
4721
|
empty.className = 'empty-state';
|
|
@@ -4065,6 +4727,54 @@
|
|
|
4065
4727
|
}
|
|
4066
4728
|
this._optionsContainer.appendChild(empty);
|
|
4067
4729
|
}
|
|
4730
|
+
else {
|
|
4731
|
+
const shouldIncrementalRender = this._config.virtualize !== false
|
|
4732
|
+
&& this._state.groupedItems.length === 0
|
|
4733
|
+
&& filteredIndices.length > 300;
|
|
4734
|
+
if (shouldIncrementalRender) {
|
|
4735
|
+
const chunkSize = 80;
|
|
4736
|
+
let cursor = 0;
|
|
4737
|
+
let maxRenderTarget = 0;
|
|
4738
|
+
if (this._state.selectedIndices.size > 0 && this._config.scrollToSelected.enabled) {
|
|
4739
|
+
const indices = Array.from(this._state.selectedIndices).sort((a, b) => a - b);
|
|
4740
|
+
const targetIndex = this._config.scrollToSelected.multiSelectTarget === 'first' ? indices[0] : indices[indices.length - 1];
|
|
4741
|
+
const filteredPos = filteredIndices.indexOf(targetIndex);
|
|
4742
|
+
if (filteredPos !== -1) {
|
|
4743
|
+
maxRenderTarget = filteredPos + 20; // Ensure we render up to the selection
|
|
4744
|
+
}
|
|
4745
|
+
}
|
|
4746
|
+
const renderChunk = () => {
|
|
4747
|
+
if (renderCycleId !== this._renderCycleId)
|
|
4748
|
+
return;
|
|
4749
|
+
const fragment = document.createDocumentFragment();
|
|
4750
|
+
const chunkEnd = Math.min(Math.max(cursor + chunkSize, maxRenderTarget), filteredIndices.length);
|
|
4751
|
+
maxRenderTarget = 0; // Reset after fast-forwarding
|
|
4752
|
+
for (; cursor < chunkEnd; cursor += 1) {
|
|
4753
|
+
const itemIndex = filteredIndices[cursor];
|
|
4754
|
+
const item = this._state.loadedItems[itemIndex];
|
|
4755
|
+
this._renderSingleOption(item, itemIndex, getValue, getLabel, fragment);
|
|
4756
|
+
}
|
|
4757
|
+
this._optionsContainer.appendChild(fragment);
|
|
4758
|
+
if (cursor < filteredIndices.length) {
|
|
4759
|
+
requestAnimationFrame(renderChunk);
|
|
4760
|
+
}
|
|
4761
|
+
else {
|
|
4762
|
+
if (renderCycleId !== this._renderCycleId)
|
|
4763
|
+
return;
|
|
4764
|
+
if (!this._state.isBusy && (this._config.loadMore.enabled || this._config.infiniteScroll.enabled) && this._state.loadedItems.length > 0) {
|
|
4765
|
+
this._addLoadMoreTrigger();
|
|
4766
|
+
}
|
|
4767
|
+
this._finalizePerfMarks();
|
|
4768
|
+
}
|
|
4769
|
+
};
|
|
4770
|
+
renderChunk();
|
|
4771
|
+
return;
|
|
4772
|
+
}
|
|
4773
|
+
filteredIndices.forEach((itemIndex) => {
|
|
4774
|
+
const item = this._state.loadedItems[itemIndex];
|
|
4775
|
+
this._renderSingleOption(item, itemIndex, getValue, getLabel);
|
|
4776
|
+
});
|
|
4777
|
+
}
|
|
4068
4778
|
}
|
|
4069
4779
|
// Append Busy Indicator if busy
|
|
4070
4780
|
if (this._state.isBusy && this._config.busyBucket.enabled) {
|
|
@@ -4089,7 +4799,7 @@
|
|
|
4089
4799
|
}
|
|
4090
4800
|
this._finalizePerfMarks();
|
|
4091
4801
|
}
|
|
4092
|
-
_renderSingleOption(item, index, getValue, getLabel) {
|
|
4802
|
+
_renderSingleOption(item, index, getValue, getLabel, targetContainer = this._optionsContainer) {
|
|
4093
4803
|
const isSelected = this._state.selectedIndices.has(index);
|
|
4094
4804
|
const isDisabled = Boolean(item?.disabled);
|
|
4095
4805
|
const optionId = `${this._uniqueId}-option-${index}`;
|
|
@@ -4105,7 +4815,7 @@
|
|
|
4105
4815
|
disabled: isDisabled,
|
|
4106
4816
|
id: optionId,
|
|
4107
4817
|
});
|
|
4108
|
-
|
|
4818
|
+
targetContainer.appendChild(optionElement);
|
|
4109
4819
|
return;
|
|
4110
4820
|
}
|
|
4111
4821
|
const option = new SelectOption({
|
|
@@ -4134,20 +4844,16 @@
|
|
|
4134
4844
|
option.dataset.smValue = String(val);
|
|
4135
4845
|
}
|
|
4136
4846
|
option.id = option.id || optionId;
|
|
4137
|
-
|
|
4138
|
-
|
|
4139
|
-
|
|
4140
|
-
|
|
4141
|
-
shiftKey: mouseEvent.shiftKey,
|
|
4142
|
-
toggleKey: mouseEvent.ctrlKey || mouseEvent.metaKey,
|
|
4143
|
-
});
|
|
4144
|
-
});
|
|
4847
|
+
// Do NOT bind a native click listener here for SelectOption elements.
|
|
4848
|
+
// Like custom rendered options, they are fully handled by the `handleOptionEvent` delegator
|
|
4849
|
+
// on `this._optionsContainer` (line 1221).
|
|
4850
|
+
// Adding this listener causes the double-click toggle bug since both fire on selection!
|
|
4145
4851
|
option.addEventListener('optionRemove', (event) => {
|
|
4146
4852
|
const detail = event.detail;
|
|
4147
4853
|
const targetIndex = detail?.index ?? index;
|
|
4148
4854
|
this._handleOptionRemove(targetIndex);
|
|
4149
4855
|
});
|
|
4150
|
-
|
|
4856
|
+
targetContainer.appendChild(option);
|
|
4151
4857
|
}
|
|
4152
4858
|
_normalizeCustomOptionElement(element, meta) {
|
|
4153
4859
|
const optionEl = element instanceof HTMLElement ? element : document.createElement('div');
|
|
@@ -4234,35 +4940,9 @@
|
|
|
4234
4940
|
optionEl.tabIndex = -1;
|
|
4235
4941
|
}
|
|
4236
4942
|
if (!this._customOptionBoundElements.has(optionEl)) {
|
|
4237
|
-
|
|
4238
|
-
|
|
4239
|
-
|
|
4240
|
-
if (current.getAttribute('aria-disabled') === 'true')
|
|
4241
|
-
return;
|
|
4242
|
-
const parsedIndex = Number(current.dataset.index);
|
|
4243
|
-
if (!Number.isFinite(parsedIndex))
|
|
4244
|
-
return;
|
|
4245
|
-
const mouseEvent = e;
|
|
4246
|
-
this._selectOption(parsedIndex, {
|
|
4247
|
-
shiftKey: mouseEvent.shiftKey,
|
|
4248
|
-
toggleKey: mouseEvent.ctrlKey || mouseEvent.metaKey,
|
|
4249
|
-
});
|
|
4250
|
-
});
|
|
4251
|
-
optionEl.addEventListener('keydown', (e) => {
|
|
4252
|
-
if (e.key !== 'Enter' && e.key !== ' ')
|
|
4253
|
-
return;
|
|
4254
|
-
const current = e.currentTarget;
|
|
4255
|
-
if (current.getAttribute('aria-disabled') === 'true')
|
|
4256
|
-
return;
|
|
4257
|
-
const parsedIndex = Number(current.dataset.index);
|
|
4258
|
-
if (!Number.isFinite(parsedIndex))
|
|
4259
|
-
return;
|
|
4260
|
-
e.preventDefault();
|
|
4261
|
-
this._selectOption(parsedIndex, {
|
|
4262
|
-
shiftKey: e.shiftKey,
|
|
4263
|
-
toggleKey: e.ctrlKey || e.metaKey,
|
|
4264
|
-
});
|
|
4265
|
-
});
|
|
4943
|
+
// Intentionally NOT binding native option click listeners for custom options!
|
|
4944
|
+
// All option interactions are globally handled by _optionsContainer.addEventListener('click', handleOptionEvent);
|
|
4945
|
+
// Re-attaching here causes the double-click toggle bug if a child component fails to stopPropagation.
|
|
4266
4946
|
this._customOptionBoundElements.add(optionEl);
|
|
4267
4947
|
}
|
|
4268
4948
|
return optionEl;
|