@smilodon/core 1.4.12 → 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 +926 -453
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +926 -453
- 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 +926 -453
- 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 +5 -0
- package/dist/types/src/config/global-config.d.ts +2 -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,
|
|
@@ -1887,6 +1888,8 @@
|
|
|
1887
1888
|
* Enhanced Select Component
|
|
1888
1889
|
* Implements all advanced features: infinite scroll, load more, busy state,
|
|
1889
1890
|
* server-side selection, and full customization
|
|
1891
|
+
*
|
|
1892
|
+
* ✨ Redesigned with formal elegance, refined microinteractions, and polished UX
|
|
1890
1893
|
*/
|
|
1891
1894
|
class EnhancedSelect extends HTMLElement {
|
|
1892
1895
|
get classMap() {
|
|
@@ -1934,6 +1937,8 @@
|
|
|
1934
1937
|
this._globalStylesObserver = null;
|
|
1935
1938
|
this._globalStylesContainer = null;
|
|
1936
1939
|
this._tracking = { events: [], styles: [], limitations: [] };
|
|
1940
|
+
this._suppressBlurClose = false;
|
|
1941
|
+
this._renderCycleId = 0;
|
|
1937
1942
|
this._shadow = this.attachShadow({ mode: 'open' });
|
|
1938
1943
|
this._uniqueId = `enhanced-select-${Math.random().toString(36).substr(2, 9)}`;
|
|
1939
1944
|
this._rendererHelpers = this._buildRendererHelpers();
|
|
@@ -2008,6 +2013,7 @@
|
|
|
2008
2013
|
if (this._boundArrowClick && this._arrowContainer) {
|
|
2009
2014
|
this._arrowContainer.removeEventListener('click', this._boundArrowClick);
|
|
2010
2015
|
}
|
|
2016
|
+
this._renderCycleId += 1;
|
|
2011
2017
|
this._teardownGlobalStylesMirroring();
|
|
2012
2018
|
}
|
|
2013
2019
|
_setGlobalStylesMirroring(enabled) {
|
|
@@ -2111,8 +2117,48 @@
|
|
|
2111
2117
|
const container = document.createElement('div');
|
|
2112
2118
|
container.className = 'input-container';
|
|
2113
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
|
+
}
|
|
2114
2143
|
return container;
|
|
2115
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
|
+
}
|
|
2116
2162
|
_createInput() {
|
|
2117
2163
|
const input = document.createElement('input');
|
|
2118
2164
|
input.setAttribute('part', 'input');
|
|
@@ -2122,6 +2168,35 @@
|
|
|
2122
2168
|
input.placeholder = this._config.placeholder || 'Select an option...';
|
|
2123
2169
|
input.disabled = !this._config.enabled;
|
|
2124
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';
|
|
2125
2200
|
// Update readonly when input is focused if searchable
|
|
2126
2201
|
input.addEventListener('focus', () => {
|
|
2127
2202
|
if (this._config.searchable) {
|
|
@@ -2132,7 +2207,22 @@
|
|
|
2132
2207
|
input.className += ' ' + this._config.styles.classNames.input;
|
|
2133
2208
|
}
|
|
2134
2209
|
if (this._config.styles.input) {
|
|
2135
|
-
|
|
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);
|
|
2136
2226
|
}
|
|
2137
2227
|
input.setAttribute('role', 'combobox');
|
|
2138
2228
|
input.setAttribute('aria-expanded', 'false');
|
|
@@ -2176,7 +2266,7 @@
|
|
|
2176
2266
|
container.className = 'dropdown-arrow-container';
|
|
2177
2267
|
container.innerHTML = `
|
|
2178
2268
|
<svg class="dropdown-arrow" part="arrow" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2179
|
-
<path d="M4 6L8 10L12 6" stroke="currentColor" stroke-width="
|
|
2269
|
+
<path d="M4 6L8 10L12 6" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
|
2180
2270
|
</svg>
|
|
2181
2271
|
`;
|
|
2182
2272
|
return container;
|
|
@@ -2189,7 +2279,7 @@
|
|
|
2189
2279
|
const icon = document.createElement('span');
|
|
2190
2280
|
icon.className = 'clear-control-icon';
|
|
2191
2281
|
icon.setAttribute('part', 'clear-icon');
|
|
2192
|
-
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>`;
|
|
2193
2283
|
button.setAttribute('aria-label', this._config.clearControl.ariaLabel || 'Clear selection and search');
|
|
2194
2284
|
button.appendChild(icon);
|
|
2195
2285
|
this._clearControlIcon = icon;
|
|
@@ -2215,18 +2305,229 @@
|
|
|
2215
2305
|
this._dropdown.id = listboxId;
|
|
2216
2306
|
this._input.setAttribute('aria-controls', listboxId);
|
|
2217
2307
|
this._input.setAttribute('aria-owns', listboxId);
|
|
2308
|
+
this._syncInputContainerMode();
|
|
2218
2309
|
this._syncClearControlState();
|
|
2219
2310
|
}
|
|
2220
2311
|
_initializeStyles() {
|
|
2221
2312
|
const style = document.createElement('style');
|
|
2222
2313
|
style.textContent = `
|
|
2314
|
+
/* ═══════════════════════════════════════════════════════════════════════════
|
|
2315
|
+
ELEGANT SELECT COMPONENT — Refined Design System
|
|
2316
|
+
Formal aesthetics with sophisticated microinteractions
|
|
2317
|
+
═══════════════════════════════════════════════════════════════════════════ */
|
|
2318
|
+
|
|
2223
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
|
+
|
|
2224
2427
|
display: block;
|
|
2225
2428
|
position: relative;
|
|
2226
2429
|
width: var(--select-width, 100%);
|
|
2227
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);
|
|
2464
|
+
}
|
|
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);
|
|
2228
2511
|
}
|
|
2229
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
|
+
|
|
2230
2531
|
.select-container {
|
|
2231
2532
|
position: relative;
|
|
2232
2533
|
width: 100%;
|
|
@@ -2237,102 +2538,143 @@
|
|
|
2237
2538
|
width: 100%;
|
|
2238
2539
|
display: flex;
|
|
2239
2540
|
align-items: center;
|
|
2240
|
-
flex-wrap:
|
|
2541
|
+
flex-wrap: nowrap;
|
|
2241
2542
|
gap: var(--select-input-gap, 6px);
|
|
2242
|
-
padding: var(--select-input-padding,
|
|
2543
|
+
padding: var(--select-input-padding, 10px 52px 10px 14px);
|
|
2243
2544
|
height: var(--select-input-height, auto);
|
|
2244
|
-
min-height: var(--select-input-min-height,
|
|
2545
|
+
min-height: var(--select-input-min-height, 48px);
|
|
2245
2546
|
max-height: var(--select-input-max-height, 160px);
|
|
2246
2547
|
overflow-y: var(--select-input-overflow-y, auto);
|
|
2247
|
-
align-content:
|
|
2248
|
-
background: var(--select-input-bg, var(--select-
|
|
2249
|
-
border: var(--select-input-border,
|
|
2250
|
-
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);
|
|
2251
2553
|
box-sizing: border-box;
|
|
2252
|
-
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;
|
|
2253
2573
|
}
|
|
2254
2574
|
|
|
2255
2575
|
.input-container:focus-within {
|
|
2256
|
-
border-color: var(--select-input-focus-border, var(--select-border-focus
|
|
2257
|
-
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);
|
|
2258
2578
|
}
|
|
2259
2579
|
|
|
2260
|
-
/*
|
|
2580
|
+
/* Elegant separator line before arrow */
|
|
2261
2581
|
.input-container::after {
|
|
2262
2582
|
content: '';
|
|
2263
2583
|
position: absolute;
|
|
2264
2584
|
top: 50%;
|
|
2265
|
-
right: var(--select-separator-position,
|
|
2585
|
+
right: var(--select-separator-position, 42px);
|
|
2266
2586
|
transform: translateY(-50%);
|
|
2267
|
-
width: var(--select-separator-width,
|
|
2268
|
-
height: var(--select-separator-height,
|
|
2269
|
-
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(
|
|
2270
2590
|
to bottom,
|
|
2271
2591
|
transparent 0%,
|
|
2272
|
-
|
|
2273
|
-
|
|
2592
|
+
var(--select-border) 20%,
|
|
2593
|
+
var(--select-border) 80%,
|
|
2274
2594
|
transparent 100%
|
|
2275
|
-
))
|
|
2595
|
+
));
|
|
2276
2596
|
pointer-events: none;
|
|
2277
2597
|
z-index: 1;
|
|
2598
|
+
opacity: var(--select-separator-opacity);
|
|
2599
|
+
transition: opacity var(--select-transition-fast);
|
|
2278
2600
|
}
|
|
2279
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
|
+
|
|
2280
2611
|
.dropdown-arrow-container {
|
|
2281
2612
|
position: absolute;
|
|
2282
2613
|
top: 0;
|
|
2283
2614
|
right: 0;
|
|
2284
2615
|
bottom: 0;
|
|
2285
|
-
width: var(--select-arrow-width,
|
|
2286
|
-
/* allow explicit height override even though container normally stretches */
|
|
2616
|
+
width: var(--select-arrow-width, 42px);
|
|
2287
2617
|
height: var(--select-arrow-height, auto);
|
|
2288
2618
|
display: flex;
|
|
2289
2619
|
align-items: center;
|
|
2290
2620
|
justify-content: center;
|
|
2291
2621
|
cursor: pointer;
|
|
2292
|
-
|
|
2293
|
-
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);
|
|
2294
2623
|
z-index: 2;
|
|
2624
|
+
transition: background-color var(--select-transition-fast);
|
|
2295
2625
|
}
|
|
2296
2626
|
|
|
2297
2627
|
.input-container.has-clear-control {
|
|
2298
|
-
padding: var(--select-input-padding-with-clear,
|
|
2628
|
+
padding: var(--select-input-padding-with-clear, 10px 84px 10px 14px);
|
|
2299
2629
|
}
|
|
2300
2630
|
|
|
2301
2631
|
.input-container.has-clear-control::after {
|
|
2302
|
-
right: var(--select-separator-position-with-clear,
|
|
2632
|
+
right: var(--select-separator-position-with-clear, 74px);
|
|
2303
2633
|
}
|
|
2304
2634
|
|
|
2305
2635
|
.dropdown-arrow-container.with-clear-control {
|
|
2306
|
-
right: var(--select-arrow-right-with-clear,
|
|
2636
|
+
right: var(--select-arrow-right-with-clear, 34px);
|
|
2307
2637
|
}
|
|
2308
2638
|
|
|
2639
|
+
/* ─────────────────────────────────────────────────────────────────────────
|
|
2640
|
+
Clear Control — Minimal and elegant dismiss button
|
|
2641
|
+
───────────────────────────────────────────────────────────────────────── */
|
|
2642
|
+
|
|
2309
2643
|
.clear-control-button {
|
|
2310
2644
|
position: absolute;
|
|
2311
2645
|
top: 50%;
|
|
2312
|
-
right: var(--select-clear-button-right,
|
|
2646
|
+
right: var(--select-clear-button-right, 8px);
|
|
2313
2647
|
transform: translateY(-50%);
|
|
2314
|
-
width: var(--select-clear-button-size,
|
|
2315
|
-
height: var(--select-clear-button-size,
|
|
2648
|
+
width: var(--select-clear-button-size, 26px);
|
|
2649
|
+
height: var(--select-clear-button-size, 26px);
|
|
2316
2650
|
border: var(--select-clear-button-border, none);
|
|
2317
|
-
border-radius: var(--select-clear-button-radius,
|
|
2651
|
+
border-radius: var(--select-clear-button-radius, 50%);
|
|
2318
2652
|
background: var(--select-clear-button-bg, transparent);
|
|
2319
|
-
color: var(--select-clear-button-color,
|
|
2653
|
+
color: var(--select-clear-button-color, var(--select-text-muted));
|
|
2320
2654
|
display: inline-flex;
|
|
2321
2655
|
align-items: center;
|
|
2322
2656
|
justify-content: center;
|
|
2323
2657
|
cursor: pointer;
|
|
2324
2658
|
z-index: 3;
|
|
2325
|
-
transition:
|
|
2659
|
+
transition:
|
|
2660
|
+
background var(--select-transition-fast),
|
|
2661
|
+
color var(--select-transition-fast),
|
|
2662
|
+
transform var(--select-transition-bounce);
|
|
2326
2663
|
}
|
|
2327
2664
|
|
|
2328
2665
|
.clear-control-button:hover {
|
|
2329
|
-
background: var(--select-clear-button-hover-bg, rgba(
|
|
2330
|
-
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);
|
|
2331
2673
|
}
|
|
2332
2674
|
|
|
2333
2675
|
.clear-control-button:focus-visible {
|
|
2334
|
-
outline: var(--select-clear-button-focus-outline, 2px solid
|
|
2335
|
-
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);
|
|
2336
2678
|
}
|
|
2337
2679
|
|
|
2338
2680
|
.clear-control-button[hidden] {
|
|
@@ -2340,260 +2682,332 @@
|
|
|
2340
2682
|
}
|
|
2341
2683
|
|
|
2342
2684
|
.clear-control-icon {
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
font-weight: var(--select-clear-icon-weight, 500);
|
|
2685
|
+
width: var(--select-clear-icon-size);
|
|
2686
|
+
height: var(--select-clear-icon-size);
|
|
2346
2687
|
pointer-events: none;
|
|
2347
2688
|
}
|
|
2348
2689
|
|
|
2349
|
-
.
|
|
2350
|
-
|
|
2690
|
+
.clear-control-icon svg {
|
|
2691
|
+
width: 100%;
|
|
2692
|
+
height: 100%;
|
|
2351
2693
|
}
|
|
2352
2694
|
|
|
2353
|
-
.dropdown-arrow:hover {
|
|
2354
|
-
|
|
2355
|
-
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));
|
|
2356
2697
|
}
|
|
2357
2698
|
|
|
2358
2699
|
.dropdown-arrow {
|
|
2359
|
-
width: var(--select-arrow-
|
|
2360
|
-
height: var(--select-arrow-
|
|
2361
|
-
color: var(--select-arrow-color,
|
|
2362
|
-
transition:
|
|
2363
|
-
|
|
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;
|
|
2364
2707
|
}
|
|
2365
2708
|
|
|
2366
2709
|
.dropdown-arrow path {
|
|
2367
|
-
stroke-width: var(--select-arrow-stroke-width,
|
|
2710
|
+
stroke-width: var(--select-arrow-stroke-width, 1.5);
|
|
2368
2711
|
}
|
|
2369
2712
|
|
|
2370
2713
|
.dropdown-arrow-container:hover .dropdown-arrow {
|
|
2371
|
-
color: var(--select-arrow-hover-color,
|
|
2714
|
+
color: var(--select-arrow-hover-color, var(--select-accent));
|
|
2372
2715
|
}
|
|
2373
2716
|
|
|
2374
2717
|
.dropdown-arrow.open {
|
|
2375
|
-
transform:
|
|
2718
|
+
transform: var(--select-arrow-open-transform);
|
|
2376
2719
|
}
|
|
2377
2720
|
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
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);
|
|
2385
2739
|
line-height: var(--select-input-line-height, 1.5);
|
|
2386
|
-
color: var(--select-input-color, var(--select-text
|
|
2387
|
-
background: transparent;
|
|
2740
|
+
color: var(--select-input-color, var(--select-text));
|
|
2741
|
+
background: transparent !important;
|
|
2388
2742
|
box-sizing: border-box;
|
|
2389
|
-
outline: none;
|
|
2390
|
-
font-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
.selection-badge {
|
|
2398
|
-
display: inline-flex;
|
|
2399
|
-
align-items: center;
|
|
2400
|
-
gap: var(--select-badge-gap, 4px);
|
|
2401
|
-
padding: var(--select-badge-padding, 4px 8px);
|
|
2402
|
-
margin: var(--select-badge-margin, 2px);
|
|
2403
|
-
background: var(--select-badge-bg, #667eea);
|
|
2404
|
-
color: var(--select-badge-color, white);
|
|
2405
|
-
border-radius: var(--select-badge-border-radius, 4px);
|
|
2406
|
-
font-size: var(--select-badge-font-size, 13px);
|
|
2407
|
-
line-height: 1;
|
|
2408
|
-
max-width: var(--select-badge-max-width, 100%);
|
|
2409
|
-
white-space: nowrap;
|
|
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;
|
|
2410
2751
|
overflow: hidden;
|
|
2411
2752
|
text-overflow: ellipsis;
|
|
2753
|
+
white-space: nowrap;
|
|
2412
2754
|
}
|
|
2413
2755
|
|
|
2414
|
-
.
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
justify-content: center;
|
|
2418
|
-
width: var(--select-badge-remove-size, 16px);
|
|
2419
|
-
height: var(--select-badge-remove-size, 16px);
|
|
2420
|
-
padding: 0;
|
|
2421
|
-
margin-left: 4px;
|
|
2422
|
-
background: var(--select-badge-remove-bg, rgba(255, 255, 255, 0.3));
|
|
2423
|
-
border: none;
|
|
2424
|
-
border-radius: 50%;
|
|
2425
|
-
color: var(--select-badge-remove-color, white);
|
|
2426
|
-
font-size: var(--select-badge-remove-font-size, 16px);
|
|
2427
|
-
line-height: 1;
|
|
2428
|
-
cursor: pointer;
|
|
2429
|
-
transition: background 0.2s;
|
|
2756
|
+
.select-input::placeholder {
|
|
2757
|
+
color: var(--select-input-placeholder-color, var(--select-text-placeholder));
|
|
2758
|
+
font-weight: 400;
|
|
2430
2759
|
}
|
|
2431
|
-
|
|
2432
|
-
.
|
|
2433
|
-
|
|
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);
|
|
2434
2767
|
}
|
|
2435
2768
|
|
|
2436
|
-
.
|
|
2437
|
-
|
|
2438
|
-
|
|
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;
|
|
2439
2775
|
}
|
|
2440
2776
|
|
|
2441
2777
|
.select-input:disabled {
|
|
2442
2778
|
background-color: var(--select-disabled-bg, #f5f5f5);
|
|
2443
2779
|
cursor: not-allowed;
|
|
2780
|
+
opacity: var(--select-input-disabled-opacity);
|
|
2444
2781
|
}
|
|
2445
2782
|
|
|
2783
|
+
/* ─────────────────────────────────────────────────────────────────────────
|
|
2784
|
+
Dropdown Panel — Elegant floating container
|
|
2785
|
+
───────────────────────────────────────────────────────────────────────── */
|
|
2786
|
+
|
|
2446
2787
|
.select-dropdown {
|
|
2447
2788
|
position: absolute;
|
|
2448
|
-
scroll-behavior:
|
|
2449
|
-
top:
|
|
2789
|
+
scroll-behavior: var(--select-dropdown-scroll-behavior);
|
|
2790
|
+
top: var(--select-dropdown-top);
|
|
2450
2791
|
left: 0;
|
|
2451
2792
|
right: 0;
|
|
2452
|
-
|
|
2453
|
-
max-height: var(--select-dropdown-max-height, 300px);
|
|
2793
|
+
max-height: var(--select-dropdown-max-height, 320px);
|
|
2454
2794
|
overflow: hidden;
|
|
2455
|
-
background: var(--select-dropdown-bg, var(--select-
|
|
2456
|
-
border: 1px solid var(--select-dropdown-border,
|
|
2457
|
-
border-radius: var(--select-dropdown-border-radius,
|
|
2458
|
-
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));
|
|
2459
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
|
+
}
|
|
2460
2813
|
}
|
|
2461
2814
|
|
|
2462
2815
|
.options-container {
|
|
2463
2816
|
position: relative;
|
|
2464
|
-
max-height: var(--select-options-max-height,
|
|
2817
|
+
max-height: var(--select-options-max-height, 320px);
|
|
2465
2818
|
overflow: auto;
|
|
2466
|
-
|
|
2467
|
-
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);
|
|
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);
|
|
2468
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
|
+
───────────────────────────────────────────────────────────────────────── */
|
|
2469
2847
|
|
|
2470
2848
|
.group-header {
|
|
2471
|
-
padding: var(--select-group-header-padding,
|
|
2849
|
+
padding: var(--select-group-header-padding, 10px 12px 6px);
|
|
2472
2850
|
font-weight: var(--select-group-header-weight, 600);
|
|
2473
|
-
color: var(--select-group-header-color,
|
|
2474
|
-
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));
|
|
2475
2853
|
text-align: var(--select-group-header-text-align, left);
|
|
2476
|
-
font-size: var(--select-group-header-font-size,
|
|
2854
|
+
font-size: var(--select-group-header-font-size, 11px);
|
|
2477
2855
|
text-transform: var(--select-group-header-text-transform, uppercase);
|
|
2478
|
-
letter-spacing: var(--select-group-header-letter-spacing, 0.
|
|
2856
|
+
letter-spacing: var(--select-group-header-letter-spacing, 0.08em);
|
|
2479
2857
|
position: sticky;
|
|
2480
2858
|
top: 0;
|
|
2481
2859
|
z-index: 1;
|
|
2482
|
-
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);
|
|
2483
2867
|
}
|
|
2484
2868
|
|
|
2869
|
+
/* ─────────────────────────────────────────────────────────────────────────
|
|
2870
|
+
Options — Elegant hover and selection states
|
|
2871
|
+
───────────────────────────────────────────────────────────────────────── */
|
|
2872
|
+
|
|
2485
2873
|
.option {
|
|
2486
|
-
|
|
2874
|
+
position: relative;
|
|
2875
|
+
padding: var(--select-option-padding, 10px 14px);
|
|
2487
2876
|
cursor: pointer;
|
|
2488
|
-
color: var(--select-option-color, var(--select-text
|
|
2489
|
-
background: var(--select-option-bg,
|
|
2490
|
-
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);
|
|
2491
2884
|
user-select: none;
|
|
2492
2885
|
font-size: var(--select-option-font-size, 14px);
|
|
2886
|
+
font-weight: var(--select-option-font-weight);
|
|
2493
2887
|
line-height: var(--select-option-line-height, 1.5);
|
|
2494
|
-
border: var(--select-option-border,
|
|
2495
|
-
|
|
2496
|
-
border-radius: var(--select-option-border-radius, 0);
|
|
2497
|
-
box-shadow: var(--select-option-shadow, none);
|
|
2498
|
-
transform: var(--select-option-transform, none);
|
|
2888
|
+
border-radius: var(--select-option-border-radius, var(--select-radius-sm));
|
|
2889
|
+
margin: var(--select-option-margin);
|
|
2499
2890
|
}
|
|
2500
2891
|
|
|
2501
2892
|
.option:hover {
|
|
2502
|
-
background: var(--select-option-hover-bg,
|
|
2503
|
-
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);
|
|
2504
2896
|
}
|
|
2505
2897
|
|
|
2506
2898
|
.option.selected {
|
|
2507
|
-
background: var(--select-option-selected-bg,
|
|
2508
|
-
color: var(--select-option-selected-color,
|
|
2509
|
-
font-weight: var(--select-option-selected-weight,
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
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
|
+
}
|
|
2515
2926
|
}
|
|
2516
2927
|
|
|
2517
2928
|
.option.selected:hover {
|
|
2518
|
-
background: var(--select-option-selected-hover-bg,
|
|
2519
|
-
color: var(--select-option-selected-hover-color, var(--select-option-selected-color, #4338ca));
|
|
2520
|
-
border: var(--select-option-selected-hover-border, var(--select-option-selected-border, var(--select-option-border, none)));
|
|
2521
|
-
border-bottom: var(--select-option-selected-hover-border-bottom, var(--select-option-selected-border-bottom, var(--select-option-border-bottom, none)));
|
|
2522
|
-
box-shadow: var(--select-option-selected-hover-shadow, var(--select-option-selected-shadow, var(--select-option-shadow, none)));
|
|
2523
|
-
transform: var(--select-option-selected-hover-transform, var(--select-option-selected-transform, var(--select-option-transform, none)));
|
|
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%));
|
|
2524
2930
|
}
|
|
2525
2931
|
|
|
2526
2932
|
.option.active:not(.selected) {
|
|
2527
|
-
background: var(--select-option-active-bg,
|
|
2528
|
-
|
|
2529
|
-
outline: var(--select-option-active-outline
|
|
2530
|
-
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);
|
|
2531
2936
|
}
|
|
2532
2937
|
|
|
2533
2938
|
.option.selected.active {
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
border: var(--select-option-selected-active-border, var(--select-option-selected-border, var(--select-option-border, none)));
|
|
2537
|
-
border-bottom: var(--select-option-selected-active-border-bottom, var(--select-option-selected-border-bottom, var(--select-option-border-bottom, none)));
|
|
2538
|
-
box-shadow: var(--select-option-selected-active-shadow, var(--select-option-selected-shadow, var(--select-option-shadow, none)));
|
|
2539
|
-
transform: var(--select-option-selected-active-transform, var(--select-option-selected-transform, var(--select-option-transform, none)));
|
|
2540
|
-
outline: var(--select-option-selected-active-outline, var(--select-option-active-outline, 2px solid rgba(99, 102, 241, 0.45)));
|
|
2541
|
-
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);
|
|
2542
2941
|
}
|
|
2543
2942
|
|
|
2544
2943
|
.option:active:not(.selected) {
|
|
2545
|
-
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);
|
|
2546
2946
|
}
|
|
2547
2947
|
|
|
2548
2948
|
.option.selected:active {
|
|
2549
|
-
|
|
2949
|
+
transform: var(--select-option-selected-pressed-transform);
|
|
2550
2950
|
}
|
|
2551
2951
|
|
|
2952
|
+
/* ─────────────────────────────────────────────────────────────────────────
|
|
2953
|
+
Load More & Busy States — Refined feedback indicators
|
|
2954
|
+
───────────────────────────────────────────────────────────────────────── */
|
|
2955
|
+
|
|
2552
2956
|
.load-more-container {
|
|
2553
2957
|
padding: var(--select-load-more-padding, 12px);
|
|
2554
2958
|
text-align: center;
|
|
2555
|
-
border-top: var(--select-divider-border, 1px solid #e0e0e0);
|
|
2556
|
-
background: var(--select-load-more-bg, white);
|
|
2557
2959
|
}
|
|
2558
2960
|
|
|
2559
2961
|
.load-more-button {
|
|
2560
|
-
padding: var(--select-button-padding,
|
|
2561
|
-
border: var(--select-button-border,
|
|
2562
|
-
background: var(--select-button-bg,
|
|
2563
|
-
color: var(--select-button-color,
|
|
2564
|
-
border-radius: var(--select-button-border-radius,
|
|
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));
|
|
2565
2967
|
cursor: pointer;
|
|
2566
|
-
font-size: var(--select-button-font-size,
|
|
2567
|
-
font-
|
|
2568
|
-
|
|
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);
|
|
2569
2976
|
}
|
|
2570
2977
|
|
|
2571
2978
|
.load-more-button:hover {
|
|
2572
|
-
background: var(--select-button-hover-bg,
|
|
2979
|
+
background: var(--select-button-hover-bg, var(--select-accent));
|
|
2980
|
+
border-color: var(--select-accent);
|
|
2573
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);
|
|
2574
2987
|
}
|
|
2575
2988
|
|
|
2576
2989
|
.load-more-button:disabled {
|
|
2577
2990
|
opacity: var(--select-button-disabled-opacity, 0.5);
|
|
2578
2991
|
cursor: not-allowed;
|
|
2992
|
+
transform: none;
|
|
2579
2993
|
}
|
|
2580
2994
|
|
|
2581
2995
|
.busy-bucket {
|
|
2582
|
-
padding: var(--select-busy-padding,
|
|
2996
|
+
padding: var(--select-busy-padding, 20px);
|
|
2583
2997
|
text-align: center;
|
|
2584
|
-
color: var(--select-busy-color,
|
|
2585
|
-
background: var(--select-busy-bg,
|
|
2586
|
-
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);
|
|
2587
3001
|
}
|
|
2588
3002
|
|
|
2589
3003
|
.spinner {
|
|
2590
3004
|
display: inline-block;
|
|
2591
|
-
width: var(--select-spinner-size,
|
|
2592
|
-
height: var(--select-spinner-size,
|
|
2593
|
-
border: var(--select-spinner-border, 2px solid
|
|
2594
|
-
border-top-color: var(--select-spinner-active-color,
|
|
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));
|
|
2595
3009
|
border-radius: 50%;
|
|
2596
|
-
animation:
|
|
3010
|
+
animation: var(--select-spinner-animation);
|
|
2597
3011
|
}
|
|
2598
3012
|
|
|
2599
3013
|
@keyframes spin {
|
|
@@ -2601,61 +3015,97 @@
|
|
|
2601
3015
|
}
|
|
2602
3016
|
|
|
2603
3017
|
.empty-state {
|
|
2604
|
-
padding: var(--select-empty-padding, 24px);
|
|
3018
|
+
padding: var(--select-empty-padding, 32px 24px);
|
|
2605
3019
|
text-align: center;
|
|
2606
|
-
color: var(--select-empty-color,
|
|
3020
|
+
color: var(--select-empty-color, var(--select-text-muted));
|
|
2607
3021
|
font-size: var(--select-empty-font-size, 14px);
|
|
2608
|
-
background: var(--select-empty-bg,
|
|
3022
|
+
background: var(--select-empty-bg, transparent);
|
|
2609
3023
|
display: flex;
|
|
2610
3024
|
flex-direction: column;
|
|
2611
3025
|
align-items: center;
|
|
2612
3026
|
justify-content: center;
|
|
2613
|
-
gap:
|
|
2614
|
-
min-height: var(--select-empty-min-height, 72px);
|
|
3027
|
+
gap: var(--select-empty-gap);
|
|
2615
3028
|
}
|
|
2616
3029
|
|
|
2617
3030
|
.searching-state {
|
|
2618
|
-
padding: var(--select-searching-padding, 24px);
|
|
3031
|
+
padding: var(--select-searching-padding, 32px 24px);
|
|
2619
3032
|
text-align: center;
|
|
2620
|
-
color: var(--select-searching-color,
|
|
3033
|
+
color: var(--select-searching-color, var(--select-accent));
|
|
2621
3034
|
font-size: var(--select-searching-font-size, 14px);
|
|
2622
|
-
|
|
2623
|
-
background: var(--select-searching-bg, white);
|
|
2624
|
-
animation: pulse 1.5s ease-in-out infinite;
|
|
3035
|
+
background: var(--select-searching-bg, transparent);
|
|
2625
3036
|
display: flex;
|
|
2626
3037
|
flex-direction: column;
|
|
2627
3038
|
align-items: center;
|
|
2628
3039
|
justify-content: center;
|
|
2629
|
-
gap:
|
|
2630
|
-
min-height: var(--select-searching-min-height, 72px);
|
|
3040
|
+
gap: var(--select-searching-gap);
|
|
2631
3041
|
}
|
|
2632
3042
|
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
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);
|
|
2636
3051
|
}
|
|
2637
3052
|
|
|
2638
|
-
/*
|
|
3053
|
+
/* ─────────────────────────────────────────────────────────────────────────
|
|
3054
|
+
Error States — Clear visual feedback
|
|
3055
|
+
───────────────────────────────────────────────────────────────────────── */
|
|
3056
|
+
|
|
2639
3057
|
.select-input[aria-invalid="true"] {
|
|
2640
|
-
border-color: var(--select-error-border, #
|
|
3058
|
+
border-color: var(--select-error-border, #e94560);
|
|
2641
3059
|
}
|
|
2642
3060
|
|
|
2643
3061
|
.select-input[aria-invalid="true"]:focus {
|
|
2644
|
-
border-color: var(--select-error-border, #
|
|
2645
|
-
box-shadow: 0 0 0
|
|
2646
|
-
outline-color: var(--select-error-border, #dc2626);
|
|
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));
|
|
2647
3064
|
}
|
|
2648
3065
|
|
|
2649
|
-
/*
|
|
3066
|
+
/* ──────────────────────────────────────────────────��──────────────────────
|
|
3067
|
+
Accessibility — Reduced motion & High contrast
|
|
3068
|
+
───────────────────────────────────────────────────────────────────────── */
|
|
3069
|
+
|
|
2650
3070
|
@media (prefers-reduced-motion: reduce) {
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
|
|
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);
|
|
2655
3081
|
}
|
|
2656
3082
|
}
|
|
2657
3083
|
|
|
2658
|
-
|
|
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);
|
|
3096
|
+
}
|
|
3097
|
+
}
|
|
3098
|
+
|
|
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
|
+
|
|
2659
3109
|
:host(.dark-mode),
|
|
2660
3110
|
:host([dark-mode]),
|
|
2661
3111
|
:host([darkmode]),
|
|
@@ -2667,139 +3117,129 @@
|
|
|
2667
3117
|
:host-context([darkmode]),
|
|
2668
3118
|
:host-context([data-theme="dark"]),
|
|
2669
3119
|
:host-context([theme="dark"]) {
|
|
2670
|
-
|
|
2671
|
-
|
|
2672
|
-
--select-
|
|
2673
|
-
--select-
|
|
2674
|
-
--select-
|
|
2675
|
-
--select-
|
|
2676
|
-
--select-
|
|
2677
|
-
--select-
|
|
2678
|
-
|
|
2679
|
-
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
|
|
2685
|
-
color: var(--select-dark-text, #f9fafb);
|
|
2686
|
-
}
|
|
2687
|
-
|
|
2688
|
-
.select-input::placeholder {
|
|
2689
|
-
color: var(--select-dark-placeholder, #6b7280);
|
|
2690
|
-
}
|
|
2691
|
-
|
|
2692
|
-
.select-dropdown {
|
|
2693
|
-
background: var(--select-dark-dropdown-bg, #1f2937);
|
|
2694
|
-
border-color: var(--select-dark-dropdown-border, #4b5563);
|
|
2695
|
-
}
|
|
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);
|
|
2696
3135
|
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
}
|
|
2705
|
-
|
|
2706
|
-
.option:hover {
|
|
2707
|
-
background: var(--select-dark-option-hover-bg, #374151);
|
|
2708
|
-
color: var(--select-dark-option-hover-color, #f9fafb);
|
|
2709
|
-
}
|
|
2710
|
-
|
|
2711
|
-
.option.selected {
|
|
2712
|
-
background: var(--select-dark-option-selected-bg, #3730a3);
|
|
2713
|
-
color: var(--select-dark-option-selected-text, #e0e7ff);
|
|
2714
|
-
border: var(--select-dark-option-selected-border, var(--select-option-selected-border, var(--select-option-border, none)));
|
|
2715
|
-
border-bottom: var(--select-dark-option-selected-border-bottom, var(--select-option-selected-border-bottom, var(--select-option-border-bottom, none)));
|
|
2716
|
-
box-shadow: var(--select-dark-option-selected-shadow, var(--select-option-selected-shadow, var(--select-option-shadow, none)));
|
|
2717
|
-
transform: var(--select-dark-option-selected-transform, var(--select-option-selected-transform, var(--select-option-transform, none)));
|
|
2718
|
-
}
|
|
2719
|
-
|
|
2720
|
-
.option.selected:hover {
|
|
2721
|
-
background: var(--select-dark-option-selected-hover-bg, var(--select-dark-option-selected-bg, #3730a3));
|
|
2722
|
-
color: var(--select-dark-option-selected-hover-color, var(--select-dark-option-selected-text, #e0e7ff));
|
|
2723
|
-
border: var(--select-dark-option-selected-hover-border, var(--select-dark-option-selected-border, var(--select-option-selected-hover-border, var(--select-option-selected-border, var(--select-option-border, none)))));
|
|
2724
|
-
border-bottom: var(--select-dark-option-selected-hover-border-bottom, var(--select-dark-option-selected-border-bottom, var(--select-option-selected-hover-border-bottom, var(--select-option-selected-border-bottom, var(--select-option-border-bottom, none)))));
|
|
2725
|
-
box-shadow: var(--select-dark-option-selected-hover-shadow, var(--select-dark-option-selected-shadow, var(--select-option-selected-hover-shadow, var(--select-option-selected-shadow, var(--select-option-shadow, none)))));
|
|
2726
|
-
transform: var(--select-dark-option-selected-hover-transform, var(--select-dark-option-selected-transform, var(--select-option-selected-hover-transform, var(--select-option-selected-transform, var(--select-option-transform, none)))));
|
|
2727
|
-
}
|
|
2728
|
-
|
|
2729
|
-
.option.active:not(.selected) {
|
|
2730
|
-
background-color: var(--select-dark-option-active-bg, #374151);
|
|
2731
|
-
color: var(--select-dark-option-active-color, #f9fafb);
|
|
2732
|
-
outline: var(--select-dark-option-active-outline, 2px solid rgba(129, 140, 248, 0.55));
|
|
2733
|
-
}
|
|
2734
|
-
|
|
2735
|
-
/* Group header in dark mode */
|
|
2736
|
-
.group-header {
|
|
2737
|
-
color: var(--select-dark-group-header-color, var(--select-group-header-color, #6b7280));
|
|
2738
|
-
background-color: var(--select-dark-group-header-bg, var(--select-group-header-bg, #374151));
|
|
2739
|
-
}
|
|
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
|
+
}
|
|
2740
3143
|
|
|
2741
|
-
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
|
|
2750
|
-
|
|
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
|
+
}
|
|
2751
3158
|
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
|
|
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
|
+
}
|
|
2756
3172
|
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
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
|
+
}
|
|
2761
3187
|
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
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
|
+
}
|
|
2771
3202
|
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
|
|
2781
|
-
|
|
2782
|
-
|
|
2783
|
-
|
|
2784
|
-
}
|
|
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);
|
|
2785
3215
|
}
|
|
2786
|
-
|
|
2787
|
-
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
|
|
2791
|
-
|
|
2792
|
-
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
|
|
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);
|
|
2797
3229
|
}
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
.
|
|
2801
|
-
|
|
2802
|
-
|
|
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);
|
|
2803
3243
|
}
|
|
2804
3244
|
`;
|
|
2805
3245
|
// Insert as first child to ensure styles are processed first
|
|
@@ -2819,10 +3259,10 @@
|
|
|
2819
3259
|
// delegate to the existing open/close helpers so we don't accidentally
|
|
2820
3260
|
// drift out of sync with the logic in those methods (focus, events,
|
|
2821
3261
|
// scroll-to-selected, etc.)
|
|
2822
|
-
if (this._state.isOpen) {
|
|
3262
|
+
if (this._state.isOpen && this._config.selection.toggleOnTriggerClick !== false) {
|
|
2823
3263
|
this._handleClose();
|
|
2824
3264
|
}
|
|
2825
|
-
else {
|
|
3265
|
+
else if (!this._state.isOpen) {
|
|
2826
3266
|
this._handleOpen();
|
|
2827
3267
|
}
|
|
2828
3268
|
};
|
|
@@ -2845,7 +3285,7 @@
|
|
|
2845
3285
|
this._inputContainer.addEventListener('pointerdown', (e) => {
|
|
2846
3286
|
// Prevent propagation to document click listener but do NOT preventDefault.
|
|
2847
3287
|
// Allow default so browser events (click) on newly opened options still fire.
|
|
2848
|
-
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.
|
|
2849
3289
|
const target = e.target;
|
|
2850
3290
|
if (!this._config.enabled)
|
|
2851
3291
|
return;
|
|
@@ -2853,21 +3293,23 @@
|
|
|
2853
3293
|
return;
|
|
2854
3294
|
if (target && target.closest('.clear-control-button'))
|
|
2855
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
|
+
}
|
|
2856
3308
|
const wasClosed = !this._state.isOpen;
|
|
2857
3309
|
if (wasClosed) {
|
|
2858
3310
|
this._handleOpen();
|
|
2859
3311
|
}
|
|
2860
|
-
|
|
2861
|
-
// Keep open while interacting directly with the input so users can
|
|
2862
|
-
// place cursor/type without accidental collapse.
|
|
2863
|
-
if (target === this._input) {
|
|
2864
|
-
this._input.focus();
|
|
2865
|
-
return;
|
|
2866
|
-
}
|
|
2867
|
-
// clicking other parts of the input container while open toggles close
|
|
2868
|
-
this._handleClose();
|
|
2869
|
-
}
|
|
2870
|
-
// Focus the input (do not prevent default behavior)
|
|
3312
|
+
// Focus the input (do not prevent default behavior for input itself)
|
|
2871
3313
|
this._input.focus();
|
|
2872
3314
|
// If we just opened the dropdown, transfer pointer capture to the
|
|
2873
3315
|
// options container so the subsequent pointerup lands there instead of
|
|
@@ -2909,7 +3351,7 @@
|
|
|
2909
3351
|
return;
|
|
2910
3352
|
}
|
|
2911
3353
|
this._handleClose();
|
|
2912
|
-
},
|
|
3354
|
+
}, 150);
|
|
2913
3355
|
});
|
|
2914
3356
|
// Input search
|
|
2915
3357
|
this._input.addEventListener('input', (e) => {
|
|
@@ -2926,7 +3368,7 @@
|
|
|
2926
3368
|
this._suppressBlurClose = true;
|
|
2927
3369
|
setTimeout(() => {
|
|
2928
3370
|
this._suppressBlurClose = false;
|
|
2929
|
-
},
|
|
3371
|
+
}, 150); // Increased timeout to ensure click finishes before blur checks
|
|
2930
3372
|
});
|
|
2931
3373
|
// Delegated click listener for improved event handling (robust across shadow DOM)
|
|
2932
3374
|
const handleOptionEvent = (e) => {
|
|
@@ -2957,9 +3399,6 @@
|
|
|
2957
3399
|
}
|
|
2958
3400
|
};
|
|
2959
3401
|
this._optionsContainer.addEventListener('click', handleOptionEvent);
|
|
2960
|
-
// also watch pointerup to catch cases where the pointerdown started outside
|
|
2961
|
-
// (e.g. on the input) and the click never fires
|
|
2962
|
-
this._optionsContainer.addEventListener('pointerup', handleOptionEvent);
|
|
2963
3402
|
// Keyboard navigation
|
|
2964
3403
|
this._input.addEventListener('keydown', (e) => this._handleKeydown(e));
|
|
2965
3404
|
// Click outside to close — robust detection across shadow DOM and custom renderers
|
|
@@ -3057,17 +3496,6 @@
|
|
|
3057
3496
|
this._dropdown.style.display = 'block';
|
|
3058
3497
|
this._input.setAttribute('aria-expanded', 'true');
|
|
3059
3498
|
this._updateArrowRotation();
|
|
3060
|
-
// Clear search query when opening to show all options
|
|
3061
|
-
// This ensures we can scroll to selected item
|
|
3062
|
-
if (this._config.searchable) {
|
|
3063
|
-
this._state.searchQuery = '';
|
|
3064
|
-
// Don't clear input value if it represents selection
|
|
3065
|
-
// But if we want to search, we might want to clear it?
|
|
3066
|
-
// Standard behavior: input keeps value (label), but dropdown shows all options
|
|
3067
|
-
// until user types.
|
|
3068
|
-
// However, our filtering logic uses _state.searchQuery.
|
|
3069
|
-
// So clearing it here resets the filter.
|
|
3070
|
-
}
|
|
3071
3499
|
// Render options when opening
|
|
3072
3500
|
this._renderOptions();
|
|
3073
3501
|
this._setInitialActiveOption();
|
|
@@ -3313,24 +3741,24 @@
|
|
|
3313
3741
|
}
|
|
3314
3742
|
}
|
|
3315
3743
|
_setActive(index) {
|
|
3316
|
-
const options = Array.from(this._optionsContainer.children);
|
|
3317
3744
|
// Clear previous active state
|
|
3318
|
-
if (this._state.activeIndex >= 0
|
|
3319
|
-
const prevOption =
|
|
3320
|
-
|
|
3321
|
-
|
|
3322
|
-
prevOption.setActive
|
|
3323
|
-
|
|
3324
|
-
|
|
3325
|
-
|
|
3326
|
-
|
|
3327
|
-
|
|
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
|
+
}
|
|
3328
3756
|
}
|
|
3329
3757
|
}
|
|
3330
3758
|
this._state.activeIndex = index;
|
|
3331
3759
|
// Set new active state
|
|
3332
|
-
|
|
3333
|
-
|
|
3760
|
+
const option = this._getOptionElementByIndex(index);
|
|
3761
|
+
if (option) {
|
|
3334
3762
|
// Check if it's a custom SelectOption or a lightweight DOM element
|
|
3335
3763
|
if ('setActive' in option && typeof option.setActive === 'function') {
|
|
3336
3764
|
option.setActive(true);
|
|
@@ -3338,13 +3766,13 @@
|
|
|
3338
3766
|
else {
|
|
3339
3767
|
// Lightweight option - add active class
|
|
3340
3768
|
option.classList.add('smilodon-option--active');
|
|
3341
|
-
option.setAttribute('aria-selected', 'true');
|
|
3342
3769
|
}
|
|
3343
3770
|
if (typeof option.scrollIntoView === 'function') {
|
|
3771
|
+
// Don't scroll wildly when just opening with pre-selections
|
|
3344
3772
|
option.scrollIntoView({ block: 'nearest', behavior: 'smooth' });
|
|
3345
3773
|
}
|
|
3346
3774
|
// Announce position for screen readers
|
|
3347
|
-
const total =
|
|
3775
|
+
const total = this._state.loadedItems.length;
|
|
3348
3776
|
this._announce(`Item ${index + 1} of ${total}`);
|
|
3349
3777
|
// Update aria-activedescendant using the actual option id when available
|
|
3350
3778
|
const optionId = option.id || `${this._uniqueId}-option-${index}`;
|
|
@@ -3467,9 +3895,9 @@
|
|
|
3467
3895
|
// FIX: Do not rely on this._optionsContainer.children[index] because filtering changes the children
|
|
3468
3896
|
// Instead, use the index to update state directly
|
|
3469
3897
|
const item = this._state.loadedItems[index];
|
|
3470
|
-
|
|
3471
|
-
if (!item)
|
|
3898
|
+
if (!item) {
|
|
3472
3899
|
return;
|
|
3900
|
+
}
|
|
3473
3901
|
const isCurrentlySelected = this._state.selectedIndices.has(index);
|
|
3474
3902
|
// Keep active/focus styling aligned with the most recently interacted option.
|
|
3475
3903
|
// Without this, a previously selected item may retain active classes/styles
|
|
@@ -3480,7 +3908,7 @@
|
|
|
3480
3908
|
const wasSelected = this._state.selectedIndices.has(index);
|
|
3481
3909
|
this._state.selectedIndices.clear();
|
|
3482
3910
|
this._state.selectedItems.clear();
|
|
3483
|
-
if (!wasSelected) {
|
|
3911
|
+
if (!wasSelected || !this._config.selection.allowDeselect) {
|
|
3484
3912
|
// Select this option
|
|
3485
3913
|
this._state.selectedIndices.add(index);
|
|
3486
3914
|
this._state.selectedItems.set(index, item);
|
|
@@ -3542,16 +3970,34 @@
|
|
|
3542
3970
|
});
|
|
3543
3971
|
}
|
|
3544
3972
|
_handleOptionRemove(index) {
|
|
3973
|
+
const item = this._state.selectedItems.get(index);
|
|
3545
3974
|
const option = this._getOptionElementByIndex(index);
|
|
3546
|
-
if (!option)
|
|
3547
|
-
return;
|
|
3548
3975
|
this._state.selectedIndices.delete(index);
|
|
3549
3976
|
this._state.selectedItems.delete(index);
|
|
3550
|
-
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
|
+
}
|
|
3551
3994
|
this._updateInputDisplay();
|
|
3995
|
+
this._renderOptions();
|
|
3552
3996
|
this._emitChange();
|
|
3553
|
-
const config = option.getConfig
|
|
3554
|
-
|
|
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 });
|
|
3555
4001
|
}
|
|
3556
4002
|
_updateInputDisplay() {
|
|
3557
4003
|
const selectedItems = Array.from(this._state.selectedItems.values());
|
|
@@ -3579,22 +4025,29 @@
|
|
|
3579
4025
|
const badge = document.createElement('span');
|
|
3580
4026
|
badge.className = 'selection-badge';
|
|
3581
4027
|
badge.setAttribute('part', 'chip');
|
|
3582
|
-
|
|
4028
|
+
const badgeLabel = document.createElement('span');
|
|
4029
|
+
badgeLabel.className = 'selection-badge-label';
|
|
4030
|
+
badgeLabel.textContent = getLabel(item);
|
|
4031
|
+
badge.appendChild(badgeLabel);
|
|
3583
4032
|
// Add remove button to badge
|
|
3584
|
-
|
|
3585
|
-
|
|
3586
|
-
|
|
3587
|
-
|
|
3588
|
-
|
|
3589
|
-
|
|
3590
|
-
|
|
3591
|
-
|
|
3592
|
-
|
|
3593
|
-
|
|
3594
|
-
|
|
3595
|
-
|
|
3596
|
-
|
|
3597
|
-
|
|
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
|
+
}
|
|
3598
4051
|
this._inputContainer.insertBefore(badge, this._input);
|
|
3599
4052
|
});
|
|
3600
4053
|
}
|
|
@@ -3646,10 +4099,12 @@
|
|
|
3646
4099
|
const option = this._getOptionElementByIndex(targetIndex);
|
|
3647
4100
|
if (option) {
|
|
3648
4101
|
// Use smooth scrolling with center alignment for better UX
|
|
3649
|
-
option.scrollIntoView
|
|
3650
|
-
|
|
3651
|
-
|
|
3652
|
-
|
|
4102
|
+
if (typeof option.scrollIntoView === 'function') {
|
|
4103
|
+
option.scrollIntoView({
|
|
4104
|
+
block: this._config.scrollToSelected.block || 'center',
|
|
4105
|
+
behavior: 'smooth',
|
|
4106
|
+
});
|
|
4107
|
+
}
|
|
3653
4108
|
// Also set it as active for keyboard navigation
|
|
3654
4109
|
this._setActive(targetIndex);
|
|
3655
4110
|
}
|
|
@@ -3861,7 +4316,6 @@
|
|
|
3861
4316
|
const getValue = this._config.serverSide.getValueFromItem || ((item) => item?.value ?? item);
|
|
3862
4317
|
const selectedValues = selectedItems.map(getValue);
|
|
3863
4318
|
const selectedIndices = Array.from(this._state.selectedIndices);
|
|
3864
|
-
// Debug: log change payload
|
|
3865
4319
|
this._emit('change', { selectedItems, selectedValues, selectedIndices });
|
|
3866
4320
|
this._config.callbacks.onChange?.(selectedItems, selectedValues);
|
|
3867
4321
|
}
|
|
@@ -4065,7 +4519,7 @@
|
|
|
4065
4519
|
this._clearControl.setAttribute('aria-label', this._config.clearControl.ariaLabel || 'Clear selection and search');
|
|
4066
4520
|
}
|
|
4067
4521
|
if (this._clearControlIcon) {
|
|
4068
|
-
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>`;
|
|
4069
4523
|
}
|
|
4070
4524
|
if (this._dropdown) {
|
|
4071
4525
|
if (this._config.selection.mode === 'multi') {
|
|
@@ -4075,6 +4529,7 @@
|
|
|
4075
4529
|
this._dropdown.removeAttribute('aria-multiselectable');
|
|
4076
4530
|
}
|
|
4077
4531
|
}
|
|
4532
|
+
this._syncInputContainerMode();
|
|
4078
4533
|
// Re-initialize observers in case infinite scroll was enabled/disabled
|
|
4079
4534
|
this._initializeObservers();
|
|
4080
4535
|
this._syncClearControlState();
|
|
@@ -4180,6 +4635,8 @@
|
|
|
4180
4635
|
* Render options based on current state
|
|
4181
4636
|
*/
|
|
4182
4637
|
_renderOptions() {
|
|
4638
|
+
this._renderCycleId += 1;
|
|
4639
|
+
const renderCycleId = this._renderCycleId;
|
|
4183
4640
|
// Cleanup observer
|
|
4184
4641
|
if (this._loadMoreTrigger && this._intersectionObserver) {
|
|
4185
4642
|
this._intersectionObserver.unobserve(this._loadMoreTrigger);
|
|
@@ -4244,23 +4701,21 @@
|
|
|
4244
4701
|
}
|
|
4245
4702
|
else {
|
|
4246
4703
|
// Normal rendering (flat list or filtered)
|
|
4247
|
-
|
|
4704
|
+
const filteredIndices = [];
|
|
4248
4705
|
this._state.loadedItems.forEach((item, index) => {
|
|
4249
|
-
// Apply filter if query exists
|
|
4250
4706
|
if (query) {
|
|
4251
4707
|
try {
|
|
4252
4708
|
const label = String(getLabel(item)).toLowerCase();
|
|
4253
4709
|
if (!label.includes(query))
|
|
4254
4710
|
return;
|
|
4255
4711
|
}
|
|
4256
|
-
catch (
|
|
4712
|
+
catch (_e) {
|
|
4257
4713
|
return;
|
|
4258
4714
|
}
|
|
4259
4715
|
}
|
|
4260
|
-
|
|
4261
|
-
this._renderSingleOption(item, index, getValue, getLabel);
|
|
4716
|
+
filteredIndices.push(index);
|
|
4262
4717
|
});
|
|
4263
|
-
if (
|
|
4718
|
+
if (filteredIndices.length === 0 && !this._state.isBusy) {
|
|
4264
4719
|
const empty = document.createElement('div');
|
|
4265
4720
|
empty.setAttribute('part', 'no-results');
|
|
4266
4721
|
empty.className = 'empty-state';
|
|
@@ -4272,6 +4727,54 @@
|
|
|
4272
4727
|
}
|
|
4273
4728
|
this._optionsContainer.appendChild(empty);
|
|
4274
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
|
+
}
|
|
4275
4778
|
}
|
|
4276
4779
|
// Append Busy Indicator if busy
|
|
4277
4780
|
if (this._state.isBusy && this._config.busyBucket.enabled) {
|
|
@@ -4296,7 +4799,7 @@
|
|
|
4296
4799
|
}
|
|
4297
4800
|
this._finalizePerfMarks();
|
|
4298
4801
|
}
|
|
4299
|
-
_renderSingleOption(item, index, getValue, getLabel) {
|
|
4802
|
+
_renderSingleOption(item, index, getValue, getLabel, targetContainer = this._optionsContainer) {
|
|
4300
4803
|
const isSelected = this._state.selectedIndices.has(index);
|
|
4301
4804
|
const isDisabled = Boolean(item?.disabled);
|
|
4302
4805
|
const optionId = `${this._uniqueId}-option-${index}`;
|
|
@@ -4312,7 +4815,7 @@
|
|
|
4312
4815
|
disabled: isDisabled,
|
|
4313
4816
|
id: optionId,
|
|
4314
4817
|
});
|
|
4315
|
-
|
|
4818
|
+
targetContainer.appendChild(optionElement);
|
|
4316
4819
|
return;
|
|
4317
4820
|
}
|
|
4318
4821
|
const option = new SelectOption({
|
|
@@ -4341,20 +4844,16 @@
|
|
|
4341
4844
|
option.dataset.smValue = String(val);
|
|
4342
4845
|
}
|
|
4343
4846
|
option.id = option.id || optionId;
|
|
4344
|
-
|
|
4345
|
-
|
|
4346
|
-
|
|
4347
|
-
|
|
4348
|
-
shiftKey: mouseEvent.shiftKey,
|
|
4349
|
-
toggleKey: mouseEvent.ctrlKey || mouseEvent.metaKey,
|
|
4350
|
-
});
|
|
4351
|
-
});
|
|
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!
|
|
4352
4851
|
option.addEventListener('optionRemove', (event) => {
|
|
4353
4852
|
const detail = event.detail;
|
|
4354
4853
|
const targetIndex = detail?.index ?? index;
|
|
4355
4854
|
this._handleOptionRemove(targetIndex);
|
|
4356
4855
|
});
|
|
4357
|
-
|
|
4856
|
+
targetContainer.appendChild(option);
|
|
4358
4857
|
}
|
|
4359
4858
|
_normalizeCustomOptionElement(element, meta) {
|
|
4360
4859
|
const optionEl = element instanceof HTMLElement ? element : document.createElement('div');
|
|
@@ -4441,35 +4940,9 @@
|
|
|
4441
4940
|
optionEl.tabIndex = -1;
|
|
4442
4941
|
}
|
|
4443
4942
|
if (!this._customOptionBoundElements.has(optionEl)) {
|
|
4444
|
-
|
|
4445
|
-
|
|
4446
|
-
|
|
4447
|
-
if (current.getAttribute('aria-disabled') === 'true')
|
|
4448
|
-
return;
|
|
4449
|
-
const parsedIndex = Number(current.dataset.index);
|
|
4450
|
-
if (!Number.isFinite(parsedIndex))
|
|
4451
|
-
return;
|
|
4452
|
-
const mouseEvent = e;
|
|
4453
|
-
this._selectOption(parsedIndex, {
|
|
4454
|
-
shiftKey: mouseEvent.shiftKey,
|
|
4455
|
-
toggleKey: mouseEvent.ctrlKey || mouseEvent.metaKey,
|
|
4456
|
-
});
|
|
4457
|
-
});
|
|
4458
|
-
optionEl.addEventListener('keydown', (e) => {
|
|
4459
|
-
if (e.key !== 'Enter' && e.key !== ' ')
|
|
4460
|
-
return;
|
|
4461
|
-
const current = e.currentTarget;
|
|
4462
|
-
if (current.getAttribute('aria-disabled') === 'true')
|
|
4463
|
-
return;
|
|
4464
|
-
const parsedIndex = Number(current.dataset.index);
|
|
4465
|
-
if (!Number.isFinite(parsedIndex))
|
|
4466
|
-
return;
|
|
4467
|
-
e.preventDefault();
|
|
4468
|
-
this._selectOption(parsedIndex, {
|
|
4469
|
-
shiftKey: e.shiftKey,
|
|
4470
|
-
toggleKey: e.ctrlKey || e.metaKey,
|
|
4471
|
-
});
|
|
4472
|
-
});
|
|
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.
|
|
4473
4946
|
this._customOptionBoundElements.add(optionEl);
|
|
4474
4947
|
}
|
|
4475
4948
|
return optionEl;
|