@smilodon/core 1.4.10 → 1.4.12

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 CHANGED
@@ -610,6 +610,11 @@ Dark mode is **opt-in only** and can be enabled by adding a class or data attrib
610
610
 
611
611
  <!-- Using data attribute -->
612
612
  <enhanced-select data-theme="dark"></enhanced-select>
613
+
614
+ <!-- Also supported (attribute aliases) -->
615
+ <enhanced-select dark-mode></enhanced-select>
616
+ <enhanced-select darkmode></enhanced-select>
617
+ <enhanced-select theme="dark"></enhanced-select>
613
618
  ```
614
619
 
615
620
  ```css
@@ -631,6 +636,8 @@ enhanced-select.dark-mode {
631
636
  **Light Mode (Default)**
632
637
  ```css
633
638
  --select-options-bg /* Options container background (white) */
639
+ --select-width /* Host width (100% default) */
640
+ --select-height /* Host height (auto default) */
634
641
  --select-option-color /* Option text color (#1f2937) */
635
642
  --select-option-bg /* Option background (white) */
636
643
  --select-option-padding /* Option padding (8px 12px) */
@@ -643,6 +650,8 @@ enhanced-select.dark-mode {
643
650
  --select-option-selected-hover-border /* Selected+hover border (inherits selected border by default) */
644
651
  --select-option-active-bg /* Active background (#f3f4f6) */
645
652
  --select-option-active-color /* Active text color (#1f2937) */
653
+ --select-input-width /* Input field width */
654
+ --select-input-height /* Input container height */
646
655
  --select-dropdown-bg /* Dropdown background (white) */
647
656
  --select-dropdown-border /* Dropdown border color (#ccc) */
648
657
  --select-dropdown-shadow /* Dropdown shadow */
@@ -665,9 +674,17 @@ enhanced-select.dark-mode {
665
674
  --select-group-header-color /* Text color (#6b7280) */
666
675
  --select-group-header-bg /* Background (#f3f4f6) */
667
676
  --select-group-header-font-size
677
+ --select-group-header-text-align /* Header text alignment (left default) */
668
678
  --select-group-header-text-transform
669
679
  --select-group-header-letter-spacing
670
680
  --select-group-header-border-bottom
681
+
682
+ /* Option content and checkmark hooks */
683
+ --select-option-content-overflow
684
+ --select-option-content-text-overflow
685
+ --select-option-content-white-space
686
+ --select-checkmark-margin-left
687
+ --select-checkmark-color
671
688
  ```
672
689
 
673
690
  **Dark Mode (Opt-in)**
@@ -717,8 +734,19 @@ enhanced-select {
717
734
  transparent 100%
718
735
  );
719
736
  }
