vite-uni-dev-tool 1.0.0 → 1.1.0

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 (168) hide show
  1. package/README.md +46 -0
  2. package/dist/const.cjs +1 -1
  3. package/dist/const.d.ts +12 -0
  4. package/dist/const.d.ts.map +1 -1
  5. package/dist/const.js +1 -1
  6. package/dist/core-shared.d.ts +1 -1
  7. package/dist/core-shared.d.ts.map +1 -1
  8. package/dist/core-shared.js +1 -1
  9. package/dist/core.d.ts +10 -3
  10. package/dist/core.d.ts.map +1 -1
  11. package/dist/core.js +2 -2
  12. package/dist/i18n/locales/en.cjs +1 -1
  13. package/dist/i18n/locales/en.d.ts +81 -0
  14. package/dist/i18n/locales/en.d.ts.map +1 -1
  15. package/dist/i18n/locales/en.js +1 -1
  16. package/dist/i18n/locales/zh-Hans.cjs +1 -1
  17. package/dist/i18n/locales/zh-Hans.d.ts +82 -1
  18. package/dist/i18n/locales/zh-Hans.d.ts.map +1 -1
  19. package/dist/i18n/locales/zh-Hans.js +1 -1
  20. package/dist/modules/devConsole/index.cjs +1 -1
  21. package/dist/modules/devConsole/index.js +3 -3
  22. package/dist/modules/devEvent/index.cjs +3 -3
  23. package/dist/modules/devEvent/index.d.ts +1 -0
  24. package/dist/modules/devEvent/index.d.ts.map +1 -1
  25. package/dist/modules/devEvent/index.js +3 -3
  26. package/dist/modules/devIntercept/index.cjs +14 -13
  27. package/dist/modules/devIntercept/index.d.ts +19 -0
  28. package/dist/modules/devIntercept/index.d.ts.map +1 -1
  29. package/dist/modules/devIntercept/index.js +14 -13
  30. package/dist/modules/devStore/index.cjs +1 -1
  31. package/dist/modules/devStore/index.d.ts +21 -0
  32. package/dist/modules/devStore/index.d.ts.map +1 -1
  33. package/dist/modules/devStore/index.js +1 -1
  34. package/dist/plugins/uniDevTool/transform/transformMain.cjs +1 -1
  35. package/dist/plugins/uniDevTool/transform/transformMain.js +1 -1
  36. package/dist/type.d.ts +47 -2
  37. package/dist/type.d.ts.map +1 -1
  38. package/dist/utils/language.cjs +1 -1
  39. package/dist/utils/language.d.ts.map +1 -1
  40. package/dist/utils/language.js +1 -1
  41. package/dist/utils/object.cjs +1 -1
  42. package/dist/utils/object.d.ts.map +1 -1
  43. package/dist/utils/object.js +1 -1
  44. package/dist/v3/DevTool/components/BluetoothList/BluetoothItem.vue +199 -0
  45. package/dist/v3/DevTool/components/BluetoothList/BluetoothTool.vue +730 -0
  46. package/dist/v3/DevTool/components/BluetoothList/index.vue +167 -0
  47. package/dist/v3/{CaptureScreen → DevTool/components/CaptureScreen}/index.vue +109 -109
  48. package/dist/v3/{ConsoleList → DevTool/components/ConsoleList}/ConsoleItem.vue +225 -224
  49. package/dist/v3/{ConsoleList → DevTool/components/ConsoleList}/RunJSInput.vue +247 -249
  50. package/dist/v3/{ConsoleList → DevTool/components/ConsoleList}/index.vue +171 -160
  51. package/dist/v3/{ConsoleList → DevTool/components/ConsoleList}/staticTips.ts +1145 -1145
  52. package/dist/v3/{DevToolButton → DevTool/components/DevToolButton}/index.vue +7 -4
  53. package/dist/v3/{DevToolTitle → DevTool/components/DevToolTitle}/index.vue +24 -24
  54. package/dist/v3/{DevToolWindow → DevTool/components/DevToolWindow}/DevToolOverlay.vue +197 -182
  55. package/dist/v3/{DevToolWindow → DevTool/components/DevToolWindow}/const.ts +28 -5
  56. package/dist/v3/{DevToolWindow → DevTool/components/DevToolWindow}/hooks/dataUtils.ts +48 -48
  57. package/dist/v3/{DevToolWindow → DevTool/components/DevToolWindow}/hooks/useDevToolData.ts +387 -338
  58. package/dist/v3/{DevToolWindow → DevTool/components/DevToolWindow}/hooks/useDevToolHandlers.ts +629 -549
  59. package/dist/v3/{DevToolWindow → DevTool/components/DevToolWindow}/hooks/useDevToolOverlay.ts +197 -184
  60. package/dist/v3/{DevToolWindow → DevTool/components/DevToolWindow}/index.vue +67 -16
  61. package/dist/v3/{ElEvent → DevTool/components/ElEvent}/ElEventItem.vue +105 -105
  62. package/dist/v3/{ElEvent → DevTool/components/ElEvent}/index.vue +106 -109
  63. package/dist/v3/{Instance → DevTool/components/Instance}/components/InstanceTreeNode.vue +265 -265
  64. package/dist/v3/{Instance → DevTool/components/Instance}/flatten.ts +226 -226
  65. package/dist/v3/{Instance → DevTool/components/Instance}/index.vue +94 -94
  66. package/dist/v3/{Instance → DevTool/components/Instance}/registry.ts +49 -49
  67. package/dist/v3/{Instance → DevTool/components/Instance}/transformTree.ts +375 -375
  68. package/dist/v3/{Instance → DevTool/components/Instance}/transformTreeCtx.ts +268 -268
  69. package/dist/v3/{Instance → DevTool/components/Instance}/typing.d.ts +43 -43
  70. package/dist/v3/{InstanceDetail → DevTool/components/InstanceDetail}/index.vue +485 -485
  71. package/dist/v3/{JsonDetail → DevTool/components/JsonDetail}/index.vue +70 -70
  72. package/dist/v3/{NFCList → DevTool/components/NFCList}/NFCItem.vue +112 -113
  73. package/dist/v3/{NFCList → DevTool/components/NFCList}/NFCTool.vue +454 -478
  74. package/dist/v3/{NFCList → DevTool/components/NFCList}/const.ts +56 -56
  75. package/dist/v3/{NFCList → DevTool/components/NFCList}/index.vue +94 -98
  76. package/dist/v3/{NetworkList → DevTool/components/NetworkList}/InterceptConfig.vue +624 -608
  77. package/dist/v3/{NetworkList → DevTool/components/NetworkList}/InterceptItem.vue +140 -140
  78. package/dist/v3/{NetworkList → DevTool/components/NetworkList}/NetworkDetail.vue +287 -296
  79. package/dist/v3/{NetworkList → DevTool/components/NetworkList}/NetworkIntercept.vue +88 -93
  80. package/dist/v3/{NetworkList → DevTool/components/NetworkList}/NetworkItem.vue +163 -167
  81. package/dist/v3/{NetworkList → DevTool/components/NetworkList}/NetworkSend.vue +589 -556
  82. package/dist/v3/{NetworkList → DevTool/components/NetworkList}/const.ts +4 -4
  83. package/dist/v3/{NetworkList → DevTool/components/NetworkList}/hooks/useNetworkForm.ts +86 -86
  84. package/dist/v3/{NetworkList → DevTool/components/NetworkList}/index.vue +160 -160
  85. package/dist/v3/{NetworkList → DevTool/components/NetworkList}/utils.ts +101 -101
  86. package/dist/v3/{Performance → DevTool/components/Performance}/index.vue +498 -495
  87. package/dist/v3/{Performance → DevTool/components/Performance}/modules/PerformanceMetrics.vue +153 -153
  88. package/dist/v3/{Performance → DevTool/components/Performance}/modules/PerformanceWidget.vue +12 -9
  89. package/dist/v3/{Performance → DevTool/components/Performance}/modules/usePerformanceChart.ts +460 -460
  90. package/dist/v3/{Performance → DevTool/components/Performance}/modules/usePerformanceData.ts +258 -258
  91. package/dist/v3/{PiniaList → DevTool/components/PiniaList}/index.vue +93 -94
  92. package/dist/v3/{RouteList → DevTool/components/RouteList}/index.vue +21 -24
  93. package/dist/v3/{RunJS → DevTool/components/RunJS}/index.vue +148 -148
  94. package/dist/v3/{ScanCodeList → DevTool/components/ScanCodeList}/ScanCodeItem.vue +97 -98
  95. package/dist/v3/{ScanCodeList → DevTool/components/ScanCodeList}/index.vue +100 -104
  96. package/dist/v3/{SettingButton → DevTool/components/SettingButton}/index.vue +45 -45
  97. package/dist/v3/{SettingList → DevTool/components/SettingList}/index.vue +218 -150
  98. package/dist/v3/DevTool/components/SettingList/modules/SettingBarrage.vue +304 -0
  99. package/dist/v3/{SettingList → DevTool/components/SettingList}/modules/SettingDevTool.vue +212 -208
  100. package/dist/v3/{SettingList → DevTool/components/SettingList}/modules/SettingInfo.vue +157 -119
  101. package/dist/v3/{SettingList → DevTool/components/SettingList}/modules/SettingLanguage.vue +74 -74
  102. package/dist/v3/{SettingList → DevTool/components/SettingList}/modules/SettingLog.vue +230 -230
  103. package/dist/v3/{SettingList → DevTool/components/SettingList}/modules/SettingNetwork.vue +3 -3
  104. package/dist/v3/{SettingList → DevTool/components/SettingList}/modules/SettingTheme.vue +37 -7
  105. package/dist/v3/{SettingList → DevTool/components/SettingList}/typing.d.ts +2 -2
  106. package/dist/v3/{SourceCode → DevTool/components/SourceCode}/Line.vue +127 -116
  107. package/dist/v3/{SourceCode → DevTool/components/SourceCode}/index.vue +8 -8
  108. package/dist/v3/{SourceCode → DevTool/components/SourceCode}/parseCode.ts +609 -701
  109. package/dist/v3/{StorageList → DevTool/components/StorageList}/index.vue +174 -174
  110. package/dist/v3/{TransferList → DevTool/components/TransferList}/TransferDetail.vue +268 -268
  111. package/dist/v3/{TransferList → DevTool/components/TransferList}/TransferItem.vue +4 -4
  112. package/dist/v3/{TransferList → DevTool/components/TransferList}/index.vue +8 -8
  113. package/dist/v3/{UniEvent → DevTool/components/UniEvent}/UniEventItem.vue +6 -7
  114. package/dist/v3/{UniEvent → DevTool/components/UniEvent}/index.vue +6 -6
  115. package/dist/v3/{VuexList → DevTool/components/VuexList}/index.vue +84 -84
  116. package/dist/v3/{WebSocket → DevTool/components/WebSocket}/WebSocketDetail.vue +8 -8
  117. package/dist/v3/{WebSocket → DevTool/components/WebSocket}/WebSocketItem.vue +4 -4
  118. package/dist/v3/{WebSocket → DevTool/components/WebSocket}/index.vue +8 -8
  119. package/dist/v3/DevTool/index.vue +179 -5
  120. package/dist/v3/{AppTransition → components/AppTransition}/index.vue +176 -170
  121. package/dist/v3/{AutoSizer → components/AutoSizer}/index.vue +192 -192
  122. package/dist/v3/{AutoSizer → components/AutoSizer}/index1.vue +184 -184
  123. package/dist/v3/{AutoSizer → components/AutoSizer}/utils.ts +49 -49
  124. package/dist/v3/components/Barrage/BarrageItem.vue +137 -0
  125. package/dist/v3/components/Barrage/index.vue +202 -0
  126. package/dist/v3/{CircularButton → components/CircularButton}/index.vue +84 -84
  127. package/dist/v3/{CustomSwiper → components/CustomSwiper}/CustomSwiperItem.vue +49 -49
  128. package/dist/v3/{CustomSwiper → components/CustomSwiper}/index.vue +104 -104
  129. package/dist/v3/{DraggableContainer → components/DraggableContainer}/index.vue +1 -1
  130. package/dist/v3/{Empty → components/Empty}/index.vue +29 -29
  131. package/dist/v3/{FilterInput → components/FilterInput}/index.vue +1 -1
  132. package/dist/v3/{FilterSelect → components/FilterSelect}/index.vue +179 -179
  133. package/dist/v3/{JsonPretty → components/JsonPretty}/components/Brackets/index.vue +27 -27
  134. package/dist/v3/{JsonPretty → components/JsonPretty}/components/Carets/index.vue +59 -59
  135. package/dist/v3/{JsonPretty → components/JsonPretty}/components/CheckController/index.vue +136 -136
  136. package/dist/v3/{JsonPretty → components/JsonPretty}/components/TreeNode/index.vue +387 -381
  137. package/dist/v3/{JsonPretty → components/JsonPretty}/hooks/useClipboard.ts +21 -21
  138. package/dist/v3/{JsonPretty → components/JsonPretty}/hooks/useError.ts +21 -21
  139. package/dist/v3/{JsonPretty → components/JsonPretty}/index.vue +16 -13
  140. package/dist/v3/{JsonPretty → components/JsonPretty}/type.ts +127 -126
  141. package/dist/v3/{JsonPretty → components/JsonPretty}/utils/index.ts +169 -169
  142. package/dist/v3/{MovableContainer → components/MovableContainer}/index.vue +1 -1
  143. package/dist/v3/{Pick → components/Pick}/index.vue +322 -322
  144. package/dist/v3/{Tabs → components/Tabs}/index.vue +30 -4
  145. package/dist/v3/{Tag → components/Tag}/index.vue +113 -113
  146. package/dist/v3/{VirtualList → components/VirtualList}/AutoSize.vue +40 -40
  147. package/dist/v3/{VirtualList → components/VirtualList}/index.vue +416 -412
  148. package/dist/v3/hooks/useBluetooth/index.ts +561 -0
  149. package/dist/v3/hooks/useContainerStyle.ts +153 -153
  150. package/dist/v3/hooks/useNFC/index.ts +107 -107
  151. package/dist/v3/hooks/useNFC/typing.d.ts +396 -396
  152. package/dist/v3/hooks/useNFC/useNFCAndroid.ts +966 -966
  153. package/dist/v3/hooks/useNFC/useNFCMpWeiXin.ts +812 -812
  154. package/dist/v3/hooks/useNFC/utils.ts +754 -754
  155. package/dist/v3/hooks/useRequest/index.ts +586 -573
  156. package/dist/v3/hooks/useRequest/utils.ts +267 -267
  157. package/dist/v3/hooks/useScanCode/index.ts +206 -206
  158. package/dist/v3/hooks/useWebsocket/README.md +79 -0
  159. package/dist/v3/hooks/useWebsocket/index.ts +253 -0
  160. package/dist/v3/styles/theme.css +17 -10
  161. package/dist/v3/styles/theme.ts +12 -12
  162. package/package.json +59 -64
  163. package/dist/plugins/uniParseStock/index.d.ts +0 -10
  164. package/dist/plugins/uniParseStock/index.d.ts.map +0 -1
  165. /package/dist/v3/{DevToolWindow → DevTool/components/DevToolWindow}/index.css +0 -0
  166. /package/dist/v3/{SettingList → DevTool/components/SettingList}/index.css +0 -0
  167. /package/dist/v3/{Empty → components/Empty}/empty.png +0 -0
  168. /package/dist/v3/{VirtualList → components/VirtualList}/readme.md +0 -0
