@smilodon/core 1.4.4 → 1.4.5
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 +25 -0
- package/dist/index.cjs +194 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +194 -5
- 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 +194 -5
- 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 +9 -0
- package/dist/types/src/config/global-config.d.ts +21 -0
- package/dist/types/src/index.d.ts +1 -1
- package/dist/types/src/types.d.ts +5 -0
- package/dist/types/src/utils/csp-styles.d.ts +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1392,6 +1392,14 @@ const defaultConfig = {
|
|
|
1392
1392
|
expandLabel: 'Show more',
|
|
1393
1393
|
collapseLabel: 'Show less',
|
|
1394
1394
|
},
|
|
1395
|
+
clearControl: {
|
|
1396
|
+
enabled: false,
|
|
1397
|
+
clearSelection: true,
|
|
1398
|
+
clearSearch: true,
|
|
1399
|
+
hideWhenEmpty: true,
|
|
1400
|
+
ariaLabel: 'Clear selection and search',
|
|
1401
|
+
icon: '×',
|
|
1402
|
+
},
|
|
1395
1403
|
callbacks: {},
|
|
1396
1404
|
enabled: true,
|
|
1397
1405
|
searchable: false,
|
|
@@ -1888,6 +1896,7 @@ class EnhancedSelect extends HTMLElement {
|
|
|
1888
1896
|
this._inputContainer = this._createInputContainer();
|
|
1889
1897
|
this._input = this._createInput();
|
|
1890
1898
|
this._arrowContainer = this._createArrowContainer();
|
|
1899
|
+
this._clearControl = this._createClearControl();
|
|
1891
1900
|
this._dropdown = this._createDropdown();
|
|
1892
1901
|
this._optionsContainer = this._createOptionsContainer();
|
|
1893
1902
|
this._liveRegion = this._createLiveRegion();
|
|
@@ -2101,8 +2110,25 @@ class EnhancedSelect extends HTMLElement {
|
|
|
2101
2110
|
`;
|
|
2102
2111
|
return container;
|
|
2103
2112
|
}
|
|
2113
|
+
_createClearControl() {
|
|
2114
|
+
const button = document.createElement('button');
|
|
2115
|
+
button.type = 'button';
|
|
2116
|
+
button.className = 'clear-control-button';
|
|
2117
|
+
button.setAttribute('part', 'clear-button');
|
|
2118
|
+
const icon = document.createElement('span');
|
|
2119
|
+
icon.className = 'clear-control-icon';
|
|
2120
|
+
icon.setAttribute('part', 'clear-icon');
|
|
2121
|
+
icon.textContent = this._config.clearControl.icon || '×';
|
|
2122
|
+
button.setAttribute('aria-label', this._config.clearControl.ariaLabel || 'Clear selection and search');
|
|
2123
|
+
button.appendChild(icon);
|
|
2124
|
+
this._clearControlIcon = icon;
|
|
2125
|
+
return button;
|
|
2126
|
+
}
|
|
2104
2127
|
_assembleDOM() {
|
|
2105
2128
|
this._inputContainer.appendChild(this._input);
|
|
2129
|
+
if (this._clearControl) {
|
|
2130
|
+
this._inputContainer.appendChild(this._clearControl);
|
|
2131
|
+
}
|
|
2106
2132
|
if (this._arrowContainer) {
|
|
2107
2133
|
this._inputContainer.appendChild(this._arrowContainer);
|
|
2108
2134
|
}
|
|
@@ -2118,6 +2144,7 @@ class EnhancedSelect extends HTMLElement {
|
|
|
2118
2144
|
this._dropdown.id = listboxId;
|
|
2119
2145
|
this._input.setAttribute('aria-controls', listboxId);
|
|
2120
2146
|
this._input.setAttribute('aria-owns', listboxId);
|
|
2147
|
+
this._syncClearControlState();
|
|
2121
2148
|
}
|
|
2122
2149
|
_initializeStyles() {
|
|
2123
2150
|
const style = document.createElement('style');
|
|
@@ -2191,6 +2218,58 @@ class EnhancedSelect extends HTMLElement {
|
|
|
2191
2218
|
border-radius: var(--select-arrow-border-radius, 0 4px 4px 0);
|
|
2192
2219
|
z-index: 2;
|
|
2193
2220
|
}
|
|
2221
|
+
|
|
2222
|
+
.input-container.has-clear-control {
|
|
2223
|
+
padding: var(--select-input-padding-with-clear, 6px 84px 6px 8px);
|
|
2224
|
+
}
|
|
2225
|
+
|
|
2226
|
+
.input-container.has-clear-control::after {
|
|
2227
|
+
right: var(--select-separator-position-with-clear, 72px);
|
|
2228
|
+
}
|
|
2229
|
+
|
|
2230
|
+
.dropdown-arrow-container.with-clear-control {
|
|
2231
|
+
right: var(--select-arrow-right-with-clear, 32px);
|
|
2232
|
+
}
|
|
2233
|
+
|
|
2234
|
+
.clear-control-button {
|
|
2235
|
+
position: absolute;
|
|
2236
|
+
top: 50%;
|
|
2237
|
+
right: var(--select-clear-button-right, 6px);
|
|
2238
|
+
transform: translateY(-50%);
|
|
2239
|
+
width: var(--select-clear-button-size, 24px);
|
|
2240
|
+
height: var(--select-clear-button-size, 24px);
|
|
2241
|
+
border: var(--select-clear-button-border, none);
|
|
2242
|
+
border-radius: var(--select-clear-button-radius, 999px);
|
|
2243
|
+
background: var(--select-clear-button-bg, transparent);
|
|
2244
|
+
color: var(--select-clear-button-color, #6b7280);
|
|
2245
|
+
display: inline-flex;
|
|
2246
|
+
align-items: center;
|
|
2247
|
+
justify-content: center;
|
|
2248
|
+
cursor: pointer;
|
|
2249
|
+
z-index: 3;
|
|
2250
|
+
transition: var(--select-clear-button-transition, all 0.2s ease);
|
|
2251
|
+
}
|
|
2252
|
+
|
|
2253
|
+
.clear-control-button:hover {
|
|
2254
|
+
background: var(--select-clear-button-hover-bg, rgba(0, 0, 0, 0.06));
|
|
2255
|
+
color: var(--select-clear-button-hover-color, #111827);
|
|
2256
|
+
}
|
|
2257
|
+
|
|
2258
|
+
.clear-control-button:focus-visible {
|
|
2259
|
+
outline: var(--select-clear-button-focus-outline, 2px solid rgba(102, 126, 234, 0.55));
|
|
2260
|
+
outline-offset: 1px;
|
|
2261
|
+
}
|
|
2262
|
+
|
|
2263
|
+
.clear-control-button[hidden] {
|
|
2264
|
+
display: none;
|
|
2265
|
+
}
|
|
2266
|
+
|
|
2267
|
+
.clear-control-icon {
|
|
2268
|
+
font-size: var(--select-clear-icon-size, 16px);
|
|
2269
|
+
line-height: 1;
|
|
2270
|
+
font-weight: var(--select-clear-icon-weight, 500);
|
|
2271
|
+
pointer-events: none;
|
|
2272
|
+
}
|
|
2194
2273
|
|
|
2195
2274
|
.dropdown-arrow-container:hover {
|
|
2196
2275
|
background-color: var(--select-arrow-hover-bg, rgba(102, 126, 234, 0.08));
|
|
@@ -2348,16 +2427,31 @@ class EnhancedSelect extends HTMLElement {
|
|
|
2348
2427
|
transform: var(--select-option-selected-hover-transform, var(--select-option-selected-transform, var(--select-option-transform, none)));
|
|
2349
2428
|
}
|
|
2350
2429
|
|
|
2351
|
-
.option.active {
|
|
2430
|
+
.option.active:not(.selected) {
|
|
2352
2431
|
background-color: var(--select-option-active-bg, #f3f4f6);
|
|
2353
2432
|
color: var(--select-option-active-color, #1f2937);
|
|
2354
2433
|
outline: var(--select-option-active-outline, 2px solid rgba(99, 102, 241, 0.45));
|
|
2355
2434
|
outline-offset: -2px;
|
|
2356
2435
|
}
|
|
2357
2436
|
|
|
2358
|
-
.option
|
|
2437
|
+
.option.selected.active {
|
|
2438
|
+
background-color: var(--select-option-selected-active-bg, var(--select-option-selected-bg, #e0e7ff));
|
|
2439
|
+
color: var(--select-option-selected-active-color, var(--select-option-selected-color, #4338ca));
|
|
2440
|
+
border: var(--select-option-selected-active-border, var(--select-option-selected-border, var(--select-option-border, none)));
|
|
2441
|
+
border-bottom: var(--select-option-selected-active-border-bottom, var(--select-option-selected-border-bottom, var(--select-option-border-bottom, none)));
|
|
2442
|
+
box-shadow: var(--select-option-selected-active-shadow, var(--select-option-selected-shadow, var(--select-option-shadow, none)));
|
|
2443
|
+
transform: var(--select-option-selected-active-transform, var(--select-option-selected-transform, var(--select-option-transform, none)));
|
|
2444
|
+
outline: var(--select-option-selected-active-outline, var(--select-option-active-outline, 2px solid rgba(99, 102, 241, 0.45)));
|
|
2445
|
+
outline-offset: -2px;
|
|
2446
|
+
}
|
|
2447
|
+
|
|
2448
|
+
.option:active:not(.selected) {
|
|
2359
2449
|
background-color: var(--select-option-pressed-bg, #e5e7eb);
|
|
2360
2450
|
}
|
|
2451
|
+
|
|
2452
|
+
.option.selected:active {
|
|
2453
|
+
background-color: var(--select-option-selected-pressed-bg, var(--select-option-selected-hover-bg, var(--select-option-selected-bg, #e0e7ff)));
|
|
2454
|
+
}
|
|
2361
2455
|
|
|
2362
2456
|
.load-more-container {
|
|
2363
2457
|
padding: var(--select-load-more-padding, 12px);
|
|
@@ -2518,12 +2612,23 @@ class EnhancedSelect extends HTMLElement {
|
|
|
2518
2612
|
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)))));
|
|
2519
2613
|
}
|
|
2520
2614
|
|
|
2521
|
-
.option.active {
|
|
2615
|
+
.option.active:not(.selected) {
|
|
2522
2616
|
background-color: var(--select-dark-option-active-bg, #374151);
|
|
2523
2617
|
color: var(--select-dark-option-active-color, #f9fafb);
|
|
2524
2618
|
outline: var(--select-dark-option-active-outline, 2px solid rgba(129, 140, 248, 0.55));
|
|
2525
2619
|
}
|
|
2526
2620
|
|
|
2621
|
+
.option.selected.active {
|
|
2622
|
+
background-color: var(--select-dark-option-selected-active-bg, var(--select-dark-option-selected-bg, #3730a3));
|
|
2623
|
+
color: var(--select-dark-option-selected-active-color, var(--select-dark-option-selected-text, #e0e7ff));
|
|
2624
|
+
border: var(--select-dark-option-selected-active-border, var(--select-dark-option-selected-border, var(--select-option-selected-active-border, var(--select-option-selected-border, var(--select-option-border, none)))));
|
|
2625
|
+
border-bottom: var(--select-dark-option-selected-active-border-bottom, var(--select-dark-option-selected-border-bottom, var(--select-option-selected-active-border-bottom, var(--select-option-selected-border-bottom, var(--select-option-border-bottom, none)))));
|
|
2626
|
+
box-shadow: var(--select-dark-option-selected-active-shadow, var(--select-dark-option-selected-shadow, var(--select-option-selected-active-shadow, var(--select-option-selected-shadow, var(--select-option-shadow, none)))));
|
|
2627
|
+
transform: var(--select-dark-option-selected-active-transform, var(--select-dark-option-selected-transform, var(--select-option-selected-active-transform, var(--select-option-selected-transform, var(--select-option-transform, none)))));
|
|
2628
|
+
outline: var(--select-dark-option-selected-active-outline, var(--select-dark-option-active-outline, var(--select-option-selected-active-outline, var(--select-option-active-outline, 2px solid rgba(129, 140, 248, 0.55)))));
|
|
2629
|
+
outline-offset: -2px;
|
|
2630
|
+
}
|
|
2631
|
+
|
|
2527
2632
|
.selection-badge {
|
|
2528
2633
|
background: var(--select-dark-badge-bg, #4f46e5);
|
|
2529
2634
|
color: var(--select-dark-badge-color, #eef2ff);
|
|
@@ -2608,6 +2713,17 @@ class EnhancedSelect extends HTMLElement {
|
|
|
2608
2713
|
};
|
|
2609
2714
|
this._arrowContainer.addEventListener('click', this._boundArrowClick);
|
|
2610
2715
|
}
|
|
2716
|
+
if (this._clearControl) {
|
|
2717
|
+
this._clearControl.addEventListener('pointerdown', (e) => {
|
|
2718
|
+
e.stopPropagation();
|
|
2719
|
+
e.preventDefault();
|
|
2720
|
+
});
|
|
2721
|
+
this._clearControl.addEventListener('click', (e) => {
|
|
2722
|
+
e.stopPropagation();
|
|
2723
|
+
e.preventDefault();
|
|
2724
|
+
this._handleClearControlClick();
|
|
2725
|
+
});
|
|
2726
|
+
}
|
|
2611
2727
|
// Input container click - focus input and open dropdown
|
|
2612
2728
|
this._inputContainer.addEventListener('pointerdown', (e) => {
|
|
2613
2729
|
const target = e.target;
|
|
@@ -2615,6 +2731,8 @@ class EnhancedSelect extends HTMLElement {
|
|
|
2615
2731
|
return;
|
|
2616
2732
|
if (target && target.closest('.dropdown-arrow-container'))
|
|
2617
2733
|
return;
|
|
2734
|
+
if (target && target.closest('.clear-control-button'))
|
|
2735
|
+
return;
|
|
2618
2736
|
if (!this._state.isOpen) {
|
|
2619
2737
|
this._handleOpen();
|
|
2620
2738
|
}
|
|
@@ -2827,6 +2945,7 @@ class EnhancedSelect extends HTMLElement {
|
|
|
2827
2945
|
}
|
|
2828
2946
|
_handleSearch(query) {
|
|
2829
2947
|
this._state.searchQuery = query;
|
|
2948
|
+
this._syncClearControlState();
|
|
2830
2949
|
if (query.length > 0) {
|
|
2831
2950
|
this._perfMark('smilodon-search-input-last');
|
|
2832
2951
|
this._pendingSearchRenderMark = true;
|
|
@@ -3004,7 +3123,9 @@ class EnhancedSelect extends HTMLElement {
|
|
|
3004
3123
|
option.classList.add('smilodon-option--active');
|
|
3005
3124
|
option.setAttribute('aria-selected', 'true');
|
|
3006
3125
|
}
|
|
3007
|
-
option.scrollIntoView
|
|
3126
|
+
if (typeof option.scrollIntoView === 'function') {
|
|
3127
|
+
option.scrollIntoView({ block: 'nearest', behavior: 'smooth' });
|
|
3128
|
+
}
|
|
3008
3129
|
// Announce position for screen readers
|
|
3009
3130
|
const total = options.length;
|
|
3010
3131
|
this._announce(`Item ${index + 1} of ${total}`);
|
|
@@ -3259,6 +3380,7 @@ class EnhancedSelect extends HTMLElement {
|
|
|
3259
3380
|
this._inputContainer.insertBefore(badge, this._input);
|
|
3260
3381
|
});
|
|
3261
3382
|
}
|
|
3383
|
+
this._syncClearControlState();
|
|
3262
3384
|
}
|
|
3263
3385
|
_renderOptionsWithAnimation() {
|
|
3264
3386
|
// Add fade-out animation
|
|
@@ -3507,6 +3629,21 @@ class EnhancedSelect extends HTMLElement {
|
|
|
3507
3629
|
this._renderOptions();
|
|
3508
3630
|
this._updateInputDisplay();
|
|
3509
3631
|
this._emitChange();
|
|
3632
|
+
this._syncClearControlState();
|
|
3633
|
+
}
|
|
3634
|
+
/**
|
|
3635
|
+
* Clear search query and restore full option list
|
|
3636
|
+
*/
|
|
3637
|
+
clearSearch() {
|
|
3638
|
+
this._state.searchQuery = '';
|
|
3639
|
+
if (this._config.searchable) {
|
|
3640
|
+
this._input.value = '';
|
|
3641
|
+
if (this._state.selectedIndices.size > 0) {
|
|
3642
|
+
this._updateInputDisplay();
|
|
3643
|
+
}
|
|
3644
|
+
}
|
|
3645
|
+
this._renderOptions();
|
|
3646
|
+
this._syncClearControlState();
|
|
3510
3647
|
}
|
|
3511
3648
|
/**
|
|
3512
3649
|
* Open dropdown
|
|
@@ -3533,6 +3670,12 @@ class EnhancedSelect extends HTMLElement {
|
|
|
3533
3670
|
this._input.placeholder = this._config.placeholder || 'Select an option...';
|
|
3534
3671
|
}
|
|
3535
3672
|
}
|
|
3673
|
+
if (this._clearControl) {
|
|
3674
|
+
this._clearControl.setAttribute('aria-label', this._config.clearControl.ariaLabel || 'Clear selection and search');
|
|
3675
|
+
}
|
|
3676
|
+
if (this._clearControlIcon) {
|
|
3677
|
+
this._clearControlIcon.textContent = this._config.clearControl.icon || '×';
|
|
3678
|
+
}
|
|
3536
3679
|
if (this._dropdown) {
|
|
3537
3680
|
if (this._config.selection.mode === 'multi') {
|
|
3538
3681
|
this._dropdown.setAttribute('aria-multiselectable', 'true');
|
|
@@ -3543,8 +3686,47 @@ class EnhancedSelect extends HTMLElement {
|
|
|
3543
3686
|
}
|
|
3544
3687
|
// Re-initialize observers in case infinite scroll was enabled/disabled
|
|
3545
3688
|
this._initializeObservers();
|
|
3689
|
+
this._syncClearControlState();
|
|
3546
3690
|
this._renderOptions();
|
|
3547
3691
|
}
|
|
3692
|
+
_handleClearControlClick() {
|
|
3693
|
+
const shouldClearSelection = this._config.clearControl.clearSelection !== false;
|
|
3694
|
+
const shouldClearSearch = this._config.clearControl.clearSearch !== false;
|
|
3695
|
+
const hadSelection = this._state.selectedIndices.size > 0;
|
|
3696
|
+
const hadSearch = this._state.searchQuery.length > 0;
|
|
3697
|
+
if (shouldClearSelection && hadSelection) {
|
|
3698
|
+
this.clear();
|
|
3699
|
+
}
|
|
3700
|
+
if (shouldClearSearch && hadSearch) {
|
|
3701
|
+
this.clearSearch();
|
|
3702
|
+
}
|
|
3703
|
+
this._emit('clear', {
|
|
3704
|
+
clearedSelection: shouldClearSelection && hadSelection,
|
|
3705
|
+
clearedSearch: shouldClearSearch && hadSearch,
|
|
3706
|
+
});
|
|
3707
|
+
this._config.callbacks.onClear?.({
|
|
3708
|
+
clearedSelection: shouldClearSelection && hadSelection,
|
|
3709
|
+
clearedSearch: shouldClearSearch && hadSearch,
|
|
3710
|
+
});
|
|
3711
|
+
this._input.focus();
|
|
3712
|
+
}
|
|
3713
|
+
_syncClearControlState() {
|
|
3714
|
+
if (!this._clearControl || !this._inputContainer || !this._arrowContainer)
|
|
3715
|
+
return;
|
|
3716
|
+
const enabled = this._config.clearControl.enabled === true;
|
|
3717
|
+
const hasSelection = this._state.selectedIndices.size > 0;
|
|
3718
|
+
const hasSearch = this._state.searchQuery.length > 0;
|
|
3719
|
+
const clearSelection = this._config.clearControl.clearSelection !== false;
|
|
3720
|
+
const clearSearch = this._config.clearControl.clearSearch !== false;
|
|
3721
|
+
const hasSomethingToClear = (clearSelection && hasSelection) || (clearSearch && hasSearch);
|
|
3722
|
+
const hideWhenEmpty = this._config.clearControl.hideWhenEmpty !== false;
|
|
3723
|
+
const visible = enabled && (!hideWhenEmpty || hasSomethingToClear);
|
|
3724
|
+
this._inputContainer.classList.toggle('has-clear-control', enabled);
|
|
3725
|
+
this._arrowContainer.classList.toggle('with-clear-control', enabled);
|
|
3726
|
+
this._clearControl.hidden = !visible;
|
|
3727
|
+
this._clearControl.disabled = !hasSomethingToClear;
|
|
3728
|
+
this._clearControl.setAttribute('aria-hidden', String(!visible));
|
|
3729
|
+
}
|
|
3548
3730
|
/**
|
|
3549
3731
|
* Set error state
|
|
3550
3732
|
*/
|
|
@@ -4832,10 +5014,17 @@ const shadowDOMStyles = `
|
|
|
4832
5014
|
color: var(--ns-item-selected-color, #0066cc);
|
|
4833
5015
|
}
|
|
4834
5016
|
|
|
4835
|
-
.ns-item[data-active="true"] {
|
|
5017
|
+
.ns-item[data-active="true"]:not([aria-selected="true"]) {
|
|
4836
5018
|
background: var(--ns-item-active-bg, rgba(0, 102, 204, 0.2));
|
|
4837
5019
|
}
|
|
4838
5020
|
|
|
5021
|
+
.ns-item[aria-selected="true"][data-active="true"] {
|
|
5022
|
+
background: var(--ns-item-selected-active-bg, var(--ns-item-selected-bg, rgba(0, 102, 204, 0.1)));
|
|
5023
|
+
color: var(--ns-item-selected-active-color, var(--ns-item-selected-color, #0066cc));
|
|
5024
|
+
outline: var(--ns-item-selected-active-outline, 2px solid #0066cc);
|
|
5025
|
+
outline-offset: -2px;
|
|
5026
|
+
}
|
|
5027
|
+
|
|
4839
5028
|
.ns-item[aria-disabled="true"] {
|
|
4840
5029
|
opacity: 0.5;
|
|
4841
5030
|
cursor: not-allowed;
|