737
+
738
+ /* Typo-compatible aliases are also accepted */
739
+ enhanced-select {
740
+ --select-seperator-width: 2px;
741
+ --select-seperator-height: 80%;
742
+ --select-seperator-position: 40px;
743
+ --select-seperator-gradient: linear-gradient(to bottom, transparent 0%, #3b82f6 20%, #3b82f6 80%, transparent 100%);
744
+ }
720
745
  ```
721
746
 
747
+ **Gradient Dropdown + Hover/Selected States**
748
+ If your dropdown uses a gradient background (for example via `--select-dropdown-bg`), option hover/selected colors still work as expected. The component intentionally uses the `background` shorthand for hover/selected option states so any inherited `background-image` layers are cleared correctly.
749
+
722
750
  **Badge Remove/Delete Button (Multi-Select)**
723
751
  The × button that removes selected items in multi-select mode is fully customizable:
724
752
 
package/dist/index.cjs CHANGED
@@ -1403,6 +1403,18 @@ const defaultConfig = {
1403
1403
  icon: '×',
1404
1404
  },
1405
1405
  callbacks: {},
1406
+ tracking: {
1407
+ enabled: false,
1408
+ events: true,
1409
+ styling: true,
1410
+ limitations: true,
1411
+ emitDiagnostics: false,
1412
+ maxEntries: 200,
1413
+ },
1414
+ limitations: {
1415
+ policies: {},
1416
+ autoMitigateRuntimeModeSwitch: true,
1417
+ },
1406
1418
  enabled: true,
1407
1419
  searchable: false,
1408
1420
  placeholder: 'Select an option...',
@@ -1534,6 +1546,8 @@ class SelectOption extends HTMLElement {
1534
1546
  padding: var(--select-option-padding, 8px 12px);
1535
1547
  cursor: pointer;
1536
1548
  user-select: none;
1549
+ color: var(--select-option-color, var(--select-text-color, #1f2937));
1550
+ background: var(--select-option-bg, var(--select-dropdown-bg, var(--select-bg, white)));
1537
1551
  transition: var(--select-option-transition, background-color 0.2s ease);
1538
1552
  border: var(--select-option-border, none);
1539
1553
  border-bottom: var(--select-option-border-bottom, none);
@@ -1578,9 +1592,20 @@ class SelectOption extends HTMLElement {
1578
1592
 
1579
1593
  .option-content {
1580
1594
  flex: 1;
1581
- overflow: hidden;
1582
- text-overflow: ellipsis;
1583
- white-space: nowrap;
1595
+ overflow: var(--select-option-content-overflow, hidden);
1596
+ text-overflow: var(--select-option-content-text-overflow, ellipsis);
1597
+ white-space: var(--select-option-content-white-space, nowrap);
1598
+ }
1599
+
1600
+ .checkmark-icon {
1601
+ display: none;
1602
+ margin-left: var(--select-checkmark-margin-left, 8px);
1603
+ color: var(--select-checkmark-color, currentColor);
1604
+ }
1605
+
1606
+ :host([aria-selected="true"]) .checkmark-icon,
1607
+ .option-container.selected .checkmark-icon {
1608
+ display: inline-flex;
1584
1609
  }
1585
1610
 
1586
1611
  .remove-button {
@@ -1708,16 +1733,6 @@ class SelectOption extends HTMLElement {
1708
1733
  <path d="M4 8.5L6.5 11L12 5.5" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
1709
1734
  </svg>
1710
1735
  `;
1711
- // Visibility control via CSS or inline style
1712
- // We set it to display: none unless selected.
1713
- // User can override this behavior via part styling if they want transitions
1714
- if (!selected) {
1715
- checkmark.style.display = 'none';
1716
- }
1717
- else {
1718
- checkmark.style.marginLeft = '8px';
1719
- checkmark.style.color = 'currentColor';
1720
- }
1721
1736
  this._container.appendChild(checkmark);
1722
1737
  }
1723
1738
  // Data Attributes Contract on Host
