@opentiny/tiny-robot 0.1.0 → 0.2.0-alpha.1

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 (150) hide show
  1. package/dist/action-group/ActionGroup.vue.d.ts +26 -0
  2. package/dist/action-group/ActionGroupItem.vue.d.ts +18 -0
  3. package/dist/action-group/index.d.ts +12 -0
  4. package/dist/action-group/index.type.d.ts +16 -0
  5. package/dist/bubble/index.type.d.ts +1 -1
  6. package/dist/container/index.d.ts +7 -0
  7. package/dist/container/index.type.d.ts +16 -0
  8. package/dist/container/index.vue.d.ts +26 -0
  9. package/dist/feedback/components/SourceList.vue.d.ts +11 -0
  10. package/dist/feedback/components/index.d.ts +1 -0
  11. package/dist/feedback/index.d.ts +7 -0
  12. package/dist/feedback/index.type.d.ts +25 -0
  13. package/dist/feedback/index.vue.d.ts +13 -0
  14. package/dist/history/components/index.d.ts +2 -0
  15. package/dist/history/components/item-tag.vue.d.ts +5 -0
  16. package/dist/history/components/search-empty.vue.d.ts +7 -0
  17. package/dist/history/composables/index.d.ts +1 -0
  18. package/dist/history/composables/useEditItemTitle.d.ts +12 -0
  19. package/dist/history/index.d.ts +6 -0
  20. package/dist/history/index.type.d.ts +43 -0
  21. package/dist/history/index.vue.d.ts +2 -0
  22. package/dist/icon-button/index.d.ts +7 -0
  23. package/dist/icon-button/index.type.d.ts +7 -0
  24. package/dist/icon-button/index.vue.d.ts +6 -0
  25. package/dist/index.d.ts +12 -2
  26. package/dist/index.js +56 -22
  27. package/dist/node_modules/.pnpm/@opentiny_utils@3.22.0/node_modules/@opentiny/utils/dist/index.es.js +1335 -884
  28. package/dist/node_modules/.pnpm/@opentiny_vue-common@3.22.0/node_modules/@opentiny/vue-common/lib/index.js +660 -144
  29. package/dist/node_modules/.pnpm/@opentiny_vue-hooks@3.22.0/node_modules/@opentiny/vue-hooks/dist/src/vue-popper.js +85 -0
  30. package/dist/node_modules/.pnpm/@opentiny_vue-locale@3.22.0/node_modules/@opentiny/vue-locale/lib/index.js +1783 -0
  31. package/dist/node_modules/.pnpm/@opentiny_vue-renderless@3.22.0/node_modules/@opentiny/vue-renderless/tooltip/index.js +77 -0
  32. package/dist/node_modules/.pnpm/@opentiny_vue-renderless@3.22.0/node_modules/@opentiny/vue-renderless/tooltip/vue.js +90 -0
  33. package/dist/node_modules/.pnpm/@opentiny_vue-tooltip@3.22.0/node_modules/@opentiny/vue-tooltip/lib/index.js +176 -0
  34. package/dist/node_modules/.pnpm/@opentiny_vue-tooltip@3.22.0/node_modules/@opentiny/vue-tooltip/lib/pc.js +248 -0
  35. package/dist/node_modules/.pnpm/@vueuse_core@13.1.0_vue@3.5.13/node_modules/@vueuse/core/index.js +190 -0
  36. package/dist/node_modules/.pnpm/@vueuse_shared@13.1.0_vue@3.5.13/node_modules/@vueuse/shared/index.js +53 -0
  37. package/dist/packages/components/src/action-group/ActionGroup.vue.js +7 -0
  38. package/dist/packages/components/src/action-group/ActionGroup.vue2.js +97 -0
  39. package/dist/packages/components/src/action-group/ActionGroupItem.vue.js +14 -0
  40. package/dist/packages/components/src/action-group/ActionGroupItem.vue2.js +4 -0
  41. package/dist/packages/components/src/action-group/index.js +17 -0
  42. package/dist/packages/components/src/bubble/bubble-list.vue.js +2 -2
  43. package/dist/packages/components/src/bubble/bubble-list.vue2.js +18 -19
  44. package/dist/packages/components/src/bubble/bubble.vue.js +2 -2
  45. package/dist/packages/components/src/bubble/bubble.vue2.js +46 -46
  46. package/dist/packages/components/src/container/index.js +9 -0
  47. package/dist/packages/components/src/container/index.vue.js +7 -0
  48. package/dist/packages/components/src/container/index.vue2.js +55 -0
  49. package/dist/packages/components/src/feedback/components/SourceList.vue.js +7 -0
  50. package/dist/packages/components/src/feedback/components/SourceList.vue2.js +52 -0
  51. package/dist/packages/components/src/feedback/index.js +9 -0
  52. package/dist/packages/components/src/feedback/index.vue.js +7 -0
  53. package/dist/packages/components/src/feedback/index.vue2.js +142 -0
  54. package/dist/packages/components/src/history/components/item-tag.vue.js +7 -0
  55. package/dist/packages/components/src/history/components/item-tag.vue2.js +21 -0
  56. package/dist/packages/components/src/history/components/search-empty.vue.js +7 -0
  57. package/dist/packages/components/src/history/components/search-empty.vue2.js +20 -0
  58. package/dist/packages/components/src/history/composables/useEditItemTitle.js +43 -0
  59. package/dist/packages/components/src/history/index.js +11 -0
  60. package/dist/packages/components/src/history/index.vue.js +7 -0
  61. package/dist/packages/components/src/history/index.vue2.js +130 -0
  62. package/dist/packages/components/src/icon-button/index.js +9 -0
  63. package/dist/packages/components/src/icon-button/index.vue.js +7 -0
  64. package/dist/packages/components/src/icon-button/index.vue2.js +40 -0
  65. package/dist/packages/components/src/prompts/prompt.vue.js +2 -2
  66. package/dist/packages/components/src/prompts/prompt.vue2.js +17 -15
  67. package/dist/packages/components/src/question/components/HotQuestions.vue.js +22 -22
  68. package/dist/packages/components/src/question/index.vue.js +7 -7
  69. package/dist/packages/components/src/sender/components/TemplateEditor.vue.js +7 -0
  70. package/dist/packages/components/src/sender/components/TemplateEditor.vue2.js +121 -0
  71. package/dist/packages/components/src/sender/index.vue.js +149 -128
  72. package/dist/packages/components/src/suggestion/components/CategoryNav.vue.js +38 -0
  73. package/dist/packages/components/src/suggestion/components/CategoryNav.vue2.js +4 -0
  74. package/dist/packages/components/src/suggestion/components/SuggestionCapsule.vue.js +107 -0
  75. package/dist/packages/components/src/suggestion/components/SuggestionCapsule.vue2.js +4 -0
  76. package/dist/packages/components/src/suggestion/components/SuggestionPanel.vue.js +123 -0
  77. package/dist/packages/components/src/suggestion/components/SuggestionPanel.vue2.js +4 -0
  78. package/dist/packages/components/src/suggestion/composables/useKeyboardNavigation.js +45 -0
  79. package/dist/packages/components/src/suggestion/composables/useTriggerDetection.js +17 -0
  80. package/dist/packages/components/src/suggestion/index.js +9 -0
  81. package/dist/packages/components/src/suggestion/index.vue.js +179 -0
  82. package/dist/packages/components/src/suggestion/index.vue2.js +4 -0
  83. package/dist/packages/components/src/suggestion/utils/dom.js +18 -0
  84. package/dist/packages/svgs/dist/tiny-robot-svgs.js +364 -69
  85. package/dist/question/components/HotQuestions.vue.d.ts +2 -2
  86. package/dist/question/index.vue.d.ts +1 -1
  87. package/dist/sender/components/ActionButtons.vue.d.ts +2 -2
  88. package/dist/sender/components/TemplateEditor.vue.d.ts +18 -0
  89. package/dist/sender/index.type.d.ts +47 -0
  90. package/dist/sender/index.vue.d.ts +70 -5
  91. package/dist/style.css +1 -1
  92. package/dist/suggestion/components/CategoryNav.vue.d.ts +45 -0
  93. package/dist/suggestion/components/SuggestionCapsule.vue.d.ts +32 -0
  94. package/dist/suggestion/components/SuggestionPanel.vue.d.ts +84 -0
  95. package/dist/suggestion/composables/useKeyboardNavigation.d.ts +18 -0
  96. package/dist/suggestion/composables/useSuggestionFilter.d.ts +10 -0
  97. package/dist/suggestion/composables/useTriggerDetection.d.ts +11 -0
  98. package/dist/suggestion/index.d.ts +7 -0
  99. package/dist/suggestion/index.type.d.ts +94 -0
  100. package/dist/suggestion/index.vue.d.ts +343 -0
  101. package/dist/suggestion/utils/dom.d.ts +20 -0
  102. package/package.json +5 -5
  103. package/src/action-group/ActionGroup.vue +232 -0
  104. package/src/action-group/ActionGroupItem.vue +9 -0
  105. package/src/action-group/index.ts +25 -0
  106. package/src/action-group/index.type.ts +20 -0
  107. package/src/bubble/bubble-list.vue +1 -3
  108. package/src/bubble/bubble.vue +4 -14
  109. package/src/bubble/index.type.ts +1 -1
  110. package/src/container/index.ts +12 -0
  111. package/src/container/index.type.ts +17 -0
  112. package/src/container/index.vue +134 -0
  113. package/src/feedback/components/SourceList.vue +112 -0
  114. package/src/feedback/components/index.ts +1 -0
  115. package/src/feedback/index.ts +12 -0
  116. package/src/feedback/index.type.ts +27 -0
  117. package/src/feedback/index.vue +166 -0
  118. package/src/history/components/index.ts +2 -0
  119. package/src/history/components/item-tag.vue +49 -0
  120. package/src/history/components/search-empty.vue +38 -0
  121. package/src/history/composables/index.ts +1 -0
  122. package/src/history/composables/useEditItemTitle.ts +75 -0
  123. package/src/history/index.ts +12 -0
  124. package/src/history/index.type.ts +50 -0
  125. package/src/history/index.vue +292 -0
  126. package/src/icon-button/index.ts +12 -0
  127. package/src/icon-button/index.type.ts +8 -0
  128. package/src/icon-button/index.vue +52 -0
  129. package/src/index.ts +37 -2
  130. package/src/prompts/prompt.vue +7 -21
  131. package/src/question/components/HotQuestions.vue +1 -1
  132. package/src/question/index.less +9 -10
  133. package/src/sender/components/TemplateEditor.vue +274 -0
  134. package/src/sender/index.less +17 -7
  135. package/src/sender/index.type.ts +51 -0
  136. package/src/sender/index.vue +56 -8
  137. package/src/sender/vars.less +3 -3
  138. package/src/suggestion/components/CategoryNav.vue +38 -0
  139. package/src/suggestion/components/SuggestionCapsule.vue +183 -0
  140. package/src/suggestion/components/SuggestionPanel.vue +147 -0
  141. package/src/suggestion/composables/useKeyboardNavigation.ts +101 -0
  142. package/src/suggestion/composables/useSuggestionFilter.ts +34 -0
  143. package/src/suggestion/composables/useTriggerDetection.ts +46 -0
  144. package/src/suggestion/index.less +497 -0
  145. package/src/suggestion/index.ts +12 -0
  146. package/src/suggestion/index.type.ts +101 -0
  147. package/src/suggestion/index.vue +338 -0
  148. package/src/suggestion/utils/dom.ts +66 -0
  149. package/src/suggestion/vars.less +141 -0
  150. package/.vscode/extensions.json +0 -3