@@ -1,322 +1,322 @@
1
- <template>
2
- <view class="pick-wrapper" :style="customStyle">
3
- <!-- Trigger Area -->
4
- <view
5
- :class="`pick-trigger ${!modelValue ? 'pick-trigger-placeholder' : ''}`"
6
- @click="onOpenPick">
7
- <text class="pick-trigger-text">
8
- {{ label || placeholder || '请选择' }}
9
- </text>
10
- <view class="pick-handle">
11
- <view
12
- v-if="allowClear && modelValue"
13
- class="pick-clear"
14
- @click.stop="onClear">
15
- ×
16
- </view>
17
- <view :class="['pick-arrow', isActive ? 'pick-arrow-active' : '']">
18
- >
19
- </view>
20
- </view>
21
- </view>
22
-
23
- <!-- Popup Modal -->
24
- <view class="pick-mask" v-if="isActive" @click="onClosePick">
25
- <view class="pick-modal" @click.stop>
26
- <!-- Header -->
27
- <view class="pick-header">
28
- <text class="pick-title">{{ placeholder || '请选择' }}</text>
29
- <view class="pick-close" @click="onClosePick">×</view>
30
- </view>
31
-
32
- <!-- Search -->
33
- <view class="pick-search" v-if="!readonly">
34
- <input
35
- class="pick-search-input"
36
- :value="searchText"
37
- placeholder="搜索..."
38
- @input="debounceInput"
39
- :focus="isActive" />
40
- </view>
41
-
42
- <!-- List -->
43
- <scroll-view scroll-y class="pick-list">
44
- <view
45
- v-for="item in filteredOptions"
46
- :key="item.value"
47
- :class="[
48
- 'pick-item',
49
- item.value === modelValue ? 'pick-item-active' : '',
50
- ]"
51
- @click="onSelect(item)">
52
- <text class="pick-item-text">{{ item.label }}</text>
53
- <text v-if="item.value === modelValue" class="pick-item-check">
54
-
55
- </text>
56
- </view>
57
- <view v-if="filteredOptions.length === 0" class="pick-empty">
58
- 暂无数据
59
- </view>
60
- </scroll-view>
61
- </view>
62
- </view>
63
- </view>
64
- </template>
65
-
66
- <script lang="ts" setup>
67
- import { debounce } from '../../utils';
68
- import { ref, computed } from 'vue';
69
-
70
- const props = defineProps<{
71
- placeholder?: string;
72
- readonly?: boolean;
73
- allowClear?: boolean;
74
- options?: { label: string; value: any }[];
75
- customStyle?: Record<string, any> | string;
76
- }>();
77
-
78
- const modelValue = defineModel<string>('modelValue');
79
-
80
- const emit = defineEmits<{
81
- (e: 'search', value: string): void;
82
- (e: 'openSearch', value: boolean): void;
83
- (e: 'change', value: { label: string; value: any }): void;
84
- }>();
85
-
86
- const isActive = ref(false);
87
- const searchText = ref('');
88
-
89
- // Computed label for the trigger
90
- const label = computed(() => {
91
- return (
92
- props.options?.find((item) => item.value === modelValue.value)?.label ??
93
- modelValue.value
94
- );
95
- });
96
-
97
- const filteredOptions = computed(() => {
98
- if (!searchText.value) return props.options || [];
99
- const lowerSearch = searchText.value.toLowerCase();
100
- return (props.options || []).filter(
101
- (item) => item.label && item.label.toLowerCase().includes(lowerSearch),
102
- );
103
- });
104
-
105
- function onOpenPick() {
106
- isActive.value = true;
107
- searchText.value = '';
108
- emit('openSearch', true);
109
- }
110
-
111
- function onClosePick() {
112
- isActive.value = false;
113
- emit('openSearch', false);
114
- }
115
-
116
- function onInput(e: any) {
117
- const value = e.detail?.value ?? e.target?.value;
118
- searchText.value = value;
119
- emit('search', value);
120
- }
121
-
122
- const debounceInput = debounce(onInput, 300);
123
-
124
- function onSelect(item: { label: string; value: any }) {
125
- modelValue.value = item.value;
126
- emit('change', item);
127
- onClosePick();
128
- }
129
-
130
- function onClear() {
131
- modelValue.value = '';
132
- emit('search', '');
133
- emit('change', { label: '', value: '' });
134
- }
135
- </script>
136
-
137
- <style scoped>
138
- .pick-wrapper {
139
- position: relative;
140
- width: 100%;
141
- }
142
-
143
- .pick-trigger {
144
- display: flex;
145
- align-items: center;
146
- justify-content: space-between;
147
- width: 100%;
148
- min-width: 0;
149
- height: 24px; /* Slightly taller for easier click */
150
- padding: 0 10px;
151
- border-radius: 4px;
152
- border: 1px solid var(--dev-tool-border-color);
153
- background-color: var(--dev-tool-bg-color);
154
- transition: all 0.3s;
155
- box-sizing: border-box;
156
- cursor: pointer;
157
- }
158
-
159
- .pick-trigger:hover {
160
- border-color: var(--dev-tool-active-color, #409eff);
161
- }
162
-
163
- .pick-trigger-placeholder .pick-trigger-text {
164
- color: var(--dev-tool-text-color-placeholder, #999);
165
- }
166
-
167
- .pick-trigger-text {
168
- flex: 1;
169
- overflow: hidden;
170
- text-overflow: ellipsis;
171
- white-space: nowrap;
172
- color: var(--dev-tool-text-color);
173
- }
174
-
175
- .pick-handle {
176
- display: flex;
177
- align-items: center;
178
- }
179
-
180
- .pick-arrow {
181
- padding-left: 4px;
182
- color: #999;
183
- font-family: monospace;
184
- font-weight: bold;
185
- transform: rotate(90deg);
186
- transition: transform 0.3s;
187
- position: relative;
188
- top: -1px;
189
- }
190
-
191
- .pick-arrow-active {
192
- transform: rotate(-90deg);
193
- }
194
-
195
- .pick-clear {
196
- padding-left: 8px;
197
- font-size: 16px;
198
- color: #999;
199
- }
200
-
201
- .pick-mask {
202
- position: fixed;
203
- inset: 0;
204
- background-color: rgb(0 0 0 / 40%);
205
- z-index: 10000;
206
- display: flex;
207
- align-items: center;
208
- justify-content: center;
209
- backdrop-filter: blur(2px);
210
- }
211
-
212
- .pick-modal {
213
- width: 80%;
214
- max-width: 400px;
215
- height: 60vh;
216
- max-height: 500px;
217
- background-color: var(--dev-tool-bg-color);
218
- border-radius: 12px;
219
- box-shadow: 0 8px 24px rgb(0 0 0 / 15%);
220
- display: flex;
221
- flex-direction: column;
222
- overflow: hidden;
223
- animation: pick-pop-in 0.2s ease-out;
224
- }
225
-
226
- @keyframes pick-pop-in {
227
- from {
228
- opacity: 0;
229
- transform: scale(0.95);
230
- }
231
-
232
- to {
233
- opacity: 1;
234
- transform: scale(1);
235
- }
236
- }
237
-
238
- .pick-header {
239
- display: flex;
240
- align-items: center;
241
- justify-content: space-between;
242
- padding: 12px 16px;
243
- border-bottom: 1px solid var(--dev-tool-border-color);
244
- }
245
-
246
- .pick-title {
247
- font-weight: 600;
248
- color: var(--dev-tool-text-color);
249
- }
250
-
251
- .pick-close {
252
- font-size: 20px;
253
- color: #999;
254
- padding: 4px;
255
- cursor: pointer;
256
- }
257
-
258
- .pick-search {
259
- padding: 10px 16px;
260
- border-bottom: 1px solid var(--dev-tool-border-color);
261
- }
262
-
263
- .pick-search-input {
264
- width: 100%;
265
- height: 36px;
266
- padding: 0 12px;
267
- border-radius: 6px;
268
- background-color: var(--dev-tool-bg2-color, #f5f5f5);
269
- border: 1px solid transparent;
270
- box-sizing: border-box;
271
- color: var(--dev-tool-text-color);
272
- }
273
-
274
- .pick-search-input:focus {
275
- border-color: var(--dev-tool-active-color, #409eff);
276
- background-color: var(--dev-tool-bg-color);
277
- }
278
-
279
- .pick-list {
280
- flex: 1;
281
- overflow-y: auto;
282
- padding: 8px 0;
283
- }
284
-
285
- .pick-item {
286
- display: flex;
287
- align-items: center;
288
- justify-content: space-between;
289
- padding: 12px 16px;
290
- cursor: pointer;
291
- transition: background-color 0.2s;
292
- }
293
-
294
- .pick-item:hover,
295
- .pick-item:active {
296
- background-color: var(--dev-tool-hover-bg-color, rgb(0 0 0 / 5%));
297
- }
298
-
299
- .pick-item-active {
300
- background-color: var(--dev-tool-active-bg-color, rgb(64 158 255 / 10%));
301
- }
302
-
303
- .pick-item-active .pick-item-text {
304
- color: var(--dev-tool-active-color, #409eff);
305
- font-weight: 500;
306
- }
307
-
308
- .pick-item-text {
309
- color: var(--dev-tool-text-color);
310
- }
311
-
312
- .pick-item-check {
313
- color: var(--dev-tool-active-color, #409eff);
314
- font-weight: bold;
315
- }
316
-
317
- .pick-empty {
318
- padding: 24px;
319
- text-align: center;
320
- color: #999;
321
- }
322
- </style>
1
+ <template>
2
+ <view class="pick-wrapper" :style="customStyle">
3
+ <!-- Trigger Area -->
4
+ <view
5
+ :class="`pick-trigger ${!modelValue ? 'pick-trigger-placeholder' : ''}`"
6
+ @click="onOpenPick">
7
+ <text class="pick-trigger-text">
8
+ {{ label || placeholder || '请选择' }}
9
+ </text>
10
+ <view class="pick-handle">
11
+ <view
12
+ v-if="allowClear && modelValue"
13
+ class="pick-clear"
14
+ @click.stop="onClear">
15
+ ×
16
+ </view>
17
+ <view :class="['pick-arrow', isActive ? 'pick-arrow-active' : '']">
18
+ >
19
+ </view>
20
+ </view>
21
+ </view>
22
+
23
+ <!-- Popup Modal -->
24
+ <view class="pick-mask" v-if="isActive" @click="onClosePick">
25
+ <view class="pick-modal" @click.stop>
26
+ <!-- Header -->
27
+ <view class="pick-header">
28
+ <text class="pick-title">{{ placeholder || '请选择' }}</text>
29
+ <view class="pick-close" @click="onClosePick">×</view>
30
+ </view>
31
+
32
+ <!-- Search -->
33
+ <view class="pick-search" v-if="!readonly">
34
+ <input
35
+ class="pick-search-input"
36
+ :value="searchText"
37
+ placeholder="搜索..."
38
+ @input="debounceInput"
39
+ :focus="isActive" />
40
+ </view>
41
+
42
+ <!-- List -->
43
+ <scroll-view scroll-y class="pick-list">
44
+ <view
45
+ v-for="item in filteredOptions"
46
+ :key="item.value"
47
+ :class="[
48
+ 'pick-item',
49
+ item.value === modelValue ? 'pick-item-active' : '',
50
+ ]"
51
+ @click="onSelect(item)">
52
+ <text class="pick-item-text">{{ item.label }}</text>
53
+ <text v-if="item.value === modelValue" class="pick-item-check">
54
+
55
+ </text>
56
+ </view>
57
+ <view v-if="filteredOptions.length === 0" class="pick-empty">
58
+ 暂无数据
59
+ </view>
60
+ </scroll-view>
61
+ </view>
62
+ </view>
63
+ </view>
64
+ </template>
65
+
66
+ <script lang="ts" setup>
67
+ import { debounce } from '../../../utils';
68
+ import { ref, computed } from 'vue';
69
+
70
+ const props = defineProps<{
71
+ placeholder?: string;
72
+ readonly?: boolean;
73
+ allowClear?: boolean;
74
+ options?: { label: string; value: any }[];
75
+ customStyle?: Record<string, any> | string;
76
+ }>();
77
+
78
+ const modelValue = defineModel<string>('modelValue');
79
+
80
+ const emit = defineEmits<{
81
+ (e: 'search', value: string): void;
82
+ (e: 'openSearch', value: boolean): void;
83
+ (e: 'change', value: { label: string; value: any }): void;
84
+ }>();
85
+
86
+ const isActive = ref(false);
87
+ const searchText = ref('');
88
+
89
+ // Computed label for the trigger
90
+ const label = computed(() => {
91
+ return (
92
+ props.options?.find((item) => item.value === modelValue.value)?.label ??
93
+ modelValue.value
94
+ );
95
+ });
96
+
97
+ const filteredOptions = computed(() => {
98
+ if (!searchText.value) return props.options || [];
99
+ const lowerSearch = searchText.value.toLowerCase();
100
+ return (props.options || []).filter(
101
+ (item) => item.label && item.label.toLowerCase().includes(lowerSearch),
102
+ );
103
+ });
104
+
105
+ function onOpenPick() {
106
+ isActive.value = true;
107
+ searchText.value = '';
108
+ emit('openSearch', true);
109
+ }
110
+
111
+ function onClosePick() {
112
+ isActive.value = false;
113
+ emit('openSearch', false);
114
+ }
115
+
116
+ function onInput(e: any) {
117
+ const value = e.detail?.value ?? e.target?.value;
118
+ searchText.value = value;
119
+ emit('search', value);
120
+ }
121
+
122
+ const debounceInput = debounce(onInput, 300);
123
+
124
+ function onSelect(item: { label: string; value: any }) {
125
+ modelValue.value = item.value;
126
+ emit('change', item);
127
+ onClosePick();
128
+ }
129
+
130
+ function onClear() {
131
+ modelValue.value = '';
132
+ emit('search', '');
133
+ emit('change', { label: '', value: '' });
134
+ }
135
+ </script>
136
+
137
+ <style scoped>
138
+ .pick-wrapper {
139
+ position: relative;
140
+ width: 100%;
141
+ }
142
+
143
+ .pick-trigger {
144
+ display: flex;
145
+ align-items: center;
146
+ justify-content: space-between;
147
+ width: 100%;
148
+ min-width: 0;
149
+ height: 24px; /* Slightly taller for easier click */
150
+ padding: 0 10px;
151
+ border-radius: 4px;
152
+ border: 1px solid var(--dev-tool-border-color);
153
+ background-color: var(--dev-tool-bg-color);
154
+ transition: all 0.3s;
155
+ box-sizing: border-box;
156
+ cursor: pointer;
157
+ }
158
+
159
+ .pick-trigger:hover {
160
+ border-color: var(--dev-tool-active-color, #409eff);
161
+ }
162
+
163
+ .pick-trigger-placeholder .pick-trigger-text {
164
+ color: var(--dev-tool-text-color-placeholder, #999);
165
+ }
166
+
167
+ .pick-trigger-text {
168
+ flex: 1;
169
+ overflow: hidden;
170
+ text-overflow: ellipsis;
171
+ white-space: nowrap;
172
+ color: var(--dev-tool-text-color);
173
+ }
174
+
175
+ .pick-handle {
176
+ display: flex;
177
+ align-items: center;
178
+ }
179
+
180
+ .pick-arrow {
181
+ padding-left: 4px;
182
+ color: #999;
183
+ font-family: monospace;
184
+ font-weight: bold;
185
+ transform: rotate(90deg);
186
+ transition: transform 0.3s;
187
+ position: relative;
188
+ top: -1px;
189
+ }
190
+
191
+ .pick-arrow-active {
192
+ transform: rotate(-90deg);
193
+ }
194
+
195
+ .pick-clear {
196
+ padding-left: 8px;
197
+ font-size: 16px;
198
+ color: #999;
199
+ }
200
+
201
+ .pick-mask {
202
+ position: fixed;
203
+ inset: 0;
204
+ background-color: rgb(0 0 0 / 40%);
205
+ z-index: 10000;
206
+ display: flex;
207
+ align-items: center;
208
+ justify-content: center;
209
+ backdrop-filter: blur(2px);
210
+ }
211
+
212
+ .pick-modal {
213
+ width: 80%;
214
+ max-width: 400px;
215
+ height: 60vh;
216
+ max-height: 500px;
217
+ background-color: var(--dev-tool-bg-color);
218
+ border-radius: 12px;
219
+ box-shadow: 0 8px 24px rgb(0 0 0 / 15%);
220
+ display: flex;
221
+ flex-direction: column;
222
+ overflow: hidden;
223
+ animation: pick-pop-in 0.2s ease-out;
224
+ }
225
+
226
+ @keyframes pick-pop-in {
227
+ from {
228
+ opacity: 0;
229
+ transform: scale(0.95);
230
+ }
231
+
232
+ to {
233
+ opacity: 1;
234
+ transform: scale(1);
235
+ }
236
+ }
237
+
238
+ .pick-header {
239
+ display: flex;
240
+ align-items: center;
241
+ justify-content: space-between;
242
+ padding: 12px 16px;
243
+ border-bottom: 1px solid var(--dev-tool-border-color);
244
+ }
245
+
246
+ .pick-title {
247
+ font-weight: 600;
248
+ color: var(--dev-tool-text-color);
249
+ }
250
+
251
+ .pick-close {
252
+ font-size: 20px;
253
+ color: #999;
254
+ padding: 4px;
255
+ cursor: pointer;
256
+ }
257
+
258
+ .pick-search {
259
+ padding: 10px 16px;
260
+ border-bottom: 1px solid var(--dev-tool-border-color);
261
+ }
262
+
263
+ .pick-search-input {
264
+ width: 100%;
265
+ height: 36px;
266
+ padding: 0 12px;
267
+ border-radius: 6px;
268
+ background-color: var(--dev-tool-bg2-color, #f5f5f5);
269
+ border: 1px solid transparent;
270
+ box-sizing: border-box;
271
+ color: var(--dev-tool-text-color);
272
+ }
273
+
274
+ .pick-search-input:focus {
275
+ border-color: var(--dev-tool-active-color, #409eff);
276
+ background-color: var(--dev-tool-bg-color);
277
+ }
278
+
279
+ .pick-list {
280
+ flex: 1;
281
+ overflow-y: auto;
282
+ padding: 8px 0;
283
+ }
284
+
285
+ .pick-item {
286
+ display: flex;
287
+ align-items: center;
288
+ justify-content: space-between;
289
+ padding: 12px 16px;
290
+ cursor: pointer;
291
+ transition: background-color 0.2s;
292
+ }
293
+
294
+ .pick-item:hover,
295
+ .pick-item:active {
296
+ background-color: var(--dev-tool-hover-bg-color, rgb(0 0 0 / 5%));
297
+ }
298
+
299
+ .pick-item-active {
300
+ background-color: var(--dev-tool-active-bg-color, rgb(64 158 255 / 10%));
301
+ }
302
+
303
+ .pick-item-active .pick-item-text {
304
+ color: var(--dev-tool-active-color, #409eff);
305
+ font-weight: 500;
306
+ }
307
+
308
+ .pick-item-text {
309
+ color: var(--dev-tool-text-color);
310
+ }
311
+
312
+ .pick-item-check {
313
+ color: var(--dev-tool-active-color, #409eff);
314
+ font-weight: bold;
315
+ }
316
+
317
+ .pick-empty {
318
+ padding: 24px;
319
+ text-align: center;
320
+ color: #999;
321
+ }
322
+ </style>