@@ -1876,6 +1891,10 @@ class EnhancedSelect extends HTMLElement {
1876
1891
  set classMap(map) {
1877
1892
  this._classMap = map;
1878
1893
  this._setGlobalStylesMirroring(Boolean(this._optionRenderer || map || this._groupHeaderRenderer));
1894
+ this._track('style', 'classMapChanged', {
1895
+ hasClassMap: Boolean(map),
1896
+ keys: map ? Object.keys(map) : [],
1897
+ });
1879
1898
  if (!this.isConnected)
1880
1899
  return;
1881
1900
  this._renderOptions();
@@ -1891,6 +1910,7 @@ class EnhancedSelect extends HTMLElement {
1891
1910
  set groupHeaderRenderer(renderer) {
1892
1911
  this._groupHeaderRenderer = renderer;
1893
1912
  this._setGlobalStylesMirroring(Boolean(this._optionRenderer || this._classMap || renderer));
1913
+ this._track('style', 'groupHeaderRendererChanged', { enabled: Boolean(renderer) });
1894
1914
  if (!this.isConnected)
1895
1915
  return;
1896
1916
  this._renderOptions();
@@ -1909,6 +1929,7 @@ class EnhancedSelect extends HTMLElement {
1909
1929
  this._mirrorGlobalStylesForCustomOptions = false;
1910
1930
  this._globalStylesObserver = null;
1911
1931
  this._globalStylesContainer = null;
1932
+ this._tracking = { events: [], styles: [], limitations: [] };
1912
1933
  this._shadow = this.attachShadow({ mode: 'open' });
1913
1934
  this._uniqueId = `enhanced-select-${Math.random().toString(36).substr(2, 9)}`;
1914
1935
  this._rendererHelpers = this._buildRendererHelpers();
@@ -1955,7 +1976,6 @@ class EnhancedSelect extends HTMLElement {
1955
1976
  // Angular's rendering seems to not apply :host styles correctly in some cases
1956
1977
  // Must be done in connectedCallback when element is attached to DOM
1957
1978
  this.style.display = 'block';
1958
- this.style.width = '100%';
1959
1979
  if (this._optionRenderer) {
1960
1980
  this._setGlobalStylesMirroring(true);
1961
1981
  }
@@ -1994,6 +2014,7 @@ class EnhancedSelect extends HTMLElement {
1994
2014
  return;
1995
2015
  }
1996
2016
  this._mirrorGlobalStylesForCustomOptions = enabled;
2017
+ this._track('style', 'globalStylesMirroringChanged', { enabled });
1997
2018
  if (enabled) {
1998
2019
  this._setupGlobalStylesMirroring();
1999
2020
  }
@@ -2198,7 +2219,8 @@ class EnhancedSelect extends HTMLElement {
2198
2219
  :host {
2199
2220
  display: block;
2200
2221
  position: relative;
2201
- width: 100%;
2222
+ width: var(--select-width, 100%);
2223
+ height: var(--select-height, auto);
2202
2224
  }
2203
2225
 
2204
2226
  .select-container {
@@ -2214,6 +2236,7 @@ class EnhancedSelect extends HTMLElement {
2214
2236
  flex-wrap: wrap;
2215
2237
  gap: var(--select-input-gap, 6px);
2216
2238
  padding: var(--select-input-padding, 6px 52px 6px 8px);
2239
+ height: var(--select-input-height, auto);
2217
2240
  min-height: var(--select-input-min-height, 44px);
2218
2241
  max-height: var(--select-input-max-height, 160px);
2219
2242
  overflow-y: var(--select-input-overflow-y, auto);
@@ -2235,17 +2258,17 @@ class EnhancedSelect extends HTMLElement {
2235
2258
  content: '';
2236
2259
  position: absolute;
2237
2260
  top: 50%;
2238
- right: var(--select-separator-position, 40px);
2261
+ right: var(--select-separator-position, var(--select-seperator-position, 40px));
2239
2262
  transform: translateY(-50%);
2240
- width: var(--select-separator-width, 1px);
2241
- height: var(--select-separator-height, 60%);
2242
- background: var(--select-separator-bg, var(--select-separator-gradient, linear-gradient(
2263
+ width: var(--select-separator-width, var(--select-seperator-width, 1px));
2264
+ height: var(--select-separator-height, var(--select-seperator-height, 60%));
2265
+ background: var(--select-separator-bg, var(--select-seperator-bg, var(--select-separator-gradient, var(--select-seperator-gradient, linear-gradient(
2243
2266
  to bottom,
2244
2267
  transparent 0%,
2245
2268
  rgba(0, 0, 0, 0.1) 20%,
2246
2269
  rgba(0, 0, 0, 0.1) 80%,
2247
2270
  transparent 100%
2248
- )));
2271
+ ))));
2249
2272
  pointer-events: none;
2250
2273
  z-index: 1;
2251
2274
  }
@@ -2272,7 +2295,7 @@ class EnhancedSelect extends HTMLElement {
2272
2295
  }
2273
2296
 
2274
2297
  .input-container.has-clear-control::after {
2275
- right: var(--select-separator-position-with-clear, 72px);
2298
+ right: var(--select-separator-position-with-clear, var(--select-seperator-position-with-clear, 72px));
2276
2299
  }
2277
2300
 
2278
2301
  .dropdown-arrow-container.with-clear-control {
@@ -2350,6 +2373,7 @@ class EnhancedSelect extends HTMLElement {
2350
2373
 
2351
2374
  .select-input {
2352
2375
  flex: 1;
2376
+ width: var(--select-input-width, auto);
2353
2377
  min-width: var(--select-input-min-width, 120px);
2354
2378
  padding: var(--select-input-field-padding, 4px);
2355
2379
  border: none;
@@ -2444,6 +2468,7 @@ class EnhancedSelect extends HTMLElement {
2444
2468
  font-weight: var(--select-group-header-weight, 600);
2445
2469
  color: var(--select-group-header-color, #6b7280);
2446
2470
  background-color: var(--select-group-header-bg, #f3f4f6);
2471
+ text-align: var(--select-group-header-text-align, left);
2447
2472
  font-size: var(--select-group-header-font-size, 12px);
2448
2473
  text-transform: var(--select-group-header-text-transform, uppercase);
2449
2474
  letter-spacing: var(--select-group-header-letter-spacing, 0.05em);
@@ -2628,10 +2653,25 @@ class EnhancedSelect extends HTMLElement {
2628
2653
 
2629
2654
  /* Dark mode - Opt-in via class, data attribute, or ancestor context */
2630
2655
  :host(.dark-mode),
2656
+ :host([dark-mode]),
2657
+ :host([darkmode]),
2631
2658
  :host([data-theme="dark"]),
2659
+ :host([theme="dark"]),
2632
2660
  :host-context(.dark-mode),
2633
2661
  :host-context(.dark),
2634
- :host-context([data-theme="dark"]) {
2662
+ :host-context([dark-mode]),
2663
+ :host-context([darkmode]),
2664
+ :host-context([data-theme="dark"]),
2665
+ :host-context([theme="dark"]) {
2666
+ /* map dark tokens to base option tokens so nested <select-option>
2667
+ components also pick up dark mode via inherited CSS variables */
2668
+ --select-option-bg: var(--select-dark-option-bg, #1f2937);
2669
+ --select-option-color: var(--select-dark-option-color, #f9fafb);
2670
+ --select-option-hover-bg: var(--select-dark-option-hover-bg, #374151);
2671
+ --select-option-hover-color: var(--select-dark-option-hover-color, #f9fafb);
2672
+ --select-option-selected-bg: var(--select-dark-option-selected-bg, #3730a3);
2673
+ --select-option-selected-color: var(--select-dark-option-selected-text, #e0e7ff);
2674
+
2635
2675
  .input-container {
2636
2676
  background: var(--select-dark-bg, #1f2937);
2637
2677
  border-color: var(--select-dark-border, #4b5563);
@@ -2684,6 +2724,8 @@ class EnhancedSelect extends HTMLElement {
2684
2724
 
2685
2725
  .option.active:not(.selected) {
2686
2726
  background-color: var(--select-dark-option-active-bg, #374151);
2727
+ color: var(--select-dark-option-active-color, #f9fafb);
2728
+ outline: var(--select-dark-option-active-outline, 2px solid rgba(129, 140, 248, 0.55));
2687
2729
  }
2688
2730
 
2689
2731
  /* Group header in dark mode */
@@ -2691,9 +2733,6 @@ class EnhancedSelect extends HTMLElement {
2691
2733
  color: var(--select-dark-group-header-color, var(--select-group-header-color, #6b7280));
2692
2734
  background-color: var(--select-dark-group-header-bg, var(--select-group-header-bg, #374151));
2693
2735
  }
2694
- color: var(--select-dark-option-active-color, #f9fafb);
2695
- outline: var(--select-dark-option-active-outline, 2px solid rgba(129, 140, 248, 0.55));
2696
- }
2697
2736
 
2698
2737
  .option.selected.active {
2699
2738
  background-color: var(--select-dark-option-selected-active-bg, var(--select-dark-option-selected-bg, #3730a3));
@@ -2815,7 +2854,13 @@ class EnhancedSelect extends HTMLElement {
2815
2854
  this._handleOpen();
2816
2855
  }
2817
2856
  else {
2818
- // clicking the input while open should close the dropdown too
2857
+ // Keep open while interacting directly with the input so users can
2858
+ // place cursor/type without accidental collapse.
2859
+ if (target === this._input) {
2860
+ this._input.focus();
2861
+ return;
2862
+ }
2863
+ // clicking other parts of the input container while open toggles close
2819
2864
  this._handleClose();
2820
2865
  }
2821
2866
  // Focus the input (do not prevent default behavior)
@@ -3650,6 +3695,162 @@ class EnhancedSelect extends HTMLElement {
3650
3695
  }
3651
3696
  _emit(name, detail) {
3652
3697
  this.dispatchEvent(new CustomEvent(name, { detail, bubbles: true, composed: true }));
3698
+ if (name !== 'diagnostic') {
3699
+ this._track('event', String(name), detail);
3700
+ }
3701
+ }
3702
+ _track(source, name, detail) {
3703
+ const cfg = this._config.tracking;
3704
+ if (!cfg?.enabled)
3705
+ return;
3706
+ if (source === 'event' && !cfg.events)
3707
+ return;
3708
+ if (source === 'style' && !cfg.styling)
3709
+ return;
3710
+ if (source === 'limitation' && !cfg.limitations)
3711
+ return;
3712
+ const entry = {
3713
+ timestamp: Date.now(),
3714
+ source,
3715
+ name,
3716
+ detail,
3717
+ };
3718
+ const bucket = source === 'event'
3719
+ ? this._tracking.events
3720
+ : source === 'style'
3721
+ ? this._tracking.styles
3722
+ : this._tracking.limitations;
3723
+ bucket.push(entry);
3724
+ const maxEntries = Math.max(10, cfg.maxEntries || 200);
3725
+ if (bucket.length > maxEntries) {
3726
+ bucket.splice(0, bucket.length - maxEntries);
3727
+ }
3728
+ if (cfg.emitDiagnostics) {
3729
+ this.dispatchEvent(new CustomEvent('diagnostic', {
3730
+ detail: entry,
3731
+ bubbles: true,
3732
+ composed: true,
3733
+ }));
3734
+ }
3735
+ }
3736
+ _getKnownLimitationDefinitions() {
3737
+ return [
3738
+ {
3739
+ id: 'variableItemHeight',
3740
+ title: 'Variable item height',
3741
+ description: 'Virtualization assumes fixed or estimated item heights; fully dynamic heights are not yet supported.',
3742
+ workaround: 'Use consistent item heights or set estimatedItemHeight to your dominant row size.',
3743
+ },
3744
+ {
3745
+ id: 'builtInFetchPaginationApi',
3746
+ title: 'Built-in fetch/pagination API',
3747
+ description: 'Core does not include a built-in fetchUrl/searchUrl pagination transport.',
3748
+ workaround: 'Use onSearch/onLoadMore callbacks and update data via setItems().',
3749
+ },
3750
+ {
3751
+ id: 'virtualizationOverheadSmallLists',
3752
+ title: 'Virtualization overhead for small lists',
3753
+ description: 'Virtualization can add slight overhead on very small lists.',
3754
+ workaround: 'Disable virtualization for tiny datasets when micro-latency is critical.',
3755
+ },
3756
+ {
3757
+ id: 'runtimeModeSwitching',
3758
+ title: 'Runtime single/multi mode switching',
3759
+ description: 'Switching between single and multi mode can require state reset for consistency.',
3760
+ workaround: 'Enable autoMitigateRuntimeModeSwitch or recreate/reset component state when toggling modes.',
3761
+ },
3762
+ {
3763
+ id: 'legacyBrowserSupport',
3764
+ title: 'Legacy browser support',
3765
+ description: 'Official support targets modern evergreen browsers.',
3766
+ },
3767
+ {
3768
+ id: 'webkitArchLinux',
3769
+ title: 'Playwright WebKit on Arch-based Linux',
3770
+ description: 'Native WebKit Playwright bundle depends on unavailable legacy system libraries on Arch-based distros.',
3771
+ workaround: 'Run WebKit E2E tests via Playwright Docker image.',
3772
+ },
3773
+ ];
3774
+ }
3775
+ _evaluateLimitationStatus(id) {
3776
+ const policyMode = this._config.limitations?.policies?.[id]?.mode ?? 'default';
3777
+ if (policyMode === 'suppress')
3778
+ return 'suppressed';
3779
+ if (id === 'runtimeModeSwitching' && this._config.limitations?.autoMitigateRuntimeModeSwitch) {
3780
+ return 'mitigated';
3781
+ }
3782
+ return 'active';
3783
+ }
3784
+ getKnownLimitations() {
3785
+ return this._getKnownLimitationDefinitions().map((limitation) => {
3786
+ const mode = this._config.limitations?.policies?.[limitation.id]?.mode ?? 'default';
3787
+ return {
3788
+ ...limitation,
3789
+ mode,
3790
+ status: this._evaluateLimitationStatus(limitation.id),
3791
+ };
3792
+ });
3793
+ }
3794
+ setLimitationPolicies(policies) {
3795
+ const next = {
3796
+ ...(this._config.limitations?.policies || {}),
3797
+ ...policies,
3798
+ };
3799
+ this.updateConfig({
3800
+ limitations: {
3801
+ ...(this._config.limitations || { autoMitigateRuntimeModeSwitch: true, policies: {} }),
3802
+ policies: next,
3803
+ },
3804
+ });
3805
+ this._track('limitation', 'policiesUpdated', { policies: next });
3806
+ }
3807
+ getTrackingSnapshot() {
3808
+ return {
3809
+ events: [...this._tracking.events],
3810
+ styles: [...this._tracking.styles],
3811
+ limitations: [...this._tracking.limitations],
3812
+ };
3813
+ }
3814
+ clearTracking(source) {
3815
+ if (!source || source === 'all') {
3816
+ this._tracking.events = [];
3817
+ this._tracking.styles = [];
3818
+ this._tracking.limitations = [];
3819
+ return;
3820
+ }
3821
+ if (source === 'event')
3822
+ this._tracking.events = [];
3823
+ if (source === 'style')
3824
+ this._tracking.styles = [];
3825
+ if (source === 'limitation')
3826
+ this._tracking.limitations = [];
3827
+ }
3828
+ getCapabilities() {
3829
+ return {
3830
+ styling: {
3831
+ classMap: true,
3832
+ optionRenderer: true,
3833
+ groupHeaderRenderer: true,
3834
+ cssCustomProperties: true,
3835
+ shadowParts: true,
3836
+ globalStyleMirroring: true,
3837
+ },
3838
+ events: {
3839
+ emitted: ['select', 'open', 'close', 'search', 'change', 'loadMore', 'remove', 'clear', 'error', 'diagnostic'],
3840
+ diagnosticEvent: true,
3841
+ },
3842
+ functionality: {
3843
+ multiSelect: true,
3844
+ searchable: true,
3845
+ infiniteScroll: true,
3846
+ loadMore: true,
3847
+ clearControl: true,
3848
+ groupedItems: true,
3849
+ serverSideSelection: true,
3850
+ runtimeModeSwitchMitigation: Boolean(this._config.limitations?.autoMitigateRuntimeModeSwitch),
3851
+ },
3852
+ limitations: this.getKnownLimitations(),
3853
+ };
3653
3854
  }
3654
3855
  _emitChange() {
3655
3856
  const selectedItems = Array.from(this._state.selectedItems.values());
@@ -3667,6 +3868,7 @@ class EnhancedSelect extends HTMLElement {
3667
3868
  set optionRenderer(renderer) {
3668
3869
  this._optionRenderer = renderer;
3669
3870
  this._setGlobalStylesMirroring(Boolean(renderer || this._classMap));
3871
+ this._track('style', 'optionRendererChanged', { enabled: Boolean(renderer) });
3670
3872
  this._renderOptions();
3671
3873
  }
3672
3874
  /**
@@ -3831,7 +4033,22 @@ class EnhancedSelect extends HTMLElement {
3831
4033
  * Update component configuration
3832
4034
  */
3833
4035
  updateConfig(config) {
3834
- this._config = selectConfig.mergeWithComponentConfig(config);
4036
+ const previousMode = this._config.selection.mode;
4037
+ this._config = this._mergeConfig(this._config, config);
4038
+ if (previousMode !== this._config.selection.mode &&
4039
+ this._config.limitations?.autoMitigateRuntimeModeSwitch) {
4040
+ this.clear();
4041
+ this._track('limitation', 'runtimeModeSwitchMitigated', {
4042
+ from: previousMode,
4043
+ to: this._config.selection.mode,
4044
+ });
4045
+ }
4046
+ else if (previousMode !== this._config.selection.mode) {
4047
+ this._track('limitation', 'runtimeModeSwitchDetected', {
4048
+ from: previousMode,
4049
+ to: this._config.selection.mode,
4050
+ });
4051
+ }
3835
4052
  // Update input state based on new config
3836
4053
  if (this._input) {
3837
4054
  this._input.readOnly = !this._config.searchable;
@@ -3859,6 +4076,22 @@ class EnhancedSelect extends HTMLElement {
3859
4076
  this._syncClearControlState();
3860
4077
  this._renderOptions();
3861
4078
  }
4079
+ _mergeConfig(target, source) {
4080
+ const result = { ...target };
4081
+ for (const key in source) {
4082
+ if (!Object.prototype.hasOwnProperty.call(source, key))
4083
+ continue;
4084
+ const sourceValue = source[key];
4085
+ const targetValue = result[key];
4086
+ if (sourceValue && typeof sourceValue === 'object' && !Array.isArray(sourceValue)) {
4087
+ result[key] = this._mergeConfig(targetValue && typeof targetValue === 'object' ? targetValue : {}, sourceValue);
4088
+ }
4089
+ else {
4090
+ result[key] = sourceValue;
4091
+ }
4092
+ }
4093
+ return result;
4094
+ }
3862
4095
  _handleClearControlClick() {
3863
4096
  const shouldClearSelection = this._config.clearControl.clearSelection !== false;
3864
4097
  const shouldClearSearch = this._config.clearControl.clearSearch !== false;