@talex-touch/utils 1.0.31 → 1.0.33
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/animation/window-node.ts +15 -12
- package/animation/window.ts +19 -15
- package/auth/clerk-types.ts +1 -1
- package/auth/index.ts +1 -1
- package/auth/useAuthState.ts +6 -5
- package/auth/useClerkConfig.ts +4 -4
- package/auth/useClerkProvider.ts +3 -2
- package/channel/index.ts +23 -22
- package/common/file-scan-constants.ts +137 -121
- package/common/file-scan-utils.ts +48 -27
- package/common/index.ts +3 -3
- package/common/search/gather.ts +1 -1
- package/common/search/index.ts +5 -6
- package/common/storage/constants.ts +3 -2
- package/common/storage/entity/app-settings.ts +5 -3
- package/common/storage/entity/shortcut-settings.ts +10 -10
- package/common/storage/shortcut-storage.ts +6 -4
- package/common/utils/file.ts +14 -6
- package/common/utils/index.ts +62 -52
- package/common/utils/polling.ts +88 -84
- package/common/utils/task-queue.ts +11 -10
- package/common/utils/time.ts +50 -47
- package/common/utils/timing.ts +41 -37
- package/core-box/builder/index.ts +1 -1
- package/core-box/builder/tuff-builder.ts +254 -229
- package/core-box/index.ts +4 -6
- package/core-box/preview/index.ts +1 -0
- package/core-box/preview/types.ts +43 -0
- package/core-box/recommendation.ts +77 -0
- package/core-box/tuff/index.ts +1 -1
- package/core-box/tuff/tuff-dsl.ts +328 -266
- package/electron/download-manager.ts +43 -42
- package/electron/env-tool.ts +19 -18
- package/electron/file-parsers/index.ts +2 -2
- package/electron/file-parsers/parsers/text-parser.ts +15 -14
- package/electron/file-parsers/registry.ts +9 -7
- package/electron/file-parsers/types.ts +4 -4
- package/electron/index.ts +2 -2
- package/eventbus/index.ts +11 -11
- package/index.ts +5 -4
- package/intelligence/client.ts +87 -0
- package/intelligence/index.ts +1 -0
- package/package.json +14 -14
- package/permission/index.ts +8 -8
- package/plugin/channel.ts +77 -68
- package/plugin/index.ts +96 -82
- package/plugin/install.ts +8 -8
- package/plugin/log/types.ts +5 -5
- package/plugin/node/index.ts +1 -1
- package/plugin/node/logger-manager.ts +14 -11
- package/plugin/node/logger.ts +8 -8
- package/plugin/plugin-source.ts +11 -11
- package/plugin/preload.ts +1 -1
- package/plugin/providers/registry.ts +8 -7
- package/plugin/providers/types.ts +6 -6
- package/plugin/sdk/README.md +216 -0
- package/plugin/sdk/box-sdk.ts +219 -0
- package/plugin/sdk/channel.ts +20 -20
- package/plugin/sdk/clipboard.ts +8 -6
- package/plugin/sdk/common.ts +10 -6
- package/plugin/sdk/core-box.ts +2 -3
- package/plugin/sdk/division-box.ts +266 -0
- package/plugin/sdk/enum/bridge-event.ts +1 -1
- package/plugin/sdk/examples/storage-onDidChange-example.js +1 -1
- package/plugin/sdk/feature-sdk.ts +235 -0
- package/plugin/sdk/features.ts +34 -26
- package/plugin/sdk/hooks/bridge.ts +3 -6
- package/plugin/sdk/hooks/index.ts +1 -1
- package/plugin/sdk/hooks/life-cycle.ts +4 -10
- package/plugin/sdk/index.ts +10 -7
- package/plugin/sdk/service/index.ts +3 -3
- package/plugin/sdk/storage.ts +4 -4
- package/plugin/sdk/system.ts +1 -1
- package/plugin/sdk/types.ts +165 -146
- package/plugin/sdk/window/index.ts +8 -5
- package/preload/loading.ts +6 -6
- package/preload/renderer.ts +4 -2
- package/renderer/hooks/arg-mapper.ts +1 -2
- package/renderer/hooks/index.ts +2 -0
- package/renderer/hooks/initialize.ts +10 -8
- package/renderer/hooks/performance.ts +4 -4
- package/renderer/hooks/use-channel.ts +150 -0
- package/renderer/hooks/use-intelligence.ts +236 -0
- package/renderer/index.ts +6 -2
- package/renderer/ref.ts +32 -36
- package/renderer/slots.ts +29 -26
- package/renderer/storage/app-settings.ts +16 -6
- package/renderer/storage/base-storage.ts +222 -114
- package/renderer/storage/index.ts +3 -0
- package/renderer/storage/intelligence-storage.ts +218 -0
- package/renderer/storage/openers.ts +13 -3
- package/renderer/touch-sdk/env.ts +41 -41
- package/renderer/touch-sdk/index.ts +1 -1
- package/renderer/touch-sdk/terminal.ts +5 -5
- package/renderer/touch-sdk/utils.ts +4 -3
- package/search/levenshtein-utils.ts +11 -11
- package/search/types.ts +102 -102
- package/service/index.ts +11 -11
- package/service/protocol/index.ts +217 -14
- package/types/division-box.ts +248 -0
- package/types/download.ts +72 -34
- package/types/index.ts +3 -1
- package/types/intelligence.ts +607 -0
- package/types/modules/base.ts +16 -16
- package/types/modules/index.ts +1 -1
- package/types/modules/module-lifecycle.ts +21 -21
- package/types/modules/module-manager.ts +11 -11
- package/types/modules/module.ts +16 -16
- package/types/storage.ts +0 -1
- package/types/touch-app-core.ts +32 -32
- package/types/update.ts +91 -21
- package/core-box/README.md +0 -218
- package/core-box/builder/tuff-builder.example.ts.bak +0 -258
- package/core-box/run-tests.sh +0 -7
- package/core-box/search.ts +0 -1
- package/electron/clipboard-helper.ts +0 -199
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DivisionBox SDK for Plugin Development
|
|
3
|
+
*
|
|
4
|
+
* Provides a simple API for plugins to create and manage DivisionBox instances.
|
|
5
|
+
* DivisionBox is a lightweight floating window container for plugin UIs and tools.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type {
|
|
9
|
+
CloseOptions,
|
|
10
|
+
DivisionBoxConfig,
|
|
11
|
+
DivisionBoxState,
|
|
12
|
+
SessionInfo,
|
|
13
|
+
} from '../../types/division-box'
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* State change event handler
|
|
17
|
+
*/
|
|
18
|
+
export type StateChangeHandler = (data: {
|
|
19
|
+
sessionId: string
|
|
20
|
+
state: DivisionBoxState
|
|
21
|
+
}) => void
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* DivisionBox SDK interface for plugins
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```typescript
|
|
28
|
+
* // Open a DivisionBox
|
|
29
|
+
* const { sessionId } = await plugin.divisionBox.open({
|
|
30
|
+
* url: 'https://example.com/tool',
|
|
31
|
+
* title: 'My Tool',
|
|
32
|
+
* size: 'medium',
|
|
33
|
+
* keepAlive: true
|
|
34
|
+
* })
|
|
35
|
+
*
|
|
36
|
+
* // Listen for state changes
|
|
37
|
+
* plugin.divisionBox.onStateChange((data) => {
|
|
38
|
+
* console.log(`Session ${data.sessionId} is now ${data.state}`)
|
|
39
|
+
* })
|
|
40
|
+
*
|
|
41
|
+
* // Close the DivisionBox
|
|
42
|
+
* await plugin.divisionBox.close(sessionId)
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
export interface DivisionBoxSDK {
|
|
46
|
+
/**
|
|
47
|
+
* Opens a new DivisionBox instance
|
|
48
|
+
*
|
|
49
|
+
* @param config - Configuration for the DivisionBox
|
|
50
|
+
* @returns Promise resolving to session information
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* ```typescript
|
|
54
|
+
* const { sessionId } = await plugin.divisionBox.open({
|
|
55
|
+
* url: 'https://example.com',
|
|
56
|
+
* title: 'Web Tool',
|
|
57
|
+
* icon: 'ri:tools-line',
|
|
58
|
+
* size: 'medium',
|
|
59
|
+
* keepAlive: true,
|
|
60
|
+
* header: {
|
|
61
|
+
* show: true,
|
|
62
|
+
* title: 'Custom Title',
|
|
63
|
+
* actions: [
|
|
64
|
+
* { label: 'Refresh', icon: 'ri:refresh-line', onClick: () => {} }
|
|
65
|
+
* ]
|
|
66
|
+
* }
|
|
67
|
+
* })
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
70
|
+
open(config: DivisionBoxConfig): Promise<SessionInfo>
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Closes a DivisionBox instance
|
|
74
|
+
*
|
|
75
|
+
* @param sessionId - The session ID to close
|
|
76
|
+
* @param options - Optional close options
|
|
77
|
+
* @returns Promise that resolves when closed
|
|
78
|
+
*
|
|
79
|
+
* @example
|
|
80
|
+
* ```typescript
|
|
81
|
+
* // Simple close
|
|
82
|
+
* await plugin.divisionBox.close(sessionId)
|
|
83
|
+
*
|
|
84
|
+
* // Close with delay and animation
|
|
85
|
+
* await plugin.divisionBox.close(sessionId, {
|
|
86
|
+
* delay: 1000,
|
|
87
|
+
* animation: true
|
|
88
|
+
* })
|
|
89
|
+
*
|
|
90
|
+
* // Force close (ignore keepAlive)
|
|
91
|
+
* await plugin.divisionBox.close(sessionId, {
|
|
92
|
+
* force: true
|
|
93
|
+
* })
|
|
94
|
+
* ```
|
|
95
|
+
*/
|
|
96
|
+
close(sessionId: string, options?: CloseOptions): Promise<void>
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Registers a state change listener
|
|
100
|
+
*
|
|
101
|
+
* @param handler - Callback function for state changes
|
|
102
|
+
* @returns Unsubscribe function
|
|
103
|
+
*
|
|
104
|
+
* @example
|
|
105
|
+
* ```typescript
|
|
106
|
+
* const unsubscribe = plugin.divisionBox.onStateChange((data) => {
|
|
107
|
+
* console.log(`Session ${data.sessionId} changed to ${data.state}`)
|
|
108
|
+
* })
|
|
109
|
+
*
|
|
110
|
+
* // Later, unsubscribe
|
|
111
|
+
* unsubscribe()
|
|
112
|
+
* ```
|
|
113
|
+
*/
|
|
114
|
+
onStateChange(handler: StateChangeHandler): () => void
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Updates session state data
|
|
118
|
+
*
|
|
119
|
+
* @param sessionId - The session ID
|
|
120
|
+
* @param key - State key
|
|
121
|
+
* @param value - State value
|
|
122
|
+
* @returns Promise that resolves when updated
|
|
123
|
+
*
|
|
124
|
+
* @example
|
|
125
|
+
* ```typescript
|
|
126
|
+
* // Save scroll position
|
|
127
|
+
* await plugin.divisionBox.updateState(sessionId, 'scrollY', 150)
|
|
128
|
+
*
|
|
129
|
+
* // Save draft content
|
|
130
|
+
* await plugin.divisionBox.updateState(sessionId, 'draft', {
|
|
131
|
+
* text: 'Hello world',
|
|
132
|
+
* timestamp: Date.now()
|
|
133
|
+
* })
|
|
134
|
+
* ```
|
|
135
|
+
*/
|
|
136
|
+
updateState(sessionId: string, key: string, value: any): Promise<void>
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Gets session state data
|
|
140
|
+
*
|
|
141
|
+
* @param sessionId - The session ID
|
|
142
|
+
* @param key - State key
|
|
143
|
+
* @returns Promise resolving to the state value
|
|
144
|
+
*
|
|
145
|
+
* @example
|
|
146
|
+
* ```typescript
|
|
147
|
+
* const scrollY = await plugin.divisionBox.getState(sessionId, 'scrollY')
|
|
148
|
+
* const draft = await plugin.divisionBox.getState(sessionId, 'draft')
|
|
149
|
+
* ```
|
|
150
|
+
*/
|
|
151
|
+
getState(sessionId: string, key: string): Promise<any>
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Creates a DivisionBox SDK instance for plugin use
|
|
156
|
+
*
|
|
157
|
+
* @param channel - The plugin channel bridge for IPC communication
|
|
158
|
+
* @returns Configured DivisionBox SDK instance
|
|
159
|
+
*
|
|
160
|
+
* @internal
|
|
161
|
+
*/
|
|
162
|
+
export function createDivisionBoxSDK(channel: any): DivisionBoxSDK {
|
|
163
|
+
const stateChangeHandlers: Set<StateChangeHandler> = new Set()
|
|
164
|
+
|
|
165
|
+
// Register listener for state change events from main process
|
|
166
|
+
// The channel can be either IPluginChannelBridge (main process) or window.$channel (renderer)
|
|
167
|
+
const registerListener = () => {
|
|
168
|
+
if (channel.onMain) {
|
|
169
|
+
// Main process plugin context
|
|
170
|
+
channel.onMain('division-box:state-changed', (event: any) => {
|
|
171
|
+
stateChangeHandlers.forEach(handler => handler(event.data || event))
|
|
172
|
+
})
|
|
173
|
+
} else if (channel.on) {
|
|
174
|
+
// Renderer process context
|
|
175
|
+
channel.on('division-box:state-changed', (data: any) => {
|
|
176
|
+
stateChangeHandlers.forEach(handler => handler(data))
|
|
177
|
+
})
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
registerListener()
|
|
182
|
+
|
|
183
|
+
return {
|
|
184
|
+
async open(config: DivisionBoxConfig): Promise<SessionInfo> {
|
|
185
|
+
// Send to main process
|
|
186
|
+
const sendFn = channel.sendToMain || channel.send
|
|
187
|
+
const result = await sendFn('division-box:open', config)
|
|
188
|
+
|
|
189
|
+
if (!result.success) {
|
|
190
|
+
throw new Error(result.error?.message || 'Failed to open DivisionBox')
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
return result.data
|
|
194
|
+
},
|
|
195
|
+
|
|
196
|
+
async close(sessionId: string, options?: CloseOptions): Promise<void> {
|
|
197
|
+
const sendFn = channel.sendToMain || channel.send
|
|
198
|
+
const result = await sendFn('division-box:close', { sessionId, options })
|
|
199
|
+
|
|
200
|
+
if (!result.success) {
|
|
201
|
+
throw new Error(result.error?.message || 'Failed to close DivisionBox')
|
|
202
|
+
}
|
|
203
|
+
},
|
|
204
|
+
|
|
205
|
+
onStateChange(handler: StateChangeHandler): () => void {
|
|
206
|
+
stateChangeHandlers.add(handler)
|
|
207
|
+
|
|
208
|
+
return () => {
|
|
209
|
+
stateChangeHandlers.delete(handler)
|
|
210
|
+
}
|
|
211
|
+
},
|
|
212
|
+
|
|
213
|
+
async updateState(sessionId: string, key: string, value: any): Promise<void> {
|
|
214
|
+
const sendFn = channel.sendToMain || channel.send
|
|
215
|
+
const result = await sendFn('division-box:update-state', {
|
|
216
|
+
sessionId,
|
|
217
|
+
key,
|
|
218
|
+
value
|
|
219
|
+
})
|
|
220
|
+
|
|
221
|
+
if (!result.success) {
|
|
222
|
+
throw new Error(result.error?.message || 'Failed to update state')
|
|
223
|
+
}
|
|
224
|
+
},
|
|
225
|
+
|
|
226
|
+
async getState(sessionId: string, key: string): Promise<any> {
|
|
227
|
+
const sendFn = channel.sendToMain || channel.send
|
|
228
|
+
const result = await sendFn('division-box:get-state', {
|
|
229
|
+
sessionId,
|
|
230
|
+
key
|
|
231
|
+
})
|
|
232
|
+
|
|
233
|
+
if (!result.success) {
|
|
234
|
+
throw new Error(result.error?.message || 'Failed to get state')
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
return result.data
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Hook for using DivisionBox SDK in plugin context
|
|
244
|
+
*
|
|
245
|
+
* @returns DivisionBox SDK instance
|
|
246
|
+
*
|
|
247
|
+
* @example
|
|
248
|
+
* ```typescript
|
|
249
|
+
* const divisionBox = useDivisionBox()
|
|
250
|
+
*
|
|
251
|
+
* const { sessionId } = await divisionBox.open({
|
|
252
|
+
* url: 'https://example.com',
|
|
253
|
+
* title: 'My Tool'
|
|
254
|
+
* })
|
|
255
|
+
* ```
|
|
256
|
+
*/
|
|
257
|
+
export function useDivisionBox(): DivisionBoxSDK {
|
|
258
|
+
// @ts-ignore - window.$channel is injected by the plugin system
|
|
259
|
+
const channel = window.$channel
|
|
260
|
+
|
|
261
|
+
if (!channel) {
|
|
262
|
+
throw new Error('[DivisionBox SDK] Channel not available. Make sure this is called in a plugin context.')
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
return createDivisionBoxSDK(channel)
|
|
266
|
+
}
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Feature SDK for Plugin Development
|
|
3
|
+
*
|
|
4
|
+
* Provides a unified API for plugins to manage search result items (TuffItems)
|
|
5
|
+
* in the CoreBox interface. This SDK handles item lifecycle, updates, and
|
|
6
|
+
* input change notifications.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { TuffItem } from '../../core-box/tuff'
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Input change event handler
|
|
13
|
+
*/
|
|
14
|
+
export type InputChangeHandler = (input: string) => void
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Feature SDK interface for plugins
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```typescript
|
|
21
|
+
* // Push items to CoreBox
|
|
22
|
+
* plugin.feature.pushItems([
|
|
23
|
+
* { id: 'item-1', title: 'Result 1', ... },
|
|
24
|
+
* { id: 'item-2', title: 'Result 2', ... }
|
|
25
|
+
* ])
|
|
26
|
+
*
|
|
27
|
+
* // Update a specific item
|
|
28
|
+
* plugin.feature.updateItem('item-1', { title: 'Updated Title' })
|
|
29
|
+
*
|
|
30
|
+
* // Listen for input changes
|
|
31
|
+
* plugin.feature.onInputChange((input) => {
|
|
32
|
+
* console.log('User typed:', input)
|
|
33
|
+
* })
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
export interface FeatureSDK {
|
|
37
|
+
/**
|
|
38
|
+
* Pushes multiple items to the CoreBox search results
|
|
39
|
+
*
|
|
40
|
+
* @param items - Array of TuffItem objects to display
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* ```typescript
|
|
44
|
+
* plugin.feature.pushItems([
|
|
45
|
+
* {
|
|
46
|
+
* id: 'calc-result',
|
|
47
|
+
* title: { text: '42' },
|
|
48
|
+
* subtitle: { text: 'Calculation result' },
|
|
49
|
+
* source: { id: 'calculator', name: 'Calculator' }
|
|
50
|
+
* }
|
|
51
|
+
* ])
|
|
52
|
+
* ```
|
|
53
|
+
*/
|
|
54
|
+
pushItems(items: TuffItem[]): void
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Updates a specific item by ID
|
|
58
|
+
*
|
|
59
|
+
* @param id - The unique ID of the item to update
|
|
60
|
+
* @param updates - Partial TuffItem with fields to update
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* ```typescript
|
|
64
|
+
* // Update title and subtitle
|
|
65
|
+
* plugin.feature.updateItem('item-1', {
|
|
66
|
+
* title: { text: 'New Title' },
|
|
67
|
+
* subtitle: { text: 'Updated subtitle' }
|
|
68
|
+
* })
|
|
69
|
+
* ```
|
|
70
|
+
*/
|
|
71
|
+
updateItem(id: string, updates: Partial<TuffItem>): void
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Removes a specific item by ID
|
|
75
|
+
*
|
|
76
|
+
* @param id - The unique ID of the item to remove
|
|
77
|
+
*
|
|
78
|
+
* @example
|
|
79
|
+
* ```typescript
|
|
80
|
+
* plugin.feature.removeItem('item-1')
|
|
81
|
+
* ```
|
|
82
|
+
*/
|
|
83
|
+
removeItem(id: string): void
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Clears all items pushed by this plugin
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* ```typescript
|
|
90
|
+
* plugin.feature.clearItems()
|
|
91
|
+
* ```
|
|
92
|
+
*/
|
|
93
|
+
clearItems(): void
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Gets all items currently pushed by this plugin
|
|
97
|
+
*
|
|
98
|
+
* @returns Array of TuffItem objects
|
|
99
|
+
*
|
|
100
|
+
* @example
|
|
101
|
+
* ```typescript
|
|
102
|
+
* const items = plugin.feature.getItems()
|
|
103
|
+
* console.log(`Currently showing ${items.length} items`)
|
|
104
|
+
* ```
|
|
105
|
+
*/
|
|
106
|
+
getItems(): TuffItem[]
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Registers a listener for input changes in the CoreBox search field
|
|
110
|
+
*
|
|
111
|
+
* @param handler - Callback function invoked when input changes
|
|
112
|
+
* @returns Unsubscribe function
|
|
113
|
+
*
|
|
114
|
+
* @example
|
|
115
|
+
* ```typescript
|
|
116
|
+
* const unsubscribe = plugin.feature.onInputChange((input) => {
|
|
117
|
+
* console.log('User typed:', input)
|
|
118
|
+
* // Perform real-time search
|
|
119
|
+
* performSearch(input)
|
|
120
|
+
* })
|
|
121
|
+
*
|
|
122
|
+
* // Later, unsubscribe
|
|
123
|
+
* unsubscribe()
|
|
124
|
+
* ```
|
|
125
|
+
*/
|
|
126
|
+
onInputChange(handler: InputChangeHandler): () => void
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Creates a Feature SDK instance for plugin use
|
|
131
|
+
*
|
|
132
|
+
* @param boxItemsAPI - The boxItems API object from plugin context
|
|
133
|
+
* @param channel - The plugin channel bridge for IPC communication
|
|
134
|
+
* @returns Configured Feature SDK instance
|
|
135
|
+
*
|
|
136
|
+
* @internal
|
|
137
|
+
*/
|
|
138
|
+
export function createFeatureSDK(boxItemsAPI: any, channel: any): FeatureSDK {
|
|
139
|
+
const inputChangeHandlers: Set<InputChangeHandler> = new Set()
|
|
140
|
+
|
|
141
|
+
// Register listener for input change events from main process
|
|
142
|
+
const registerListener = () => {
|
|
143
|
+
if (channel.onMain) {
|
|
144
|
+
// Main process plugin context
|
|
145
|
+
channel.onMain('core-box:input-changed', (event: any) => {
|
|
146
|
+
const input = event.data?.input || event.input || ''
|
|
147
|
+
inputChangeHandlers.forEach(handler => handler(input))
|
|
148
|
+
})
|
|
149
|
+
} else if (channel.on) {
|
|
150
|
+
// Renderer process context
|
|
151
|
+
channel.on('core-box:input-changed', (data: any) => {
|
|
152
|
+
const input = data?.input || data || ''
|
|
153
|
+
inputChangeHandlers.forEach(handler => handler(input))
|
|
154
|
+
})
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
registerListener()
|
|
159
|
+
|
|
160
|
+
return {
|
|
161
|
+
pushItems(items: TuffItem[]): void {
|
|
162
|
+
if (!boxItemsAPI || !boxItemsAPI.pushItems) {
|
|
163
|
+
throw new Error('[Feature SDK] boxItems API not available')
|
|
164
|
+
}
|
|
165
|
+
boxItemsAPI.pushItems(items)
|
|
166
|
+
},
|
|
167
|
+
|
|
168
|
+
updateItem(id: string, updates: Partial<TuffItem>): void {
|
|
169
|
+
if (!boxItemsAPI || !boxItemsAPI.update) {
|
|
170
|
+
throw new Error('[Feature SDK] boxItems API not available')
|
|
171
|
+
}
|
|
172
|
+
boxItemsAPI.update(id, updates)
|
|
173
|
+
},
|
|
174
|
+
|
|
175
|
+
removeItem(id: string): void {
|
|
176
|
+
if (!boxItemsAPI || !boxItemsAPI.remove) {
|
|
177
|
+
throw new Error('[Feature SDK] boxItems API not available')
|
|
178
|
+
}
|
|
179
|
+
boxItemsAPI.remove(id)
|
|
180
|
+
},
|
|
181
|
+
|
|
182
|
+
clearItems(): void {
|
|
183
|
+
if (!boxItemsAPI || !boxItemsAPI.clear) {
|
|
184
|
+
throw new Error('[Feature SDK] boxItems API not available')
|
|
185
|
+
}
|
|
186
|
+
boxItemsAPI.clear()
|
|
187
|
+
},
|
|
188
|
+
|
|
189
|
+
getItems(): TuffItem[] {
|
|
190
|
+
if (!boxItemsAPI || !boxItemsAPI.getItems) {
|
|
191
|
+
throw new Error('[Feature SDK] boxItems API not available')
|
|
192
|
+
}
|
|
193
|
+
return boxItemsAPI.getItems()
|
|
194
|
+
},
|
|
195
|
+
|
|
196
|
+
onInputChange(handler: InputChangeHandler): () => void {
|
|
197
|
+
inputChangeHandlers.add(handler)
|
|
198
|
+
|
|
199
|
+
return () => {
|
|
200
|
+
inputChangeHandlers.delete(handler)
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Hook for using Feature SDK in plugin context
|
|
208
|
+
*
|
|
209
|
+
* @returns Feature SDK instance
|
|
210
|
+
*
|
|
211
|
+
* @example
|
|
212
|
+
* ```typescript
|
|
213
|
+
* const feature = useFeature()
|
|
214
|
+
*
|
|
215
|
+
* feature.pushItems([
|
|
216
|
+
* { id: '1', title: { text: 'Item 1' }, ... }
|
|
217
|
+
* ])
|
|
218
|
+
* ```
|
|
219
|
+
*/
|
|
220
|
+
export function useFeature(): FeatureSDK {
|
|
221
|
+
// @ts-ignore - window.$boxItems and window.$channel are injected by the plugin system
|
|
222
|
+
const boxItemsAPI = window.$boxItems
|
|
223
|
+
// @ts-ignore
|
|
224
|
+
const channel = window.$channel
|
|
225
|
+
|
|
226
|
+
if (!boxItemsAPI) {
|
|
227
|
+
throw new Error('[Feature SDK] boxItems API not available. Make sure this is called in a plugin context.')
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
if (!channel) {
|
|
231
|
+
throw new Error('[Feature SDK] Channel not available. Make sure this is called in a plugin context.')
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
return createFeatureSDK(boxItemsAPI, channel)
|
|
235
|
+
}
|