@opentiny/next-sdk 0.2.2 → 0.2.3

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/package.json CHANGED
@@ -1,13 +1,28 @@
1
1
  {
2
2
  "name": "@opentiny/next-sdk",
3
- "version": "0.2.2",
3
+ "version": "0.2.3",
4
4
  "type": "module",
5
+ "homepage": "https://docs.opentiny.design/next-sdk/guide/",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git@github.com:opentiny/next-sdk.git"
9
+ },
10
+ "bugs": {
11
+ "url": "https://github.com/opentiny/next-sdk/issues"
12
+ },
13
+ "keywords": [
14
+ "next-sdk",
15
+ "opentiny",
16
+ "mcp",
17
+ "sdk",
18
+ "agent"
19
+ ],
5
20
  "license": "MIT",
6
21
  "author": "Chunhui Mo",
7
22
  "main": "dist/index.js",
8
23
  "module": "dist/index.js",
9
24
  "types": "dist/index.d.ts",
10
- "description": "OpenTiny NEXT SDK",
25
+ "description": "A frontend intelligent application development toolkit designed to simplify WebAgent integration and usage, supporting multiple programming languages and frontend frameworks to help developers rapidly implement intelligent features",
11
26
  "dependencies": {
12
27
  "@modelcontextprotocol/sdk": "~1.25.2",
13
28
  "@opentiny/next": "^0.3.2",
@@ -1,13 +1,14 @@
1
1
  import { QrCode } from './QrCode'
2
- import { Tooltip } from './tooltips';
3
- import chat from './svgs/chat.svg?url';
4
- import scan from './svgs/scan.svg?url';
5
- import link from './svgs/link.svg?url';
6
- import qrCode from './svgs/qrcode.svg?url';
7
- import iconCopy from './svgs/icon-copy.svg?url';
2
+ import { Tooltip } from './tooltips'
3
+ import chat from './svgs/chat.svg?url'
4
+ import scan from './svgs/scan.svg?url'
5
+ import link from './svgs/link.svg?url'
6
+ import qrCode from './svgs/qrcode.svg?url'
7
+ import iconCopy from './svgs/icon-copy.svg?url'
8
8
 
9
9
  const DEFAULT_REMOTE_URL = 'https://agent.opentiny.design/tiny-robot'
10
10
  const DEFAULT_QR_CODE_URL = 'https://ai.opentiny.design/next-remoter'
11
+ const DEFAULT_LOGO_URL = 'https://ai.opentiny.design/next-remoter/svgs/logo-next-no-bg-left.svg'
11
12
 
12
13
  /** 菜单项配置接口 */
13
14
  export interface MenuItemConfig {
@@ -20,7 +21,7 @@ export interface MenuItemConfig {
20
21
  /** 菜单文字颜色 */
21
22
  active?: boolean
22
23
  /** 识别码 */
23
- know?: boolean
24
+ know?: boolean
24
25
  /** 菜单项描述 */
25
26
  desc?: string
26
27
  /** 菜单项提示 */
@@ -44,6 +45,8 @@ export interface FloatingBlockOptions {
44
45
  menuItems?: MenuItemConfig[]
45
46
  /** 遥控端页面地址,默认为: https://agent.opentiny.design/tiny-robot */
46
47
  remoteUrl?: string
48
+ /** 悬浮Logo的url地址,默认为: https://ai.opentiny.design/next-remoter/svgs/logo-next-no-bg-left.svg */
49
+ logoUrl?: string
47
50
  }
48
51
 
49
52
  // 动作类型
@@ -83,7 +86,7 @@ const getDefaultMenuItems = (options: FloatingBlockOptions): MenuItemConfig[] =>
83
86
  know: true,
84
87
  showCopyIcon: true,
85
88
  icon: scan
86
- },
89
+ }
87
90
  ]
88
91
  }
89
92
 
