im-ui-mobile 0.1.0 → 0.1.2

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.
Files changed (85) hide show
  1. package/components/im-avatar/im-avatar.vue +7 -7
  2. package/components/im-badge/im-badge.vue +326 -0
  3. package/components/im-button/im-button.vue +71 -34
  4. package/components/im-card/im-card.vue +563 -0
  5. package/components/im-chat-item/im-chat-item.vue +5 -4
  6. package/components/im-col/im-col.vue +191 -0
  7. package/components/im-dialog/im-dialog.vue +543 -0
  8. package/components/im-double-tap-view/im-double-tap-view.vue +93 -0
  9. package/components/im-emoji-picker/im-emoji-picker.vue +1143 -0
  10. package/components/im-friend-item/im-friend-item.vue +1 -1
  11. package/components/im-group-item/im-group-item.vue +1 -1
  12. package/components/im-group-member-selector/im-group-member-selector.vue +5 -5
  13. package/components/im-group-rtc-join/im-group-rtc-join.vue +8 -8
  14. package/components/im-icon/im-icon.vue +593 -0
  15. package/components/im-image-upload/im-image-upload.vue +0 -2
  16. package/components/im-link/im-link.vue +628 -0
  17. package/components/im-loading/im-loading.vue +13 -4
  18. package/components/im-mention-picker/im-mention-picker.vue +8 -7
  19. package/components/im-message-action/im-message-action.vue +678 -0
  20. package/components/im-message-item/im-message-item.vue +28 -26
  21. package/components/im-message-list/im-message-list.vue +1108 -0
  22. package/components/im-modal/im-modal.vue +373 -0
  23. package/components/im-nav-bar/im-nav-bar.vue +689 -75
  24. package/components/im-parse/im-parse.vue +1054 -0
  25. package/components/im-popup/im-popup.vue +467 -0
  26. package/components/im-read-receipt/im-read-receipt.vue +10 -10
  27. package/components/im-row/im-row.vue +189 -0
  28. package/components/im-search/im-search.vue +762 -0
  29. package/components/im-sku/im-sku.vue +720 -0
  30. package/components/im-sku/utils/helper.ts +182 -0
  31. package/components/im-stepper/im-stepper.vue +585 -0
  32. package/components/im-stepper/utils/helper.ts +167 -0
  33. package/components/im-tabs/im-tabs.vue +1022 -0
  34. package/components/im-tabs/tabs-navigation.vue +489 -0
  35. package/components/im-tabs/utils/helper.ts +181 -0
  36. package/components/im-tabs-tab-pane/im-tabs-tab-pane.vue +145 -0
  37. package/components/im-upload/im-upload.vue +1236 -0
  38. package/components/im-voice-input/im-voice-input.vue +1 -1
  39. package/index.js +3 -5
  40. package/index.scss +19 -0
  41. package/libs/emoji-data.ts +229 -0
  42. package/libs/index.ts +16 -16
  43. package/package.json +1 -2
  44. package/styles/button.scss +33 -33
  45. package/theme.scss +2 -2
  46. package/types/components/badge.d.ts +42 -0
  47. package/types/components/button.d.ts +2 -1
  48. package/types/components/card.d.ts +122 -0
  49. package/types/components/col.d.ts +37 -0
  50. package/types/components/dialog.d.ts +125 -0
  51. package/types/components/double-tap-view.d.ts +31 -0
  52. package/types/components/emoji-picker.d.ts +121 -0
  53. package/types/components/group-rtc-join.d.ts +1 -1
  54. package/types/components/icon.d.ts +77 -0
  55. package/types/components/link.d.ts +55 -0
  56. package/types/components/loading.d.ts +1 -0
  57. package/types/components/message-action.d.ts +96 -0
  58. package/types/components/message-item.d.ts +2 -2
  59. package/types/components/message-list.d.ts +136 -0
  60. package/types/components/modal.d.ts +106 -0
  61. package/types/components/nav-bar.d.ts +125 -0
  62. package/types/components/parse.d.ts +90 -0
  63. package/types/components/popup.d.ts +58 -0
  64. package/types/components/row.d.ts +31 -0
  65. package/types/components/search.d.ts +54 -0
  66. package/types/components/sku.d.ts +195 -0
  67. package/types/components/stepper.d.ts +99 -0
  68. package/types/components/tabs-tab-pane.d.ts +27 -0
  69. package/types/components/tabs.d.ts +117 -0
  70. package/types/components/upload.d.ts +137 -0
  71. package/types/components.d.ts +19 -1
  72. package/types/index.d.ts +38 -1
  73. package/types/libs/index.d.ts +10 -10
  74. package/types/utils/base64.d.ts +5 -0
  75. package/types/utils/dom.d.ts +3 -0
  76. package/types/utils/enums.d.ts +4 -5
  77. package/types/utils/validator.d.ts +74 -0
  78. package/utils/base64.js +18 -0
  79. package/utils/dom.js +353 -1
  80. package/utils/enums.js +4 -5
  81. package/utils/validator.js +230 -0
  82. package/components/im-file-upload/im-file-upload.vue +0 -309
  83. package/plugins/uview-plus.js +0 -29
  84. package/types/components/arrow-bar.d.ts +0 -14
  85. package/types/components/file-upload.d.ts +0 -58
