raintee-maputils 1.0.35 → 1.0.36

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/dist/index.js CHANGED
@@ -6561,13 +6561,14 @@ class RulerControl {
6561
6561
 
6562
6562
  class CustomOptionsControl {
6563
6563
  constructor(args) {
6564
- const { title, options, onConfirm } = args;
6564
+ const { title, options, onConfirm, icon } = args;
6565
6565
 
6566
6566
  this._map = null;
6567
6567
  this._container = null;
6568
6568
 
6569
+ this._title = title || '';
6569
6570
  this._options = options || [];
6570
- this._title = title || '标题';
6571
+ this._icon = icon || null;
6571
6572
  this._onConfirm = onConfirm || (() => { });
6572
6573
  this._originalOptions = [...this._options];
6573
6574
  this._selectedOptions = [];
@@ -6580,119 +6581,450 @@ class CustomOptionsControl {
6580
6581
  this._container.className = 'mapboxgl-ctrl mapboxgl-ctrl-group custom-options-control';
6581
6582
 
6582
6583
  const mainButton = document.createElement('button');
6583
- mainButton.textContent = this._title;
6584
6584
  mainButton.style.cssText = `
6585
- padding: 4px 8px;
6585
+ padding: 0;
6586
6586
  background: white;
6587
- border: 1px solid #ccc;
6587
+ border: 0.0625rem solid #ccc;
6588
6588
  cursor: pointer;
6589
+ display: flex;
6590
+ align-items: center;
6591
+ justify-content: center;
6592
+ gap: 0.375rem;
6589
6593
  `;
6590
6594
 
6595
+ if (this._icon) {
6596
+ const iconWrapper = document.createElement('span');
6597
+ iconWrapper.style.cssText = `
6598
+ width: 1rem;
6599
+ height: 1rem;
6600
+ display: inline-flex;
6601
+ align-items: center;
6602
+ justify-content: center;
6603
+ `;
6604
+
6605
+ if (this._icon.trim().startsWith('<svg')) {
6606
+ iconWrapper.innerHTML = this._icon;
6607
+ } else {
6608
+ const img = document.createElement('img');
6609
+ img.src = this._icon;
6610
+ img.style.cssText = `width: 1rem; height: 1rem; object-fit: contain;`;
6611
+ iconWrapper.appendChild(img);
6612
+ }
6613
+
6614
+ mainButton.appendChild(iconWrapper);
6615
+ }
6616
+
6591
6617
  mainButton.addEventListener('click', () => {
6592
6618
  this._showModal();
6593
6619
  });
6594
6620
 
6595
6621
  this._container.appendChild(mainButton);
6622
+
6623
+ // 添加全局样式
6624
+ this._addGlobalStyles();
6625
+
6596
6626
  return this._container;
6597
6627
  }
6598
6628
 
6599
- /** 创建遮罩弹窗 */
6629
+ _addGlobalStyles() {
6630
+ if (document.querySelector('#custom-options-styles')) return;
6631
+
6632
+ const styles = document.createElement('style');
6633
+ styles.id = 'custom-options-styles';
6634
+ styles.textContent = `
6635
+ @keyframes modalSlideIn {
6636
+ from {
6637
+ opacity: 0;
6638
+ transform: scale(0.95) translateY(-20px);
6639
+ }
6640
+ to {
6641
+ opacity: 1;
6642
+ transform: scale(1) translateY(0);
6643
+ }
6644
+ }
6645
+
6646
+ @keyframes modalBackdropFadeIn {
6647
+ from { opacity: 0; }
6648
+ to { opacity: 1; }
6649
+ }
6650
+
6651
+ @keyframes fadeInUp {
6652
+ from {
6653
+ opacity: 0;
6654
+ transform: translateY(20px);
6655
+ }
6656
+ to {
6657
+ opacity: 1;
6658
+ transform: translateY(0);
6659
+ }
6660
+ }
6661
+
6662
+ .custom-modal-overlay {
6663
+ animation: modalBackdropFadeIn 0.2s ease-out;
6664
+ }
6665
+
6666
+ .custom-modal {
6667
+ animation: modalSlideIn 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
6668
+ }
6669
+
6670
+ .custom-search-input:focus {
6671
+ border-color: #667eea !important;
6672
+ box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1) !important;
6673
+ }
6674
+
6675
+ .custom-checkbox {
6676
+ position: relative;
6677
+ appearance: none;
6678
+ width: 1rem;
6679
+ height: 1rem;
6680
+ border: 2px solid #d1d5db;
6681
+ border-radius: 0.25rem;
6682
+ background: white;
6683
+ cursor: pointer;
6684
+ transition: all 0.2s ease;
6685
+ margin-right: 0.75rem;
6686
+ }
6687
+
6688
+ .custom-checkbox:checked {
6689
+ background: linear-gradient(135deg, #667eea, #764ba2);
6690
+ border-color: #667eea;
6691
+ }
6692
+
6693
+ .custom-checkbox:checked::after {
6694
+ content: '✓';
6695
+ position: absolute;
6696
+ top: 50%;
6697
+ left: 50%;
6698
+ transform: translate(-50%, -50%);
6699
+ color: white;
6700
+ font-size: 0.75rem;
6701
+ font-weight: bold;
6702
+ }
6703
+
6704
+ .custom-checkbox:hover {
6705
+ border-color: #667eea;
6706
+ box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
6707
+ }
6708
+
6709
+ .custom-list-item {
6710
+ transition: all 0.2s ease;
6711
+ }
6712
+
6713
+ .custom-list-item:hover {
6714
+ background-color: #f8fafc !important;
6715
+ border-color: #e2e8f0 !important;
6716
+ transform: translateX(4px) !important;
6717
+ }
6718
+
6719
+ .custom-modal::-webkit-scrollbar {
6720
+ width: 6px;
6721
+ }
6722
+
6723
+ .custom-modal::-webkit-scrollbar-track {
6724
+ background: #f1f5f9;
6725
+ border-radius: 3px;
6726
+ }
6727
+
6728
+ .custom-modal::-webkit-scrollbar-thumb {
6729
+ background: linear-gradient(135deg, #667eea, #764ba2);
6730
+ border-radius: 3px;
6731
+ }
6732
+
6733
+ .custom-modal::-webkit-scrollbar-thumb:hover {
6734
+ background: linear-gradient(135deg, #5a67d8, #6b46c1);
6735
+ }
6736
+ `;
6737
+ document.head.appendChild(styles);
6738
+ }
6739
+
6600
6740
  _showModal() {
6601
- // 创建遮罩层
6602
6741
  this._overlay = document.createElement('div');
6603
6742
  this._overlay.className = 'custom-modal-overlay';
6604
6743
  this._overlay.style.cssText = `
6605
6744
  position: fixed;
6606
6745
  top: 0; left: 0; right: 0; bottom: 0;
6607
- background: rgba(0,0,0,0.5);
6608
- z-index: 9999;
6746
+ background: rgba(0, 0, 0, 0.5);
6747
+ backdrop-filter: blur(4px);
6748
+ -webkit-backdrop-filter: blur(4px);
6749
+ z-index: 10000;
6609
6750
  display: flex;
6610
6751
  justify-content: center;
6611
6752
  align-items: center;
6753
+ padding: 1rem;
6754
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
6612
6755
  `;
6613
6756
 
6614
- // 弹窗容器
6615
6757
  this._modal = document.createElement('div');
6616
6758
  this._modal.className = 'custom-modal';
6617
6759
  this._modal.style.cssText = `
6618
- width: 360px;
6760
+ width: 100%;
6761
+ max-width: 26rem;
6619
6762
  max-height: 80vh;
6763
+ background: linear-gradient(145deg, #ffffff 0%, #f8fafc 100%);
6764
+ border-radius: 0.75rem;
6765
+ box-shadow:
6766
+ 0 20px 25px -5px rgba(0, 0, 0, 0.1),
6767
+ 0 10px 10px -5px rgba(0, 0, 0, 0.04);
6768
+ border: 1px solid rgba(255, 255, 255, 0.8);
6620
6769
  overflow: hidden;
6621
- background: white;
6622
- border-radius: 8px;
6623
- padding: 20px;
6624
6770
  display: flex;
6625
6771
  flex-direction: column;
6626
6772
  `;
6627
6773
 
6628
- // 搜索框
6774
+ // 创建头部
6775
+ const header = this._createHeader();
6776
+ this._modal.appendChild(header);
6777
+
6778
+ // 创建搜索区域
6779
+ const searchSection = this._createSearchSection();
6780
+ this._modal.appendChild(searchSection);
6781
+
6782
+ // 创建选项列表
6783
+ this._listBox = document.createElement('div');
6784
+ this._listBox.style.cssText = `
6785
+ flex: 1;
6786
+ overflow-y: auto;
6787
+ padding: 0 1.25rem 1.25rem 1.25rem;
6788
+ min-height: 10rem;
6789
+ `;
6790
+ this._modal.appendChild(this._listBox);
6791
+
6792
+ // 创建底部按钮
6793
+ const footer = this._createFooter();
6794
+ this._modal.appendChild(footer);
6795
+
6796
+ this._overlay.appendChild(this._modal);
6797
+ document.body.appendChild(this._overlay);
6798
+
6799
+ // 聚焦搜索框
6800
+ // setTimeout(() => {
6801
+ // const searchInput = this._modal.querySelector('.custom-search-input');
6802
+ // if (searchInput) {
6803
+ // searchInput.focus();
6804
+ // }
6805
+ // }, 100);
6806
+
6807
+ // 点击遮罩关闭
6808
+ this._overlay.addEventListener('click', (e) => {
6809
+ if (e.target === this._overlay) {
6810
+ this._closeModal();
6811
+ }
6812
+ });
6813
+
6814
+ // ESC 键关闭
6815
+ this._handleKeydown = (e) => {
6816
+ if (e.key === 'Escape') {
6817
+ this._closeModal();
6818
+ }
6819
+ };
6820
+ document.addEventListener('keydown', this._handleKeydown);
6821
+
6822
+ this._renderList('');
6823
+ }
6824
+
6825
+ _createHeader() {
6826
+ const header = document.createElement('div');
6827
+ header.style.cssText = `
6828
+ padding: 1.25rem 1.25rem 1rem 1.25rem;
6829
+ border-bottom: 1px solid #e2e8f0;
6830
+ background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);
6831
+ `;
6832
+
6833
+ const title = document.createElement('h2');
6834
+ title.textContent = this._title;
6835
+ title.style.cssText = `
6836
+ margin: 0 0 0.5rem 0;
6837
+ font-size: 1.125rem;
6838
+ font-weight: 600;
6839
+ color: #1e293b;
6840
+ display: flex;
6841
+ align-items: center;
6842
+ gap: 0.5rem;
6843
+ `;
6844
+
6845
+ // 添加图标
6846
+ const icon = document.createElement('span');
6847
+ icon.innerHTML = '📋';
6848
+ icon.style.fontSize = '1.25rem';
6849
+ title.insertBefore(icon, title.firstChild);
6850
+
6851
+ const subtitle = document.createElement('p');
6852
+ subtitle.textContent = `共 ${this._originalOptions.length} 个选项,已选择 ${this._selectedOptions.length} 个`;
6853
+ subtitle.style.cssText = `
6854
+ margin: 0;
6855
+ font-size: 0.8125rem;
6856
+ color: #64748b;
6857
+ `;
6858
+
6859
+ const closeBtn = document.createElement('button');
6860
+ closeBtn.innerHTML = '✕';
6861
+ closeBtn.style.cssText = `
6862
+ position: absolute;
6863
+ top: 1rem;
6864
+ right: 1rem;
6865
+ width: 1.75rem;
6866
+ height: 1.75rem;
6867
+ border: none;
6868
+ background: #f1f5f9;
6869
+ color: #64748b;
6870
+ border-radius: 50%;
6871
+ cursor: pointer;
6872
+ display: flex;
6873
+ align-items: center;
6874
+ justify-content: center;
6875
+ font-size: 0.875rem;
6876
+ transition: all 0.2s ease;
6877
+ font-weight: 500;
6878
+ `;
6879
+ closeBtn.addEventListener('mouseenter', () => {
6880
+ closeBtn.style.background = '#ef4444';
6881
+ closeBtn.style.color = 'white';
6882
+ closeBtn.style.transform = 'rotate(90deg)';
6883
+ });
6884
+ closeBtn.addEventListener('mouseleave', () => {
6885
+ closeBtn.style.background = '#f1f5f9';
6886
+ closeBtn.style.color = '#64748b';
6887
+ closeBtn.style.transform = 'rotate(0deg)';
6888
+ });
6889
+ closeBtn.addEventListener('click', () => this._closeModal());
6890
+
6891
+ header.style.position = 'relative';
6892
+ header.appendChild(title);
6893
+ header.appendChild(subtitle);
6894
+ header.appendChild(closeBtn);
6895
+
6896
+ return header;
6897
+ }
6898
+
6899
+ _createSearchSection() {
6900
+ const section = document.createElement('div');
6901
+ section.style.cssText = `
6902
+ padding: 1.25rem 1.25rem 1rem 1.25rem;
6903
+ `;
6904
+
6905
+ const searchContainer = document.createElement('div');
6906
+ searchContainer.style.cssText = `
6907
+ position: relative;
6908
+ `;
6909
+
6910
+ const searchIcon = document.createElement('div');
6911
+ searchIcon.innerHTML = '🔍';
6912
+ searchIcon.style.cssText = `
6913
+ position: absolute;
6914
+ left: 0.875rem;
6915
+ top: 50%;
6916
+ transform: translateY(-50%);
6917
+ font-size: 0.875rem;
6918
+ color: #94a3b8;
6919
+ pointer-events: none;
6920
+ `;
6921
+
6629
6922
  const searchInput = document.createElement('input');
6630
6923
  searchInput.placeholder = '搜索选项...';
6631
6924
  searchInput.className = 'custom-search-input';
6632
6925
  searchInput.style.cssText = `
6633
6926
  width: 100%;
6634
- padding: 8px;
6635
- border: 1px solid #ccc;
6636
- border-radius: 4px;
6637
- margin-bottom: 12px;
6927
+ padding: 0.75rem 1rem 0.75rem 2.5rem;
6928
+ border: 2px solid #e2e8f0;
6929
+ border-radius: 0.5rem;
6930
+ font-size: 0.875rem;
6931
+ background: white;
6932
+ transition: all 0.3s ease;
6933
+ box-sizing: border-box;
6934
+ font-family: inherit;
6935
+ outline: none;
6638
6936
  `;
6937
+
6938
+ searchInput.addEventListener('focus', () => {
6939
+ searchInput.style.borderColor = '#667eea';
6940
+ searchInput.style.boxShadow = '0 0 0 3px rgba(102, 126, 234, 0.1)';
6941
+ });
6942
+
6943
+ searchInput.addEventListener('blur', () => {
6944
+ searchInput.style.borderColor = '#e2e8f0';
6945
+ searchInput.style.boxShadow = 'none';
6946
+ });
6947
+
6639
6948
  searchInput.addEventListener('input', (e) => {
6640
6949
  this._renderList(e.target.value);
6641
6950
  });
6642
6951
 
6643
- this._modal.appendChild(searchInput);
6952
+ searchContainer.appendChild(searchIcon);
6953
+ searchContainer.appendChild(searchInput);
6954
+ section.appendChild(searchContainer);
6644
6955
 
6645
- // 列表区域
6646
- this._listBox = document.createElement('div');
6647
- this._listBox.style.cssText = `
6648
- flex: 1;
6649
- overflow-y: auto;
6650
- padding-right: 4px;
6651
- `;
6652
- this._modal.appendChild(this._listBox);
6956
+ return section;
6957
+ }
6653
6958
 
6654
- // 底部按钮
6959
+ _createFooter() {
6655
6960
  const footer = document.createElement('div');
6656
6961
  footer.style.cssText = `
6657
- margin-top: 12px;
6962
+ padding: 1rem 1.25rem;
6963
+ background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);
6964
+ border-top: 1px solid #e2e8f0;
6658
6965
  display: flex;
6659
6966
  justify-content: flex-end;
6660
- gap: 8px;
6967
+ gap: 0.75rem;
6661
6968
  `;
6662
6969
 
6663
6970
  const cancelBtn = document.createElement('button');
6664
6971
  cancelBtn.textContent = '取消';
6665
6972
  cancelBtn.style.cssText = `
6666
- padding: 6px 12px;
6667
- background: #ccc;
6668
- border: none;
6669
- border-radius: 4px;
6973
+ padding: 0.5rem 1rem;
6974
+ background: white;
6975
+ border: 1px solid #d1d5db;
6976
+ border-radius: 0.375rem;
6977
+ cursor: pointer;
6978
+ font-size: 0.875rem;
6979
+ font-weight: 500;
6980
+ color: #374151;
6981
+ transition: all 0.2s ease;
6982
+ font-family: inherit;
6670
6983
  `;
6984
+ cancelBtn.addEventListener('mouseenter', () => {
6985
+ cancelBtn.style.borderColor = '#ef4444';
6986
+ cancelBtn.style.color = '#ef4444';
6987
+ cancelBtn.style.transform = 'translateY(-1px)';
6988
+ });
6989
+ cancelBtn.addEventListener('mouseleave', () => {
6990
+ cancelBtn.style.borderColor = '#d1d5db';
6991
+ cancelBtn.style.color = '#374151';
6992
+ cancelBtn.style.transform = 'translateY(0)';
6993
+ });
6671
6994
  cancelBtn.addEventListener('click', () => this._closeModal());
6672
6995
 
6673
6996
  const okBtn = document.createElement('button');
6674
6997
  okBtn.textContent = '确定';
6675
6998
  okBtn.style.cssText = `
6676
- padding: 6px 12px;
6999
+ padding: 0.5rem 1rem;
6677
7000
  background: #007cba;
6678
7001
  color: white;
6679
7002
  border: none;
6680
- border-radius: 4px;
7003
+ border-radius: 0.375rem;
7004
+ cursor: pointer;
7005
+ font-size: 0.875rem;
7006
+ font-weight: 500;
7007
+ transition: all 0.2s ease;
7008
+ font-family: inherit;
7009
+ box-shadow: 0 2px 4px rgba(0, 124, 186, 0.2);
6681
7010
  `;
7011
+ okBtn.addEventListener('mouseenter', () => {
7012
+ okBtn.style.background = '#005a87';
7013
+ okBtn.style.transform = 'translateY(-1px)';
7014
+ okBtn.style.boxShadow = '0 4px 8px rgba(0, 124, 186, 0.3)';
7015
+ });
7016
+ okBtn.addEventListener('mouseleave', () => {
7017
+ okBtn.style.background = '#007cba';
7018
+ okBtn.style.transform = 'translateY(0)';
7019
+ okBtn.style.boxShadow = '0 2px 4px rgba(0, 124, 186, 0.2)';
7020
+ });
6682
7021
  okBtn.addEventListener('click', () => this._confirm());
6683
7022
 
6684
7023
  footer.appendChild(cancelBtn);
6685
7024
  footer.appendChild(okBtn);
6686
- this._modal.appendChild(footer);
6687
-
6688
- this._overlay.appendChild(this._modal);
6689
- document.body.appendChild(this._overlay);
6690
-
6691
- // 初始化列表
6692
- this._renderList('');
7025
+ return footer;
6693
7026
  }
6694
7027
 
6695
- /** 搜索过滤 */
6696
7028
  _renderList(keyword) {
6697
7029
  this._listBox.innerHTML = '';
6698
7030
 
@@ -6706,53 +7038,126 @@ class CustomOptionsControl {
6706
7038
 
6707
7039
  if (list.length === 0) {
6708
7040
  const empty = document.createElement('div');
6709
- empty.textContent = `未找到相关结果`;
6710
- empty.style.textAlign = 'center';
6711
- empty.style.padding = '20px';
7041
+ empty.style.cssText = `
7042
+ text-align: center;
7043
+ padding: 2.5rem 1rem;
7044
+ color: #94a3b8;
7045
+ `;
7046
+ empty.innerHTML = `
7047
+ <div style="font-size: 2.5rem; margin-bottom: 0.75rem; opacity: 0.6;">🔍</div>
7048
+ <div style="font-size: 1rem; font-weight: 500; margin-bottom: 0.25rem; color: #64748b;">未找到相关结果</div>
7049
+ <div style="font-size: 0.8125rem;">尝试使用其他关键词搜索</div>
7050
+ `;
6712
7051
  this._listBox.appendChild(empty);
6713
7052
  return;
6714
7053
  }
6715
7054
 
6716
- list.forEach((opt) => {
7055
+ // 添加选项统计
7056
+ const stats = document.createElement('div');
7057
+ stats.style.cssText = `
7058
+ padding: 0.5rem 0;
7059
+ font-size: 0.8125rem;
7060
+ color: #64748b;
7061
+ border-bottom: 1px solid #f1f5f9;
7062
+ margin-bottom: 0.5rem;
7063
+ `;
7064
+ stats.textContent = `找到 ${list.length} 个相关选项`;
7065
+ this._listBox.appendChild(stats);
7066
+
7067
+ list.forEach((opt, index) => {
6717
7068
  const item = document.createElement('label');
7069
+ item.className = 'custom-list-item';
6718
7070
  item.style.cssText = `
6719
7071
  display: flex;
6720
7072
  align-items: center;
6721
- padding: 6px 0;
7073
+ padding: 0.75rem;
6722
7074
  cursor: pointer;
7075
+ border-radius: 0.5rem;
7076
+ margin-bottom: 0.375rem;
7077
+ transition: all 0.2s ease;
7078
+ border: 2px solid transparent;
7079
+ background: white;
7080
+ position: relative;
7081
+ overflow: hidden;
6723
7082
  `;
6724
7083
 
6725
7084
  const checkbox = document.createElement('input');
6726
7085
  checkbox.type = 'checkbox';
7086
+ checkbox.className = 'custom-checkbox';
6727
7087
  checkbox.value = opt.value;
6728
7088
  checkbox.checked = this._selectedOptions.includes(opt.value);
6729
- checkbox.style.marginRight = '8px';
6730
- checkbox.addEventListener('change', () => this._toggle(opt.value));
7089
+ checkbox.style.marginRight = '0.75rem';
6731
7090
 
6732
7091
  const labelSpan = document.createElement('span');
6733
7092
  labelSpan.innerHTML = this._highlight(opt.label, keyword);
7093
+ labelSpan.style.cssText = `
7094
+ flex: 1;
7095
+ font-size: 0.875rem;
7096
+ color: #374151;
7097
+ line-height: 1.4;
7098
+ font-weight: 500;
7099
+ `;
7100
+
7101
+ // 添加选中状态的视觉反馈
7102
+ if (checkbox.checked) {
7103
+ item.style.backgroundColor = '#f0f4ff';
7104
+ item.style.borderColor = '#667eea';
7105
+ }
7106
+
7107
+ checkbox.addEventListener('change', () => {
7108
+ this._toggle(opt.value);
7109
+
7110
+ // 更新项目样式
7111
+ if (checkbox.checked) {
7112
+ item.style.backgroundColor = '#f0f4ff';
7113
+ item.style.borderColor = '#667eea';
7114
+ } else {
7115
+ item.style.backgroundColor = 'white';
7116
+ item.style.borderColor = 'transparent';
7117
+ }
7118
+
7119
+ // 更新标题中的统计信息
7120
+ const subtitle = this._modal.querySelector('p');
7121
+ if (subtitle) {
7122
+ subtitle.textContent = `共 ${this._originalOptions.length} 个选项,已选择 ${this._selectedOptions.length} 个`;
7123
+ }
7124
+ });
6734
7125
 
6735
7126
  item.appendChild(checkbox);
6736
7127
  item.appendChild(labelSpan);
6737
7128
 
7129
+ // 添加进入动画
7130
+ item.style.opacity = '0';
7131
+ item.style.transform = 'translateY(10px)';
6738
7132
  this._listBox.appendChild(item);
7133
+
7134
+ setTimeout(() => {
7135
+ item.style.transition = 'all 0.3s ease';
7136
+ item.style.opacity = '1';
7137
+ item.style.transform = 'translateY(0)';
7138
+ }, index * 30);
6739
7139
  });
6740
7140
  }
6741
7141
 
6742
- /** 高亮关键词 */
6743
7142
  _highlight(text, key) {
6744
7143
  if (!key) return text;
6745
- return text.replace(new RegExp(`(${key})`, 'gi'), `<mark>$1</mark>`);
7144
+ const regex = new RegExp(`(${this._escapeRegExp(key)})`, 'gi');
7145
+ return text.replace(regex, '<mark style="background: linear-gradient(120deg, #fef3c7 0%, #fde68a 100%); padding: 0.125rem 0.25rem; border-radius: 0.25rem; font-weight: 600;">$1</mark>');
7146
+ }
7147
+
7148
+ _escapeRegExp(string) {
7149
+ return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
6746
7150
  }
6747
7151
 
6748
- /** 选择切换 */
6749
7152
  _toggle(value) {
6750
7153
  const index = this._selectedOptions.indexOf(value);
6751
- if (index >= 0) this._selectedOptions.splice(index, 1);
6752
- else this._selectedOptions.push(value);
7154
+ if (index >= 0) {
7155
+ this._selectedOptions.splice(index, 1);
7156
+ } else {
7157
+ this._selectedOptions.push(value);
7158
+ }
6753
7159
  }
6754
7160
 
6755
- /** 点击确定 */
6756
7161
  _confirm() {
6757
7162
  this._onConfirm({
6758
7163
  selectedOptions: this._selectedOptions,
@@ -6764,17 +7169,28 @@ class CustomOptionsControl {
6764
7169
  this._closeModal();
6765
7170
  }
6766
7171
 
6767
- /** 销毁弹窗 */
6768
7172
  _closeModal() {
6769
7173
  if (this._overlay) {
6770
- document.body.removeChild(this._overlay);
6771
- this._overlay = null;
6772
- this._modal = null;
7174
+ // 添加退出动画
7175
+ this._modal.style.animation = 'modalSlideIn 0.2s ease-out reverse';
7176
+ this._overlay.style.animation = 'modalBackdropFadeIn 0.2s ease-out reverse';
7177
+
7178
+ setTimeout(() => {
7179
+ if (this._overlay && this._overlay.parentNode) {
7180
+ document.body.removeChild(this._overlay);
7181
+ }
7182
+ this._overlay = null;
7183
+ this._modal = null;
7184
+ }, 200);
7185
+
7186
+ document.removeEventListener('keydown', this._handleKeydown);
6773
7187
  }
6774
7188
  }
6775
7189
 
6776
7190
  onRemove() {
6777
- if (this._container) this._container.remove();
7191
+ if (this._container) {
7192
+ this._container.remove();
7193
+ }
6778
7194
  this._closeModal();
6779
7195
  }
6780
7196
  }