@@ -93,6 +96,8 @@ class FloatingBlock {
93
96
  private floatingBlock!: HTMLDivElement
94
97
  private dropdownMenu!: HTMLDivElement
95
98
  private menuItems: MenuItemConfig[]
99
+ /** 即将关闭dropdown的定时器 */
100
+ private closingTimer = 0
96
101
 
97
102
  // 计算 sessionPrefix 属性
98
103
  private get sessionPrefix(): string {
@@ -107,34 +112,37 @@ class FloatingBlock {
107
112
  this.options = {
108
113
  ...options,
109
114
  qrCodeUrl: options.qrCodeUrl || DEFAULT_QR_CODE_URL,
110
- remoteUrl: options.remoteUrl || DEFAULT_REMOTE_URL
115
+ remoteUrl: options.remoteUrl || DEFAULT_REMOTE_URL,
116
+ logoUrl: options.logoUrl || DEFAULT_LOGO_URL
111
117
  }
112
118
 
113
- // 合并默认菜单项配置和用户配置
114
- this.menuItems = this.mergeMenuItems(options.menuItems)
119
+ // 合并默认菜单项配置和用户配置。 用户不传入任何menu时, 则不自动合并默认菜单了,即不渲染任何菜单。
120
+ if (options.menuItems && options.menuItems.length === 0) {
121
+ this.menuItems = []
122
+ } else {
123
+ this.menuItems = this.mergeMenuItems(options.menuItems)
124
+ }
115
125
 
116
126
  this.init()
117
127
  }
118
128
 
119
129
  private getImageUrl = (asset: string | undefined): HTMLImageElement | undefined => {
120
- if (!asset) return;
121
- const img = new Image();
122
- img.src = asset;
123
- return img;
130
+ if (!asset) return
131
+ const img = new Image()
132
+ img.src = asset
133
+ return img
124
134
  }
125
135
 
126
136
  private renderItem = (): void => {
127
137
  this.menuItems
128
138
  .filter((item) => item.show !== false) // 过滤掉show为false的菜单项
129
- .map(
130
- (item) => {
131
- const wrapper = document.getElementById(`tiny-remoter-icon-item-${item.action}`) as HTMLDivElement;
132
- if (!wrapper) return;
133
- wrapper.innerHTML = '';
134
- const img = this.getImageUrl(item.icon);
135
- if (img) wrapper.appendChild(img);
136
- }
137
- );
139
+ .map((item) => {
140
+ const wrapper = document.getElementById(`tiny-remoter-icon-item-${item.action}`) as HTMLDivElement
141
+ if (!wrapper) return
142
+ wrapper.innerHTML = ''
143
+ const img = this.getImageUrl(item.icon)
144
+ if (img) wrapper.appendChild(img)
145
+ })
138
146
  }
139
147
 
140
148
  /**
@@ -174,7 +182,7 @@ class FloatingBlock {
174
182
  this.floatingBlock.className = 'tiny-remoter-floating-block'
175
183
  this.floatingBlock.innerHTML = `
176
184
  <div class="tiny-remoter-floating-block__icon">
177
- <img style="display: block; width: 56px;" src="${DEFAULT_QR_CODE_URL}/svgs/logo-next-no-bg-left.svg" alt="icon" />
185
+ <img style="display: block; width: 56px;" src="${this.options.logoUrl}" alt="icon" />
178
186
  </div>
179
187
  `
180
188
 
@@ -211,13 +219,14 @@ class FloatingBlock {
211
219
  <div class="tiny-remoter-dropdown-item__desc-wrapper">
212
220
  <div class="tiny-remoter-dropdown-item__desc ${item.active ? 'tiny-remoter-dropdown-item__desc--active' : ''} ${item.know ? 'tiny-remoter-dropdown-item__desc--know' : ''}">${item.desc}</div>
213
221
  <div>
214
- ${item.showCopyIcon
215
- ? `
222
+ ${
223
+ item.showCopyIcon
224
+ ? `
216
225
  <div class="tiny-remoter-copy-icon" id="${item.action}" data-action="${item.action}">
217
226
  <img src="${iconCopy}"/>
218
227
  </div>
219
228
  `
220
- : ''
229
+ : ''
221
230
  }
222
231
  </div>
223
232
  </div>
@@ -234,11 +243,33 @@ class FloatingBlock {
234
243
  this.readyTips(`remote-url`)
235
244
  }
236
245
 
237
-
238
246
  private bindEvents(): void {
239
247
  // 绑定浮动块点击事件
240
248
  this.floatingBlock.addEventListener('click', () => {
241
- this.toggleDropdown()
249
+ this.showAIChat()
250
+ })
251
+
252
+ // 浮动块悬浮处理
253
+ this.floatingBlock.addEventListener('mouseenter', () => {
254
+ this.openDropdown()
255
+
256
+ if (this.closingTimer) {
257
+ window.clearTimeout(this.closingTimer)
258
+ this.closingTimer = 0
259
+ }
260
+ })
261
+ this.floatingBlock.addEventListener('mouseleave', () => {
262
+ this.shouldCloseDropdown()
263
+ })
264
+ // 悬浮菜单进入,则阻止关闭
265
+ this.dropdownMenu.addEventListener('mouseenter', (e: Event) => {
266
+ if (this.closingTimer) {
267
+ window.clearTimeout(this.closingTimer)
268
+ this.closingTimer = 0
269
+ }
270
+ })
271
+ this.dropdownMenu.addEventListener('mouseleave', (e: Event) => {
272
+ this.shouldCloseDropdown()
242
273
  })
243
274
 
244
275
  // 绑定菜单项点击事件
@@ -280,20 +311,24 @@ class FloatingBlock {
280
311
  })
281
312
  }
282
313
 
283
- private toggleDropdown(): void {
284
- if (this.isExpanded) {
285
- this.closeDropdown()
286
- } else {
287
- this.openDropdown()
314
+ private openDropdown(): void {
315
+ // 没有menuItems,则返回
316
+ if (!this.menuItems || (this.menuItems && this.menuItems.length === 0)) {
317
+ return
288
318
  }
289
- }
290
319
 
291
- private openDropdown(): void {
292
320
  this.isExpanded = true
293
321
  this.floatingBlock.classList.add('expanded')
294
322
  this.dropdownMenu.classList.add('show')
295
323
  }
296
324
 
325
+ private shouldCloseDropdown() {
326
+ this.closingTimer = window.setTimeout(() => {
327
+ this.closeDropdown()
328
+ }, 300)
329
+ }
330
+
331
+ /** 真正的立即关闭 */
297
332
  private closeDropdown(): void {
298
333
  this.isExpanded = false
299
334
  this.floatingBlock.classList.remove('expanded')