@@ -0,0 +1,762 @@
1
+ <template>
2
+ <view class="im-search" :class="[
3
+ isFocused?'im-search--focus': '',
4
+ disabled?'im-search--disabled': '',
5
+ `im-search--${size}`
6
+ ]">
7
+ <!-- 搜索图标 -->
8
+ <view class="im-search__icon" @tap="handleIconClick">
9
+ <slot name="icon">
10
+ <!-- <text class="im-search__icon-text">🔍</text> -->
11
+ <im-icon size="38" name="search" />
12
+ </slot>
13
+ </view>
14
+
15
+ <!-- 搜索输入框 -->
16
+ <input
17
+ ref="inputRef"
18
+ class="im-search__input"
19
+ :type="inputType"
20
+ :value="modelValue"
21
+ :placeholder="placeholder"
22
+ :placeholder-style="placeholderStyle"
23
+ :maxlength="maxlength"
24
+ :disabled="disabled"
25
+ :focus="autoFocus"
26
+ :confirm-type="confirmType"
27
+ :adjust-position="adjustPosition"
28
+ :cursor-spacing="cursorSpacing"
29
+ :show-confirm-bar="showConfirmBar"
30
+ @input="handleInput"
31
+ @focus="handleFocus"
32
+ @blur="handleBlur"
33
+ @confirm="handleConfirm"
34
+ @keyboardheightchange="handleKeyboardHeightChange"
35
+ />
36
+
37
+ <!-- 清除按钮 -->
38
+ <view
39
+ v-if="showClear && modelValue && !disabled"
40
+ class="im-search__clear"
41
+ @tap="handleClear"
42
+ >
43
+ <slot name="clear-icon">
44
+ <text class="im-search__clear-text">✕</text>
45
+ </slot>
46
+ </view>
47
+
48
+ <!-- 取消按钮 -->
49
+ <view
50
+ v-if="showCancel"
51
+ class="im-search__cancel"
52
+ :class="{ 'im-search__cancel--show': modelValue || isFocused || alwaysShowCancel }"
53
+ @tap="handleCancel"
54
+ >
55
+ <slot name="cancel-text">
56
+ <text class="im-search__cancel-text">{{ cancelText }}</text>
57
+ </slot>
58
+ </view>
59
+
60
+ <!-- 搜索历史 -->
61
+ <view v-if="showHistory && historyVisible && searchHistory.length > 0" class="im-search__history">
62
+ <view class="im-search__history-header">
63
+ <text class="im-search__history-title">搜索历史</text>
64
+ <view class="im-search__history-clear" @tap="clearHistory">
65
+ <text class="im-search__history-clear-text">清空</text>
66
+ </view>
67
+ </view>
68
+ <view class="im-search__history-list">
69
+ <view
70
+ v-for="(item, index) in searchHistory"
71
+ :key="index"
72
+ class="im-search__history-item"
73
+ @tap="handleHistoryClick(item)"
74
+ >
75
+ <text class="im-search__history-item-text">{{ item }}</text>
76
+ <text
77
+ class="im-search__history-item-delete"
78
+ @tap.stop="deleteHistoryItem(index)"
79
+ >✕</text>
80
+ </view>
81
+ </view>
82
+ </view>
83
+
84
+ <!-- 搜索建议 -->
85
+ <view v-if="showSuggestions && suggestionsVisible && suggestions.length > 0" class="im-search__suggestions">
86
+ <view
87
+ v-for="(item, index) in suggestions"
88
+ :key="index"
89
+ class="im-search__suggestion-item"
90
+ @tap="handleSuggestionClick(item)"
91
+ >
92
+ <slot name="suggestion" :item="item" :index="index">
93
+ <text class="im-search__suggestion-text">{{ formatSuggestion(item) }}</text>
94
+ </slot>
95
+ </view>
96
+ </view>
97
+
98
+ <!-- 搜索结果 -->
99
+ <slot name="results" :results="searchResults"></slot>
100
+ </view>
101
+ </template>
102
+
103
+ <script setup lang="ts">
104
+ import { ref, computed, watch, nextTick } from 'vue'
105
+
106
+ // 定义 Props
107
+ interface Props {
108
+ // 值
109
+ modelValue?: string
110
+
111
+ // 样式配置
112
+ shape?: 'square' | 'round'
113
+ size?: 'small' | 'medium' | 'large'
114
+ bgColor?: string
115
+ borderColor?: string
116
+ textColor?: string
117
+ placeholderColor?: string
118
+
119
+ // 输入框配置
120
+ placeholder?: string
121
+ placeholderStyle?: string
122
+ inputType?: 'text' | 'number' | 'idcard' | 'digit' | 'textarea'
123
+ maxlength?: number
124
+ disabled?: boolean
125
+ autoFocus?: boolean
126
+ confirmType?: 'send' | 'search' | 'next' | 'go' | 'done'
127
+ adjustPosition?: boolean
128
+ cursorSpacing?: number
129
+ showConfirmBar?: boolean
130
+
131
+ // 功能配置
132
+ showClear?: boolean
133
+ showCancel?: boolean
134
+ alwaysShowCancel?: boolean
135
+ cancelText?: string
136
+ showHistory?: boolean
137
+ showSuggestions?: boolean
138
+
139
+ // 搜索相关
140
+ searchDelay?: number
141
+ minLength?: number
142
+ maxHistory?: number
143
+ suggestions?: any[]
144
+ suggestionFormatter?: (item: any) => string
145
+
146
+ // 自定义事件
147
+ onSearch?: (value: string) => void
148
+ onClear?: () => void
149
+ onCancel?: () => void
150
+ }
151
+
152
+ // 定义 Emits
153
+ interface Emits {
154
+ (e: 'update:modelValue', value: string): void
155
+ (e: 'input', value: string): void
156
+ (e: 'focus', event: any): void
157
+ (e: 'blur', event: any): void
158
+ (e: 'confirm', value: string): void
159
+ (e: 'clear'): void
160
+ (e: 'cancel'): void
161
+ (e: 'search', value: string): void
162
+ (e: 'history-click', value: string): void
163
+ (e: 'suggestion-click', item: any): void
164
+ (e: 'keyboardheightchange', height: number): void
165
+ }
166
+
167
+ // 定义 Props 默认值
168
+ const props = withDefaults(defineProps<Props>(), {
169
+ modelValue: '',
170
+
171
+ shape: 'round',
172
+ size: 'medium',
173
+ bgColor: '#f5f5f5',
174
+ borderColor: '#e0e0e0',
175
+ textColor: '#333333',
176
+ placeholderColor: '#999999',
177
+
178
+ placeholder: '请输入搜索内容',
179
+ placeholderStyle: '',
180
+ inputType: 'text',
181
+ maxlength: 100,
182
+ disabled: false,
183
+ autoFocus: false,
184
+ confirmType: 'search',
185
+ adjustPosition: true,
186
+ cursorSpacing: 0,
187
+ showConfirmBar: true,
188
+
189
+ showClear: true,
190
+ showCancel: true,
191
+ alwaysShowCancel: false,
192
+ cancelText: '取消',
193
+ showHistory: true,
194
+ showSuggestions: false,
195
+
196
+ searchDelay: 300,
197
+ minLength: 1,
198
+ maxHistory: 10,
199
+ suggestions: () => [],
200
+ suggestionFormatter: (item:any) => typeof item === 'string' ? item : item.text || item.name || JSON.stringify(item)
201
+ })
202
+
203
+ const emit = defineEmits<Emits>()
204
+
205
+ // 响应式状态
206
+ const inputRef = ref<any>(null)
207
+ const isFocused = ref(false)
208
+ const historyVisible = ref(false)
209
+ const suggestionsVisible = ref(false)
210
+ const searchTimer = ref<any | null>(null)
211
+ const searchResults = ref<any[]>([])
212
+
213
+ // 搜索历史
214
+ const searchHistory = ref<string[]>([])
215
+
216
+ // 初始化搜索历史
217
+ const initHistory = () => {
218
+ try {
219
+ const history = uni.getStorageSync('im_search_history')
220
+ if (history) {
221
+ searchHistory.value = JSON.parse(history)
222
+ }
223
+ } catch (error) {
224
+ console.error('读取搜索历史失败:', error)
225
+ }
226
+ }
227
+
228
+ // 保存搜索历史
229
+ const saveHistory = (value: string) => {
230
+ if (!value.trim()) return
231
+
232
+ // 移除重复项
233
+ const index = searchHistory.value.indexOf(value)
234
+ if (index > -1) {
235
+ searchHistory.value.splice(index, 1)
236
+ }
237
+
238
+ // 添加到开头
239
+ searchHistory.value.unshift(value)
240
+
241
+ // 限制历史记录数量
242
+ if (searchHistory.value.length > props.maxHistory) {
243
+ searchHistory.value = searchHistory.value.slice(0, props.maxHistory)
244
+ }
245
+
246
+ // 保存到本地存储
247
+ try {
248
+ uni.setStorageSync('im_search_history', JSON.stringify(searchHistory.value))
249
+ } catch (error) {
250
+ console.error('保存搜索历史失败:', error)
251
+ }
252
+ }
253
+
254
+ // 清空搜索历史
255
+ const clearHistory = () => {
256
+ searchHistory.value = []
257
+ try {
258
+ uni.removeStorageSync('im_search_history')
259
+ } catch (error) {
260
+ console.error('清除搜索历史失败:', error)
261
+ }
262
+ }
263
+
264
+ // 删除单个历史记录
265
+ const deleteHistoryItem = (index: number) => {
266
+ searchHistory.value.splice(index, 1)
267
+ try {
268
+ uni.setStorageSync('im_search_history', JSON.stringify(searchHistory.value))
269
+ } catch (error) {
270
+ console.error('删除搜索历史失败:', error)
271
+ }
272
+ }
273
+
274
+ // 处理输入
275
+ const handleInput = (event: any) => {
276
+ const value = event.detail?.value || ''
277
+ emit('update:modelValue', value)
278
+ emit('input', value)
279
+
280
+ // 防抖搜索
281
+ if (searchTimer.value) {
282
+ clearTimeout(searchTimer.value)
283
+ }
284
+
285
+ searchTimer.value = setTimeout(() => {
286
+ if (value.trim().length >= props.minLength) {
287
+ emit('search', value)
288
+ if (props.onSearch) {
289
+ props.onSearch(value)
290
+ }
291
+ }
292
+
293
+ // 显示/隐藏建议
294
+ suggestionsVisible.value = value.trim().length > 0 && props.showSuggestions
295
+ historyVisible.value = value.trim().length === 0 && props.showHistory
296
+ }, props.searchDelay)
297
+ }
298
+
299
+ // 处理焦点
300
+ const handleFocus = (event: any) => {
301
+ isFocused.value = true
302
+ historyVisible.value = props.showHistory && !props.modelValue
303
+ suggestionsVisible.value = props.showSuggestions && props.modelValue.length > 0
304
+ emit('focus', event)
305
+ }
306
+
307
+ // 处理失去焦点
308
+ const handleBlur = (event: any) => {
309
+ isFocused.value = false
310
+ historyVisible.value = false
311
+ suggestionsVisible.value = false
312
+ emit('blur', event)
313
+ }
314
+
315
+ // 处理确认
316
+ const handleConfirm = (event: any) => {
317
+ const value = event.detail?.value || props.modelValue
318
+ if (value.trim()) {
319
+ saveHistory(value.trim())
320
+ emit('confirm', value)
321
+ }
322
+ }
323
+
324
+ // 处理清除
325
+ const handleClear = () => {
326
+ emit('update:modelValue', '')
327
+ emit('input', '')
328
+ emit('clear')
329
+ historyVisible.value = props.showHistory
330
+ suggestionsVisible.value = false
331
+
332
+ // 聚焦输入框
333
+ nextTick(() => {
334
+ if (inputRef.value) {
335
+ focus()
336
+ }
337
+ })
338
+ }
339
+
340
+ // 处理取消
341
+ const handleCancel = () => {
342
+ emit('update:modelValue', '')
343
+ emit('input', '')
344
+ emit('cancel')
345
+ historyVisible.value = false
346
+ suggestionsVisible.value = false
347
+ isFocused.value = false
348
+
349
+ // 失去焦点
350
+ if (inputRef.value) {
351
+ blur()
352
+ }
353
+
354
+ if (props.onCancel) {
355
+ props.onCancel()
356
+ }
357
+ }
358
+
359
+ // 处理图标点击
360
+ const handleIconClick = () => {
361
+ if (inputRef.value) {
362
+ focus()
363
+ }
364
+ }
365
+
366
+ // 处理历史点击
367
+ const handleHistoryClick = (value: string) => {
368
+ emit('update:modelValue', value)
369
+ emit('input', value)
370
+ emit('history-click', value)
371
+ saveHistory(value)
372
+ historyVisible.value = false
373
+
374
+ // 触发搜索
375
+ if (value.trim().length >= props.minLength) {
376
+ emit('search', value)
377
+ if (props.onSearch) {
378
+ props.onSearch(value)
379
+ }
380
+ }
381
+
382
+ // 聚焦输入框
383
+ nextTick(() => {
384
+ if (inputRef.value) {
385
+ focus()
386
+ }
387
+ })
388
+ }
389
+
390
+ // 处理建议点击
391
+ const handleSuggestionClick = (item: any) => {
392
+ const value = props.suggestionFormatter(item)
393
+ emit('update:modelValue', value)
394
+ emit('input', value)
395
+ emit('suggestion-click', item)
396
+ saveHistory(value)
397
+ suggestionsVisible.value = false
398
+
399
+ // 触发搜索
400
+ if (value.trim().length >= props.minLength) {
401
+ emit('search', value)
402
+ if (props.onSearch) {
403
+ props.onSearch(value)
404
+ }
405
+ }
406
+ }
407
+
408
+ // 处理键盘高度变化
409
+ const handleKeyboardHeightChange = (event: any) => {
410
+ emit('keyboardheightchange', event.detail.height)
411
+ }
412
+
413
+ // 格式化建议内容
414
+ const formatSuggestion = (item: any) => {
415
+ return props.suggestionFormatter(item)
416
+ }
417
+
418
+ // 设置搜索结果
419
+ const setResults = (results: any[]) => {
420
+ searchResults.value = results
421
+ }
422
+
423
+ // 获取焦点
424
+ const focus = () => {
425
+ if (!props.disabled) {
426
+ isFocused.value = true
427
+
428
+ nextTick(() => {
429
+ // 使用 uniapp 的选择器 API
430
+ uni.createSelectorQuery()
431
+ .select('.im-search__input')
432
+ .boundingClientRect()
433
+ .exec((res) => {
434
+ if (res && res[0]) {
435
+ // 确保输入框在可视区域内
436
+ uni.pageScrollTo({
437
+ scrollTop: res[0].top - 100,
438
+ duration: 300
439
+ })
440
+ }
441
+ })
442
+
443
+ // 直接设置焦点(需要确保组件已渲染)
444
+ setTimeout(() => {
445
+ if (inputRef.value) {
446
+ // 在 uniapp 中,input 元素有原生的 focus 方法
447
+ inputRef.value.focus({
448
+ success: () => {
449
+ console.log('焦点设置成功')
450
+ },
451
+ fail: (err: any) => {
452
+ console.error('焦点设置失败:', err)
453
+ }
454
+ })
455
+ }
456
+ }, 100)
457
+ })
458
+ }
459
+ }
460
+
461
+ // 失去焦点
462
+ const blur = () => {
463
+ if (inputRef.value) {
464
+ inputRef.value.blur()
465
+ }
466
+ }
467
+
468
+ // 清空输入
469
+ const clear = () => {
470
+ handleClear()
471
+ }
472
+
473
+ // 初始化
474
+ initHistory()
475
+
476
+ // 暴露方法
477
+ defineExpose({
478
+ focus,
479
+ blur,
480
+ clear,
481
+ setResults,
482
+ clearHistory,
483
+ getHistory: () => [...searchHistory.value]
484
+ })
485
+ </script>
486
+
487
+ <style lang="scss" scoped>
488
+ .im-search {
489
+ display: flex;
490
+ align-items: center;
491
+ padding: 16rpx 24rpx;
492
+ background-color: v-bind('props.bgColor');
493
+ border: 2rpx solid v-bind('props.borderColor');
494
+ border-radius: 8rpx;
495
+ transition: all 0.3s ease;
496
+ position: relative;
497
+
498
+ &--focus {
499
+ border-color: #409eff;
500
+ background-color: #ffffff;
501
+ box-shadow: 0 4rpx 12rpx rgba(64, 158, 255, 0.1);
502
+ }
503
+
504
+ &--disabled {
505
+ opacity: 0.6;
506
+ cursor: not-allowed;
507
+ }
508
+
509
+ // 圆角样式
510
+ &--round {
511
+ border-radius: 100rpx;
512
+ }
513
+
514
+ // 尺寸样式
515
+ &--small {
516
+ padding: 12rpx 20rpx;
517
+
518
+ .im-search__input {
519
+ font-size: 26rpx;
520
+ height: 40rpx;
521
+ }
522
+ .im-search__icon {
523
+ width: 36rpx;
524
+ height: 36rpx;
525
+ margin-right: 12rpx;
526
+ }
527
+ }
528
+
529
+ &--medium {
530
+ padding: 16rpx 24rpx;
531
+ .im-search__input {
532
+ font-size: 28rpx;
533
+ height: 44rpx;
534
+ }
535
+ .im-search__icon {
536
+ width: 40rpx;
537
+ height: 40rpx;
538
+ margin-right: 16rpx;
539
+ }
540
+ }
541
+
542
+ &--large {
543
+ padding: 20rpx 28rpx;
544
+ .im-search__input {
545
+ font-size: 32rpx;
546
+ height: 48rpx;
547
+ }
548
+ .im-search__icon {
549
+ width: 44rpx;
550
+ height: 44rpx;
551
+ margin-right: 20rpx;
552
+ }
553
+ }
554
+ }
555
+
556
+ .im-search__icon {
557
+ flex-shrink: 0;
558
+ display: flex;
559
+ align-items: center;
560
+ justify-content: center;
561
+ cursor: pointer;
562
+
563
+ &-text {
564
+ font-size: 32rpx;
565
+ color: v-bind('props.placeholderColor');
566
+ }
567
+ }
568
+
569
+ .im-search__input {
570
+ flex: 1;
571
+ height: 44rpx;
572
+ font-size: 28rpx;
573
+ color: v-bind('props.textColor');
574
+ background-color: transparent;
575
+ border: none;
576
+ outline: none;
577
+
578
+ &::placeholder {
579
+ color: v-bind('props.placeholderColor');
580
+ }
581
+
582
+ &:disabled {
583
+ cursor: not-allowed;
584
+ }
585
+ }
586
+
587
+ .im-search__clear {
588
+ flex-shrink: 0;
589
+ display: flex;
590
+ align-items: center;
591
+ justify-content: center;
592
+ width: 36rpx;
593
+ height: 36rpx;
594
+ margin-left: 16rpx;
595
+ background-color: #e0e0e0;
596
+ border-radius: 50%;
597
+ cursor: pointer;
598
+ transition: all 0.3s;
599
+
600
+ &:active {
601
+ background-color: #c0c0c0;
602
+ transform: scale(0.95);
603
+ }
604
+
605
+ &-text {
606
+ font-size: 20rpx;
607
+ color: #666666;
608
+ line-height: 1;
609
+ }
610
+ }
611
+
612
+ .im-search__cancel {
613
+ flex-shrink: 0;
614
+ margin-left: 20rpx;
615
+ opacity: 0;
616
+ transform: translateX(20rpx);
617
+ transition: all 0.3s ease;
618
+ pointer-events: none;
619
+
620
+ &--show {
621
+ opacity: 1;
622
+ transform: translateX(0);
623
+ pointer-events: auto;
624
+ }
625
+
626
+ &-text {
627
+ font-size: 28rpx;
628
+ color: #409eff;
629
+ cursor: pointer;
630
+ white-space: nowrap;
631
+
632
+ &:active {
633
+ opacity: 0.8;
634
+ }
635
+ }
636
+ }
637
+
638
+ .im-search__history {
639
+ position: absolute;
640
+ top: 100%;
641
+ left: 0;
642
+ right: 0;
643
+ margin-top: 8rpx;
644
+ background-color: white;
645
+ border-radius: 8rpx;
646
+ box-shadow: 0 8rpx 40rpx rgba(0, 0, 0, 0.12);
647
+ z-index: 1000;
648
+ overflow: hidden;
649
+ }
650
+
651
+ .im-search__history-header {
652
+ display: flex;
653
+ justify-content: space-between;
654
+ align-items: center;
655
+ padding: 24rpx 32rpx 16rpx;
656
+ border-bottom: 2rpx solid #f5f5f5;
657
+ }
658
+
659
+ .im-search__history-title {
660
+ font-size: 26rpx;
661
+ color: #999999;
662
+ }
663
+
664
+ .im-search__history-clear {
665
+ padding: 8rpx 16rpx;
666
+ border-radius: 6rpx;
667
+ cursor: pointer;
668
+
669
+ &:active {
670
+ background-color: #f5f5f5;
671
+ }
672
+
673
+ &-text {
674
+ font-size: 24rpx;
675
+ color: #666666;
676
+ }
677
+ }
678
+
679
+ .im-search__history-list {
680
+ max-height: 400rpx;
681
+ overflow-y: auto;
682
+ }
683
+
684
+ .im-search__history-item {
685
+ display: flex;
686
+ justify-content: space-between;
687
+ align-items: center;
688
+ padding: 24rpx 32rpx;
689
+ border-bottom: 2rpx solid #f5f5f5;
690
+ cursor: pointer;
691
+ transition: background-color 0.2s;
692
+
693
+ &:last-child {
694
+ border-bottom: none;
695
+ }
696
+
697
+ &:active {
698
+ background-color: #f9f9f9;
699
+ }
700
+ }
701
+
702
+ .im-search__history-item-text {
703
+ flex: 1;
704
+ font-size: 28rpx;
705
+ color: #333333;
706
+ overflow: hidden;
707
+ text-overflow: ellipsis;
708
+ white-space: nowrap;
709
+ }
710
+
711
+ .im-search__history-item-delete {
712
+ flex-shrink: 0;
713
+ margin-left: 24rpx;
714
+ padding: 8rpx;
715
+ font-size: 22rpx;
716
+ color: #999999;
717
+ opacity: 0;
718
+ transition: opacity 0.3s;
719
+
720
+ .im-search__history-item:hover & {
721
+ opacity: 1;
722
+ }
723
+
724
+ &:active {
725
+ color: #ff4d4f;
726
+ }
727
+ }
728
+
729
+ .im-search__suggestions {
730
+ position: absolute;
731
+ top: 100%;
732
+ left: 0;
733
+ right: 0;
734
+ margin-top: 8rpx;
735
+ background-color: white;
736
+ border-radius: 8rpx;
737
+ box-shadow: 0 8rpx 40rpx rgba(0, 0, 0, 0.12);
738
+ z-index: 1000;
739
+ max-height: 400rpx;
740
+ overflow-y: auto;
741
+ }
742
+
743
+ .im-search__suggestion-item {
744
+ padding: 24rpx 32rpx;
745
+ border-bottom: 2rpx solid #f5f5f5;
746
+ cursor: pointer;
747
+ transition: background-color 0.2s;
748
+
749
+ &:last-child {
750
+ border-bottom: none;
751
+ }
752
+
753
+ &:active {
754
+ background-color: #f9f9f9;
755
+ }
756
+ }
757
+
758
+ .im-search__suggestion-text {
759
+ font-size: 28rpx;
760
+ color: #333333;
761
+ }
762
+ </style>