@@ -0,0 +1,338 @@
1
+ <script setup lang="ts">
2
+ import { ref, computed, watch, onMounted, onBeforeUnmount } from 'vue'
3
+ import SuggestionCapsule from './components/SuggestionCapsule.vue'
4
+ import SuggestionPanel from './components/SuggestionPanel.vue'
5
+ import { useTriggerDetection } from './composables/useTriggerDetection'
6
+ import type {
7
+ SuggestionItem,
8
+ SuggestionProps,
9
+ SuggestionEmits,
10
+ TriggerHandler,
11
+ TriggerInfo,
12
+ TriggerContext,
13
+ Category,
14
+ } from './index.type'
15
+ import { IconHotQuestion, IconArrowUp, IconArrowDown } from '@opentiny/tiny-robot-svgs'
16
+
17
+ import './index.less'
18
+
19
+ const props = withDefaults(defineProps<SuggestionProps>(), {
20
+ open: undefined,
21
+ theme: 'light',
22
+ loading: false,
23
+ title: '快捷指令',
24
+ items: () => [],
25
+ categories: () => [],
26
+ triggerKeys: () => ['/'],
27
+ maxVisibleItems: 5,
28
+ defaultExpanded: false,
29
+ closeOnOutsideClick: true,
30
+ })
31
+
32
+ const emit = defineEmits<SuggestionEmits>()
33
+
34
+ // 状态管理
35
+ const internalOpen = ref(false)
36
+ const currentItems = ref<SuggestionItem[]>([])
37
+ const triggerInfo = ref<TriggerContext>({
38
+ text: '',
39
+ position: 0,
40
+ })
41
+
42
+ // 是否展开完整指令列表
43
+ const isExpanded = ref(props.defaultExpanded)
44
+
45
+ // 是否显示展开按钮
46
+ const showExpandButton = ref(false)
47
+
48
+ // 切换指令列表的展开状态
49
+ const toggleExpand = () => {
50
+ isExpanded.value = !isExpanded.value
51
+ emit('update:expanded', isExpanded.value)
52
+ }
53
+
54
+ // 处理显示展开按钮
55
+ const handleShowExpandButton = (value: boolean) => {
56
+ showExpandButton.value = value
57
+ }
58
+
59
+ // 当前激活的分类
60
+ const activeCategory = ref<string>('')
61
+
62
+ // 当前选中的项目索引
63
+ const activeItemIndex = ref(-1)
64
+
65
+ // 元素引用
66
+ const rootRef = ref<HTMLElement | null>(null)
67
+ const panelRef = ref<InstanceType<typeof SuggestionPanel> | null>(null)
68
+
69
+ // 计算实际打开状态
70
+ const panelOpen = computed(() => (props.open !== undefined ? props.open : internalOpen.value))
71
+
72
+ // 计算当前激活分类的项目列表
73
+ const activeItems = computed(() => {
74
+ // 如果没有分类或没有选中分类,直接显示 items
75
+ if (props.categories.length === 0 || !activeCategory.value) {
76
+ return currentItems.value
77
+ }
78
+
79
+ // 查找当前激活的分类
80
+ const category = props.categories.find((cat) => cat.id === activeCategory.value)
81
+ return category ? category.items : []
82
+ })
83
+
84
+ // 监听打开状态变化,重置选中项
85
+ watch(panelOpen, (isOpen) => {
86
+ if (isOpen) {
87
+ // 初始化选中项
88
+ activeItemIndex.value = activeItems.value.length > 0 ? 0 : -1
89
+ } else {
90
+ // 重置选中项
91
+ activeItemIndex.value = -1
92
+ }
93
+ })
94
+
95
+ // 监听项目列表变化,更新选中项
96
+ watch(activeItems, (items) => {
97
+ if (items.length > 0 && activeItemIndex.value === -1) {
98
+ activeItemIndex.value = 0
99
+ } else if (items.length === 0) {
100
+ activeItemIndex.value = -1
101
+ } else if (activeItemIndex.value >= items.length) {
102
+ activeItemIndex.value = items.length - 1
103
+ }
104
+ })
105
+
106
+ // 初始化激活的分类
107
+ watch(
108
+ () => props.categories,
109
+ (categories) => {
110
+ if (categories.length > 0 && !activeCategory.value) {
111
+ activeCategory.value = categories[0].id
112
+ }
113
+ },
114
+ { immediate: true },
115
+ )
116
+
117
+ // 处理 items 数据
118
+ const processItems = () => {
119
+ currentItems.value = [...props.items]
120
+ }
121
+
122
+ // 初始化hooks
123
+ const { detectTrigger } = useTriggerDetection(props)
124
+
125
+ // 处理胶囊式指令点击
126
+ const handleSuggestionClick = (item: SuggestionItem) => {
127
+ // 发出事件,便于父组件处理回填
128
+ emit('suggestion-select', item)
129
+
130
+ // 如果存在触发信息,可以利用它进行回填
131
+ // 否则直接将值传递给父组件
132
+ emit('select', item.value, {
133
+ text: '',
134
+ position: 0,
135
+ })
136
+
137
+ // 如果指令包含模板,在选择后填充模板
138
+ if (item.template) {
139
+ emit('fill-template', item.template)
140
+ }
141
+ }
142
+
143
+ // 触发事件处理
144
+ const handleTrigger: TriggerHandler = (info: TriggerInfo) => {
145
+ if (info === false) {
146
+ closePanel()
147
+ } else {
148
+ // 保存触发信息,用于回填
149
+ if (typeof info === 'object' && info !== null) {
150
+ triggerInfo.value = {
151
+ text: info.text || '',
152
+ position: info.position || 0,
153
+ }
154
+ }
155
+ processItems()
156
+ internalOpen.value = true
157
+ emit('update:open', true)
158
+ }
159
+ }
160
+
161
+ // 核心功能:处理输入事件,用于检测触发字符
162
+ const handleInputEvent = (event: Event, text: string) => {
163
+ // 检测触发条件
164
+ const newTriggerInfo = detectTrigger(event, text)
165
+
166
+ if (newTriggerInfo) {
167
+ // 设置触发信息
168
+ triggerInfo.value = newTriggerInfo
169
+
170
+ // 触发指令面板
171
+ handleTrigger(newTriggerInfo)
172
+ return true
173
+ }
174
+
175
+ // 如果指令面板已打开,关闭面板
176
+ if (panelOpen.value && text === '') {
177
+ handleTrigger(false)
178
+ return true
179
+ }
180
+
181
+ return false
182
+ }
183
+
184
+ // 键盘事件处理,委托给面板组件
185
+ const handleKeyDown = (e: KeyboardEvent) => {
186
+ if (panelOpen.value && panelRef.value) {
187
+ panelRef.value.handleKeyDown(e)
188
+ return
189
+ }
190
+ }
191
+
192
+ // 关闭面板
193
+ const closePanel = () => {
194
+ if (props.open === undefined) {
195
+ internalOpen.value = false
196
+ }
197
+ emit('update:open', false)
198
+ emit('close')
199
+ }
200
+
201
+ // 处理分类选择
202
+ const handleCategorySelect = (category: Category) => {
203
+ activeCategory.value = category.id
204
+ // 重置选中项索引
205
+ activeItemIndex.value = 0
206
+
207
+ emit('category-select', category)
208
+ }
209
+
210
+ // 处理指令选择
211
+ const handleSelect = (value: SuggestionItem, context: TriggerContext) => {
212
+ emit('select', value.text, context)
213
+
214
+ // 如果指令包含模板,在选择后填充模板
215
+ if (value.template) {
216
+ emit('fill-template', value.template)
217
+ }
218
+
219
+ closePanel()
220
+ }
221
+
222
+ // 点击外部关闭
223
+ const handleClickOutside = (event: MouseEvent) => {
224
+ if (props.closeOnOutsideClick && panelOpen.value && rootRef.value && !rootRef.value.contains(event.target as Node)) {
225
+ closePanel()
226
+ }
227
+ }
228
+
229
+ // 按钮切换面板是否可见
230
+ const handleOpenPanel = () => {
231
+ if (panelOpen.value) {
232
+ closePanel()
233
+ } else {
234
+ processItems()
235
+ internalOpen.value = true
236
+ emit('update:open', true)
237
+ }
238
+ }
239
+
240
+ // 监听点击外部事件
241
+ onMounted(() => {
242
+ if (props.closeOnOutsideClick) {
243
+ document.addEventListener('click', handleClickOutside)
244
+ }
245
+ })
246
+
247
+ onBeforeUnmount(() => {
248
+ if (props.closeOnOutsideClick) {
249
+ document.removeEventListener('click', handleClickOutside)
250
+ }
251
+ })
252
+
253
+ // 暴露给父组件的方法
254
+ defineExpose({
255
+ trigger: handleTrigger,
256
+ keyDown: handleKeyDown,
257
+ input: handleInputEvent,
258
+ toggleExpand,
259
+ })
260
+ </script>
261
+
262
+ <template>
263
+ <div ref="rootRef" :class="['tr-suggestion', className, { 'tr-suggestion--dark': theme === 'dark' }]">
264
+ <div class="tr-suggestion__header">
265
+ <div class="tr-suggestion__trigger" @click="handleOpenPanel">
266
+ <IconHotQuestion />
267
+ </div>
268
+
269
+ <!-- 胶囊式指令 -->
270
+ <SuggestionCapsule
271
+ :suggestions="items"
272
+ :isExpanded="isExpanded"
273
+ @suggestion-click="handleSuggestionClick"
274
+ @show-expand-button="handleShowExpandButton"
275
+ >
276
+ <template #suggestion-icon="slotProps">
277
+ <slot name="capsule-icon" :suggestion="slotProps.suggestion">
278
+ <IconEdit />
279
+ </slot>
280
+ </template>
281
+ </SuggestionCapsule>
282
+
283
+ <!-- 常规指令完整内容触发按钮 -->
284
+ <div v-if="showExpandButton" class="tr-suggestion__expand-button" @click="toggleExpand">
285
+ <IconArrowUp v-if="!isExpanded" />
286
+ <IconArrowDown v-else />
287
+ </div>
288
+ </div>
289
+
290
+ <!-- 自定义输入区域 -->
291
+ <slot name="trigger" :onTrigger="handleTrigger" :onKeyDown="handleKeyDown" :onInput="handleInputEvent">
292
+ <!-- 默认输入框实现 -->
293
+ </slot>
294
+
295
+ <!-- 指令面板(弹窗显示在输入框上方) -->
296
+ <SuggestionPanel
297
+ v-if="panelOpen"
298
+ ref="panelRef"
299
+ class="tr-suggestion-panel placement-top"
300
+ :items="currentItems"
301
+ :categories="categories"
302
+ :loading="loading"
303
+ :title="title"
304
+ :maxVisibleItems="maxVisibleItems"
305
+ :triggerContext="triggerInfo"
306
+ @close="closePanel"
307
+ @select="handleSelect"
308
+ @category-select="handleCategorySelect"
309
+ >
310
+ <!-- 转发所有插槽到面板组件 -->
311
+ <template #title-icon>
312
+ <slot name="title-icon">
313
+ <IconHotQuestion style="font-size: 36px" />
314
+ </slot>
315
+ </template>
316
+
317
+ <template #category-label="slotProps">
318
+ <slot name="category-label" :category="slotProps.category"></slot>
319
+ </template>
320
+
321
+ <template #item="slotProps">
322
+ <slot name="item" :item="slotProps.item" :active="slotProps.active"></slot>
323
+ </template>
324
+
325
+ <template #loading-indicator>
326
+ <slot name="loading-indicator">
327
+ <div class="tr-suggestion__loading-spinner"></div>
328
+ </slot>
329
+ </template>
330
+
331
+ <template #empty>
332
+ <slot name="empty">
333
+ <p>无匹配结果</p>
334
+ </slot>
335
+ </template>
336
+ </SuggestionPanel>
337
+ </div>
338
+ </template>
@@ -0,0 +1,66 @@
1
+ /**
2
+ * 测量元素文本宽度
3
+ * @param text 要测量的文本
4
+ * @param className 应用的样式类名
5
+ * @returns 测量后的宽度
6
+ */
7
+ export function measureTextWidth(text: string, className: string = ''): number {
8
+ // 创建临时元素
9
+ const temp = document.createElement('div')
10
+ if (className) {
11
+ temp.className = className
12
+ }
13
+
14
+ // 设置样式确保准确测量
15
+ temp.style.visibility = 'hidden'
16
+ temp.style.position = 'absolute'
17
+ temp.style.whiteSpace = 'nowrap'
18
+ temp.textContent = text
19
+
20
+ // 添加到DOM并测量
21
+ document.body.appendChild(temp)
22
+ const width = temp.offsetWidth
23
+ document.body.removeChild(temp)
24
+
25
+ return width
26
+ }
27
+
28
+ /**
29
+ * 确保元素在容器中可见
30
+ * @param container 容器元素
31
+ * @param element 需要显示的元素
32
+ */
33
+ export function ensureElementVisible(container: HTMLElement, element: HTMLElement): void {
34
+ const containerRect = container.getBoundingClientRect()
35
+ const elementRect = element.getBoundingClientRect()
36
+
37
+ if (elementRect.bottom > containerRect.bottom) {
38
+ // 元素底部超出容器
39
+ container.scrollTop += elementRect.bottom - containerRect.bottom
40
+ } else if (elementRect.top < containerRect.top) {
41
+ // 元素顶部超出容器
42
+ container.scrollTop -= containerRect.top - elementRect.top
43
+ }
44
+ }
45
+
46
+ // 文本宽度缓存
47
+ const widthCache = new Map<string, number>()
48
+
49
+ /**
50
+ * 带缓存的文本宽度测量
51
+ * @param text 要测量的文本
52
+ * @param className 样式类名
53
+ * @returns 测量后的宽度
54
+ */
55
+ export function getCachedTextWidth(text: string, className: string = ''): number {
56
+ const key = `${text}::${className}`
57
+
58
+ if (widthCache.has(key)) {
59
+ return widthCache.get(key)!
60
+ }
61
+
62
+ const width = measureTextWidth(text, className)
63
+ widthCache.set(key, width)
64
+
65
+ return width
66
+ }
@@ -0,0 +1,141 @@
1
+ /* ----------------- 颜色变量 ----------------- */
2
+ :root {
3
+ /* 主题基础颜色 */
4
+ --tr-suggestion-primary-color: #1890ff;
5
+ --tr-suggestion-background-color: #ffffff;
6
+ --tr-suggestion-modal-background-color: #ffffff;
7
+ --tr-suggestion-text-color: #333333;
8
+ --tr-suggestion-text-color-secondary: #666666;
9
+ --tr-suggestion-border-color: #e8e8e8;
10
+ --tr-suggestion-hover-color: #f5f5f5;
11
+ --tr-suggestion-tab-hover-bg: #f0f0f0;
12
+ --tr-suggestion-active-tab-color: var(--tr-suggestion-primary-color);
13
+ --tr-suggestion-active-tab-bg: #e6f7ff;
14
+
15
+ /* 弹窗相关颜色 */
16
+ --tr-suggestion-header-bg: #f9f9f9;
17
+ --tr-suggestion-title-color: #1d2129;
18
+ --tr-suggestion-close-icon-color: #86909c;
19
+ --tr-suggestion-tab-active-bg: #e8f3ff;
20
+ --tr-suggestion-tab-active-text: #1890ff;
21
+ --tr-suggestion-tab-text: #4e5969;
22
+ --tr-suggestion-tab-border: #f0f0f0;
23
+ --tr-suggestion-list-divider-color: #f0f0f0;
24
+ --tr-suggestion-modal-backdrop-color: rgba(0, 0, 0, 0.5);
25
+
26
+ /* 常见内容颜色 */
27
+ --tr-suggestion-common-bg: #fff;
28
+ --tr-suggestion-common-text: #191919;
29
+ --tr-suggestion-common-hover-bg: #ebebeb;
30
+ --tr-suggestion-common-shadow: rgba(0, 0, 0, 0.04);
31
+
32
+ /* 背景颜色 */
33
+ --tr-suggestion-container-bg: #f8f8f8;
34
+ --tr-suggestion-list-item-bg: #fff;
35
+ --tr-suggestion-list-hover-shadow: rgba(0, 0, 0, 0.08);
36
+ --tr-suggestion-category-bg: rgba(0, 0, 0, 0.04);
37
+ --tr-suggestion-category-hover-bg: rgba(0, 0, 0, 0.08);
38
+ --tr-suggestion-category-active-border: #191919;
39
+ --tr-suggestion-item-border-color: rgba(0, 0, 0, 0.04);
40
+
41
+ /* 滚动条颜色 */
42
+ --tr-suggestion-scrollbar-track-bg: rgba(16, 31, 28, 0.1);
43
+ --tr-suggestion-scrollbar-thumb-bg: rgba(144, 147, 153, 0.5);
44
+ --tr-suggestion-scrollbar-thumb-hover-bg: rgba(144, 147, 153, 0.3);
45
+
46
+ /* ----------------- 尺寸变量 ----------------- */
47
+ /* 圆角 */
48
+ --tr-suggestion-border-radius: 24px;
49
+ --tr-suggestion-category-border-radius: 8px;
50
+ --tr-suggestion-list-border-radius: 12px;
51
+ --tr-suggestion-common-border-radius: 16px;
52
+ --tr-suggestion-scrollbar-border-radius: 2em;
53
+
54
+ /* 间距和尺寸 */
55
+ --tr-suggestion-spacing: 16px;
56
+ --tr-suggestion-icon-size: 16px;
57
+ --tr-suggestion-container-height: 46px;
58
+ --tr-suggestion-item-height: 85px;
59
+ --tr-suggestion-trigger-size: 32px;
60
+ --tr-suggestion-common-item-height: 32px;
61
+ --tr-suggestion-category-height: 38px;
62
+ --tr-suggestion-scrollbar-width: 4px;
63
+ --tr-suggestion-modal-padding: 20px;
64
+ --tr-suggestion-modal-max-height: 553px;
65
+ --tr-suggestion-modal-max-width: 640px;
66
+ --tr-suggestion-content-max-height: calc(553px - 120px);
67
+ --tr-suggestion-z-index: 1000;
68
+
69
+ /* ----------------- 文字变量 ----------------- */
70
+ /* 字体 */
71
+ --tr-suggestion-font-size: 14px;
72
+ --tr-suggestion-title-font-size: 18px;
73
+ --tr-suggestion-title-font-weight: 600;
74
+ --tr-suggestion-item-font-weight: 500;
75
+ --tr-suggestion-line-height: 1.5;
76
+ --tr-suggestion-item-line-height: 22px;
77
+ --tr-suggestion-item-extra-font-size: 14px;
78
+ --tr-suggestion-item-extra-color: #191919;
79
+
80
+ /* ----------------- 特效变量 ----------------- */
81
+ /* 阴影 */
82
+ --tr-suggestion-panel-shadow:
83
+ 0 6px 16px 0 rgba(0, 0, 0, 0.08), 0 3px 6px -4px rgba(0, 0, 0, 0.12), 0 9px 28px 8px rgba(0, 0, 0, 0.05);
84
+ --tr-suggestion-trigger-shadow: 0 4px 16px rgba(0, 0, 0, 0.04);
85
+ --tr-suggestion-common-item-shadow: 0 4px 16px rgba(0, 0, 0, 0.04);
86
+ --tr-suggestion-list-item-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
87
+ --tr-suggestion-wrap-trigger-shadow: 2px 0 9px rgba(0, 0, 0, 0.04);
88
+
89
+ /* 动画 */
90
+ --tr-suggestion-transition-duration: 0.3s;
91
+ --tr-suggestion-transition-timing: ease;
92
+ --tr-suggestion-hover-transition: all var(--tr-suggestion-transition-duration) var(--tr-suggestion-transition-timing);
93
+ }
94
+
95
+ /* ----------------- 暗色主题变量 ----------------- */
96
+ [data-theme='dark'],
97
+ .theme-dark {
98
+ /* 主题基础颜色 */
99
+ --tr-suggestion-primary-color: #177ddc;
100
+ --tr-suggestion-background-color: #1f1f1f;
101
+ --tr-suggestion-modal-background-color: #2a2a2a;
102
+ --tr-suggestion-text-color: #f0f0f0;
103
+ --tr-suggestion-text-color-secondary: #aaaaaa;
104
+ --tr-suggestion-border-color: #434343;
105
+ --tr-suggestion-hover-color: #303030;
106
+ --tr-suggestion-tab-hover-bg: #3a3a3a;
107
+ --tr-suggestion-active-tab-color: var(--tr-suggestion-primary-color);
108
+ --tr-suggestion-active-tab-bg: #113a5c;
109
+
110
+ /* 弹窗相关颜色 */
111
+ --tr-suggestion-header-bg: #2a2a2a;
112
+ --tr-suggestion-title-color: #c9d1d9;
113
+ --tr-suggestion-close-icon-color: #8b949e;
114
+ --tr-suggestion-tab-active-bg: #30363d;
115
+ --tr-suggestion-tab-active-text: #58a6ff;
116
+ --tr-suggestion-tab-text: #8b949e;
117
+ --tr-suggestion-tab-border: #30363d;
118
+ --tr-suggestion-list-divider-color: #30363d;
119
+ --tr-suggestion-modal-backdrop-color: rgba(0, 0, 0, 0.7);
120
+
121
+ /* 常见内容颜色 */
122
+ --tr-suggestion-common-bg: #2a2a2a;
123
+ --tr-suggestion-common-text: #e6e6e6;
124
+ --tr-suggestion-common-hover-bg: #3a3a3a;
125
+ --tr-suggestion-common-shadow: rgba(0, 0, 0, 0.2);
126
+
127
+ /* 背景颜色 */
128
+ --tr-suggestion-container-bg: #141414;
129
+ --tr-suggestion-list-item-bg: #2a2a2a;
130
+ --tr-suggestion-list-hover-shadow: rgba(0, 0, 0, 0.3);
131
+ --tr-suggestion-category-bg: rgba(255, 255, 255, 0.04);
132
+ --tr-suggestion-category-hover-bg: rgba(255, 255, 255, 0.08);
133
+ --tr-suggestion-category-active-border: #e6e6e6;
134
+ --tr-suggestion-item-border-color: rgba(255, 255, 255, 0.04);
135
+
136
+ /* 滚动条颜色 */
137
+ --tr-suggestion-scrollbar-track-bg: rgba(255, 255, 255, 0.05);
138
+ --tr-suggestion-scrollbar-thumb-bg: rgba(255, 255, 255, 0.2);
139
+ --tr-suggestion-scrollbar-thumb-hover-bg: rgba(255, 255, 255, 0.3);
140
+ --tr-suggestion-item-extra-color: #aaaaaa;
141
+ }
@@ -1,3 +0,0 @@
1
- {
2
- "recommendations": ["Vue.volar", "Vue.vscode-typescript-vue-plugin"]
3
- }