@genfeedai/workflow-ui 0.1.3 → 0.1.5

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 (84) hide show
  1. package/dist/canvas.d.mts +16 -2
  2. package/dist/canvas.mjs +10 -8
  3. package/dist/chunk-6PSJTBNV.mjs +638 -0
  4. package/dist/chunk-7H3WJJYS.mjs +52 -0
  5. package/dist/{chunk-HCXI63ME.mjs → chunk-AUQGOJOQ.mjs} +27 -4
  6. package/dist/{chunk-AOTUCJMA.mjs → chunk-GWBGK3KL.mjs} +2 -2
  7. package/dist/chunk-JTPADIUO.mjs +130 -0
  8. package/dist/{chunk-SQK4JDYY.mjs → chunk-LT3ZJJL6.mjs} +9 -2
  9. package/dist/{chunk-7P2JWDC7.mjs → chunk-O5II6BOJ.mjs} +1198 -254
  10. package/dist/{chunk-AUZR6REQ.mjs → chunk-OQREHJXK.mjs} +1 -1
  11. package/dist/chunk-OY7BRSGG.mjs +60 -0
  12. package/dist/{chunk-E3YBVMYZ.mjs → chunk-PANZDSP6.mjs} +274 -305
  13. package/dist/chunk-PCIWWD37.mjs +90 -0
  14. package/dist/{chunk-RIGVIEYB.mjs → chunk-R727OFBR.mjs} +11 -1
  15. package/dist/chunk-ZD2BADZO.mjs +1294 -0
  16. package/dist/contextMenuStore-DMg0hJQ1.d.mts +22 -0
  17. package/dist/hooks.d.mts +53 -244
  18. package/dist/hooks.mjs +6 -6
  19. package/dist/index.d.mts +11 -7
  20. package/dist/index.mjs +13 -11
  21. package/dist/lib.d.mts +250 -4
  22. package/dist/lib.mjs +562 -2
  23. package/dist/nodes.d.mts +3 -1
  24. package/dist/nodes.mjs +6 -6
  25. package/dist/panels.mjs +3 -4
  26. package/dist/{promptLibraryStore-zqb59nsu.d.mts → promptLibraryStore-Bgw5LzvD.d.mts} +33 -5
  27. package/dist/provider.d.mts +2 -2
  28. package/dist/provider.mjs +0 -1
  29. package/dist/stores.d.mts +4 -3
  30. package/dist/stores.mjs +3 -40
  31. package/dist/toolbar.d.mts +3 -1
  32. package/dist/toolbar.mjs +5 -4
  33. package/dist/{types-ipAnBzAJ.d.mts → types-CF6DPx0P.d.mts} +8 -3
  34. package/dist/ui.d.mts +1 -1
  35. package/dist/ui.mjs +0 -1
  36. package/dist/{hooks.d.ts → useCommentNavigation-NzJjkaj2.d.mts} +15 -2
  37. package/dist/workflowStore-UAAKOOIK.mjs +2 -0
  38. package/package.json +31 -25
  39. package/dist/canvas.d.ts +0 -27
  40. package/dist/canvas.js +0 -45
  41. package/dist/chunk-3SPPKCWR.js +0 -458
  42. package/dist/chunk-3TMV3K34.js +0 -534
  43. package/dist/chunk-3YFFDHC5.js +0 -300
  44. package/dist/chunk-4MZ62VMF.js +0 -37
  45. package/dist/chunk-5HJFQVUR.js +0 -61
  46. package/dist/chunk-5LQ4QBR5.js +0 -2
  47. package/dist/chunk-6DOEUDD5.js +0 -254
  48. package/dist/chunk-AXFOCPPP.js +0 -998
  49. package/dist/chunk-BMFRA6GK.js +0 -1546
  50. package/dist/chunk-E323WAZG.mjs +0 -272
  51. package/dist/chunk-ECD5J2BA.js +0 -6022
  52. package/dist/chunk-EMGXUNBL.js +0 -120
  53. package/dist/chunk-EMUMKW5C.js +0 -107
  54. package/dist/chunk-FOMOOERN.js +0 -2
  55. package/dist/chunk-IASLG6IA.mjs +0 -118
  56. package/dist/chunk-IHF35QZD.js +0 -1095
  57. package/dist/chunk-JLWKW3G5.js +0 -2
  58. package/dist/chunk-KDIWRSYV.js +0 -375
  59. package/dist/chunk-L5TF4EHW.mjs +0 -1
  60. package/dist/chunk-RJ262NXS.js +0 -24
  61. package/dist/chunk-RXNEDWK2.js +0 -141
  62. package/dist/chunk-SEV2DWKF.js +0 -744
  63. package/dist/chunk-ZJWP5KGZ.mjs +0 -33
  64. package/dist/hooks.js +0 -56
  65. package/dist/index.d.ts +0 -29
  66. package/dist/index.js +0 -180
  67. package/dist/lib.d.ts +0 -164
  68. package/dist/lib.js +0 -144
  69. package/dist/nodes.d.ts +0 -128
  70. package/dist/nodes.js +0 -151
  71. package/dist/panels.d.ts +0 -22
  72. package/dist/panels.js +0 -21
  73. package/dist/promptLibraryStore-BZnfmEkc.d.ts +0 -464
  74. package/dist/provider.d.ts +0 -29
  75. package/dist/provider.js +0 -17
  76. package/dist/stores.d.ts +0 -96
  77. package/dist/stores.js +0 -113
  78. package/dist/toolbar.d.ts +0 -73
  79. package/dist/toolbar.js +0 -34
  80. package/dist/types-ipAnBzAJ.d.ts +0 -46
  81. package/dist/ui.d.ts +0 -67
  82. package/dist/ui.js +0 -84
  83. package/dist/workflowStore-7SDJC4UR.mjs +0 -3
  84. package/dist/workflowStore-LNJQ5RZG.js +0 -12
@@ -1,534 +0,0 @@
1
- 'use strict';
2
-
3
- var chunk5HJFQVUR_js = require('./chunk-5HJFQVUR.js');
4
- var chunkEMUMKW5C_js = require('./chunk-EMUMKW5C.js');
5
- var chunkAXFOCPPP_js = require('./chunk-AXFOCPPP.js');
6
- var chunkIHF35QZD_js = require('./chunk-IHF35QZD.js');
7
- var chunkRJ262NXS_js = require('./chunk-RJ262NXS.js');
8
- var react = require('react');
9
- var lucideReact = require('lucide-react');
10
- var jsxRuntime = require('react/jsx-runtime');
11
- var types = require('@genfeedai/types');
12
- var shallow = require('zustand/react/shallow');
13
-
14
- function useAIGenNode({
15
- nodeId,
16
- selectedModel,
17
- schemaParams
18
- }) {
19
- const updateNodeData = chunkIHF35QZD_js.useWorkflowStore((state) => state.updateNodeData);
20
- const schemaProperties = react.useMemo(() => {
21
- const schema = selectedModel?.inputSchema;
22
- return schema?.properties;
23
- }, [selectedModel?.inputSchema]);
24
- const enumValues = react.useMemo(
25
- () => chunkEMUMKW5C_js.extractEnumValues(
26
- selectedModel?.componentSchemas
27
- ),
28
- [selectedModel?.componentSchemas]
29
- );
30
- const modelSupportsImageInput = react.useMemo(
31
- () => chunkEMUMKW5C_js.supportsImageInput(selectedModel?.inputSchema),
32
- [selectedModel?.inputSchema]
33
- );
34
- const componentSchemas = selectedModel?.componentSchemas;
35
- const handleSchemaParamChange = react.useCallback(
36
- (key, value) => {
37
- const currentNode = chunkIHF35QZD_js.useWorkflowStore.getState().getNodeById(nodeId);
38
- const currentData = currentNode?.data;
39
- updateNodeData(nodeId, {
40
- schemaParams: {
41
- ...currentData?.schemaParams ?? {},
42
- [key]: value
43
- }
44
- });
45
- },
46
- [nodeId, updateNodeData]
47
- );
48
- return {
49
- schemaProperties,
50
- enumValues,
51
- modelSupportsImageInput,
52
- handleSchemaParamChange,
53
- componentSchemas
54
- };
55
- }
56
- function useAIGenNodeHeader({
57
- modelDisplayName,
58
- isProcessing,
59
- canGenerate,
60
- hasOutput,
61
- onModelBrowse,
62
- onGenerate,
63
- onStop,
64
- onExpand
65
- }) {
66
- const titleElement = react.useMemo(
67
- () => /* @__PURE__ */ jsxRuntime.jsxs(
68
- "button",
69
- {
70
- className: `flex flex-1 items-center gap-1 text-sm font-medium text-left text-foreground ${isProcessing ? "opacity-50 cursor-default" : "hover:text-foreground/80 cursor-pointer"}`,
71
- onClick: () => !isProcessing && onModelBrowse(),
72
- title: "Browse models",
73
- disabled: isProcessing,
74
- children: [
75
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: modelDisplayName }),
76
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { className: "h-3 w-3 shrink-0" })
77
- ]
78
- }
79
- ),
80
- [modelDisplayName, isProcessing, onModelBrowse]
81
- );
82
- const headerActions = react.useMemo(
83
- () => /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
84
- hasOutput && /* @__PURE__ */ jsxRuntime.jsx(chunk5HJFQVUR_js.Button, { variant: "ghost", size: "icon-sm", onClick: onExpand, title: "Expand preview", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Expand, { className: "h-3 w-3" }) }),
85
- isProcessing ? /* @__PURE__ */ jsxRuntime.jsxs(chunk5HJFQVUR_js.Button, { variant: "destructive", size: "sm", onClick: onStop, children: [
86
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Square, { className: "h-4 w-4 fill-current" }),
87
- "Generating"
88
- ] }) : /* @__PURE__ */ jsxRuntime.jsxs(
89
- chunk5HJFQVUR_js.Button,
90
- {
91
- variant: canGenerate ? "default" : "secondary",
92
- size: "sm",
93
- onClick: onGenerate,
94
- disabled: !canGenerate,
95
- children: [
96
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Play, { className: "h-4 w-4 fill-current" }),
97
- "Generate"
98
- ]
99
- }
100
- )
101
- ] }),
102
- [hasOutput, isProcessing, canGenerate, onGenerate, onStop, onExpand]
103
- );
104
- return { titleElement, headerActions };
105
- }
106
- function useAutoLoadModelSchema({
107
- currentModel,
108
- selectedModel,
109
- modelIdMap,
110
- onModelSelect
111
- }) {
112
- const { modelSchema } = chunkRJ262NXS_js.useWorkflowUIConfig();
113
- const hasAttemptedSchemaLoad = react.useRef(false);
114
- react.useEffect(() => {
115
- if (hasAttemptedSchemaLoad.current || selectedModel || !currentModel || !modelSchema) {
116
- return;
117
- }
118
- const modelId = modelIdMap[currentModel];
119
- if (!modelId) return;
120
- const controller = new AbortController();
121
- let isCancelled = false;
122
- const loadSchema = async () => {
123
- try {
124
- const model = await modelSchema.fetchModelSchema(modelId, controller.signal);
125
- if (model && !isCancelled) {
126
- hasAttemptedSchemaLoad.current = true;
127
- onModelSelect(model);
128
- }
129
- } catch {
130
- }
131
- };
132
- loadSchema();
133
- return () => {
134
- isCancelled = true;
135
- controller.abort();
136
- };
137
- }, [currentModel, selectedModel, modelIdMap, onModelSelect, modelSchema]);
138
- }
139
- function useRequiredInputs(nodeId, nodeType) {
140
- const edges = chunkIHF35QZD_js.useWorkflowStore((state) => state.edges);
141
- return react.useMemo(() => {
142
- const nodeDef = types.NODE_DEFINITIONS[nodeType];
143
- if (!nodeDef) {
144
- return { hasRequiredInputs: true, missingInputs: [], connectionStatus: /* @__PURE__ */ new Map() };
145
- }
146
- const incomingEdges = edges.filter((e) => e.target === nodeId);
147
- const connectedHandles = new Set(incomingEdges.map((e) => e.targetHandle).filter(Boolean));
148
- const connectionStatus = /* @__PURE__ */ new Map();
149
- const missingInputs = [];
150
- for (const input of nodeDef.inputs) {
151
- const isConnected = connectedHandles.has(input.id);
152
- connectionStatus.set(input.id, isConnected);
153
- if (input.required && !isConnected) {
154
- missingInputs.push(input.id);
155
- }
156
- }
157
- return {
158
- hasRequiredInputs: missingInputs.length === 0,
159
- missingInputs,
160
- connectionStatus
161
- };
162
- }, [nodeId, nodeType, edges]);
163
- }
164
- function extractOutputValue(node, handleType) {
165
- const data = node.data;
166
- if (handleType === "text") {
167
- return data.outputText ?? data.prompt;
168
- } else if (handleType === "image") {
169
- return data.outputImage ?? data.image;
170
- } else if (handleType === "video") {
171
- return data.outputVideo ?? data.video;
172
- } else if (handleType === "audio") {
173
- return data.outputAudio ?? data.audio;
174
- }
175
- return void 0;
176
- }
177
- function useCanGenerate({
178
- nodeId,
179
- nodeType,
180
- inputSchema,
181
- schemaParams
182
- }) {
183
- const { hasRequiredInputs, missingInputs } = useRequiredInputs(nodeId, nodeType);
184
- const getConnectedInputs = chunkIHF35QZD_js.useWorkflowStore((state) => state.getConnectedInputs);
185
- const incomingEdgesSelector = react.useCallback(
186
- (state) => state.edges.filter((e) => e.target === nodeId),
187
- [nodeId]
188
- );
189
- const incomingEdges = chunkIHF35QZD_js.useWorkflowStore(shallow.useShallow(incomingEdgesSelector));
190
- const connectedOutputsSelector = react.useCallback(
191
- (state) => {
192
- const outputs = {};
193
- for (const edge of incomingEdges) {
194
- const sourceNode = state.nodes.find((n) => n.id === edge.source);
195
- if (sourceNode) {
196
- outputs[edge.source] = extractOutputValue(sourceNode, edge.sourceHandle);
197
- }
198
- }
199
- return outputs;
200
- },
201
- [incomingEdges]
202
- );
203
- chunkIHF35QZD_js.useWorkflowStore(shallow.useShallow(connectedOutputsSelector));
204
- return react.useMemo(() => {
205
- const missingItems = [];
206
- for (const inputId of missingInputs) {
207
- missingItems.push({
208
- type: "connection",
209
- field: inputId,
210
- message: `Missing connection: ${inputId}`
211
- });
212
- }
213
- const connectedInputs = getConnectedInputs(nodeId);
214
- const nodeDef = types.NODE_DEFINITIONS[nodeType];
215
- const requiredHandleIds = new Set(
216
- nodeDef?.inputs.filter((h) => h.required).map((h) => h.id) ?? []
217
- );
218
- let hasRequiredData = true;
219
- let hasConnectedData = true;
220
- if (hasRequiredInputs) {
221
- for (const edge of incomingEdges) {
222
- const handleId = edge.targetHandle;
223
- if (!handleId) continue;
224
- if (!connectedInputs.has(handleId)) {
225
- hasConnectedData = false;
226
- if (requiredHandleIds.has(handleId)) {
227
- hasRequiredData = false;
228
- }
229
- }
230
- }
231
- }
232
- const schemaValidation = chunkEMUMKW5C_js.validateRequiredSchemaFields(
233
- inputSchema,
234
- schemaParams ?? {},
235
- chunkEMUMKW5C_js.CONNECTION_FIELDS
236
- );
237
- for (const field of schemaValidation.missingFields) {
238
- missingItems.push({
239
- type: "schema",
240
- field,
241
- message: `Required field: ${field}`
242
- });
243
- }
244
- const canGenerate = hasRequiredInputs && hasRequiredData && schemaValidation.isValid;
245
- return {
246
- canGenerate,
247
- missingItems,
248
- hasRequiredConnections: hasRequiredInputs,
249
- hasConnectedData,
250
- hasRequiredSchemaFields: schemaValidation.isValid
251
- };
252
- }, [
253
- nodeId,
254
- nodeType,
255
- hasRequiredInputs,
256
- missingInputs,
257
- inputSchema,
258
- schemaParams,
259
- getConnectedInputs,
260
- incomingEdges
261
- ]);
262
- }
263
- function useModelSelection({ nodeId, modelMap, fallbackModel }) {
264
- const updateNodeData = chunkIHF35QZD_js.useWorkflowStore((state) => state.updateNodeData);
265
- const handleModelSelect = react.useCallback(
266
- (model) => {
267
- const internalModel = modelMap[model.id] ?? fallbackModel;
268
- const schemaDefaults = chunkEMUMKW5C_js.getSchemaDefaults(model.inputSchema);
269
- const selectedModel = {
270
- provider: model.provider,
271
- modelId: model.id,
272
- displayName: model.displayName,
273
- inputSchema: model.inputSchema,
274
- componentSchemas: model.componentSchemas
275
- };
276
- updateNodeData(nodeId, {
277
- model: internalModel,
278
- provider: model.provider,
279
- selectedModel,
280
- schemaParams: schemaDefaults
281
- });
282
- },
283
- [nodeId, modelMap, fallbackModel, updateNodeData]
284
- );
285
- return { handleModelSelect };
286
- }
287
- function useNodeExecution(nodeId) {
288
- const updateNodeData = chunkIHF35QZD_js.useWorkflowStore((state) => state.updateNodeData);
289
- const executeNode = chunkAXFOCPPP_js.useExecutionStore((state) => state.executeNode);
290
- const stopNodeExecution = chunkAXFOCPPP_js.useExecutionStore((state) => state.stopNodeExecution);
291
- const handleGenerate = react.useCallback(() => {
292
- updateNodeData(nodeId, { status: types.NodeStatusEnum.PROCESSING });
293
- executeNode(nodeId);
294
- }, [nodeId, executeNode, updateNodeData]);
295
- const handleStop = react.useCallback(() => {
296
- stopNodeExecution(nodeId);
297
- }, [nodeId, stopNodeExecution]);
298
- return { handleGenerate, handleStop };
299
- }
300
- function readFileAsBase64(file, nodeId, getMetadata, buildUploadUpdate, updateNodeData, onComplete) {
301
- const reader = new FileReader();
302
- reader.onload = async (event) => {
303
- const dataUrl = event.target?.result;
304
- const metadata = await getMetadata(dataUrl);
305
- updateNodeData(nodeId, buildUploadUpdate(dataUrl, file.name, metadata));
306
- };
307
- reader.readAsDataURL(file);
308
- }
309
- function useMediaUpload({
310
- nodeId,
311
- mediaType,
312
- initialUrl = "",
313
- getMetadata,
314
- buildUploadUpdate,
315
- buildUrlUpdate,
316
- buildRemoveUpdate
317
- }) {
318
- const updateNodeData = chunkIHF35QZD_js.useWorkflowStore((state) => state.updateNodeData);
319
- const workflowId = chunkIHF35QZD_js.useWorkflowStore((state) => state.workflowId);
320
- const { fileUpload } = chunkRJ262NXS_js.useWorkflowUIConfig();
321
- const fileInputRef = react.useRef(null);
322
- const [showUrlInput, setShowUrlInput] = react.useState(false);
323
- const [urlValue, setUrlValue] = react.useState(initialUrl);
324
- const [isUploading, setIsUploading] = react.useState(false);
325
- const getMetadataRef = react.useRef(getMetadata);
326
- getMetadataRef.current = getMetadata;
327
- const buildUploadUpdateRef = react.useRef(buildUploadUpdate);
328
- buildUploadUpdateRef.current = buildUploadUpdate;
329
- const buildUrlUpdateRef = react.useRef(buildUrlUpdate);
330
- buildUrlUpdateRef.current = buildUrlUpdate;
331
- const buildRemoveUpdateRef = react.useRef(buildRemoveUpdate);
332
- buildRemoveUpdateRef.current = buildRemoveUpdate;
333
- const handleFileSelect = react.useCallback(
334
- async (e) => {
335
- const file = e.target.files?.[0];
336
- if (!file) return;
337
- if (workflowId && fileUpload) {
338
- setIsUploading(true);
339
- try {
340
- const result = await fileUpload.uploadFile(
341
- `/files/workflows/${workflowId}/input/${mediaType}`,
342
- file
343
- );
344
- const metadata = await getMetadataRef.current(result.url);
345
- updateNodeData(
346
- nodeId,
347
- buildUploadUpdateRef.current(result.url, result.filename, metadata)
348
- );
349
- } catch (_error) {
350
- readFileAsBase64(
351
- file,
352
- nodeId,
353
- getMetadataRef.current,
354
- buildUploadUpdateRef.current,
355
- updateNodeData
356
- );
357
- } finally {
358
- setIsUploading(false);
359
- }
360
- } else {
361
- readFileAsBase64(
362
- file,
363
- nodeId,
364
- getMetadataRef.current,
365
- buildUploadUpdateRef.current,
366
- updateNodeData
367
- );
368
- }
369
- },
370
- [nodeId, updateNodeData, workflowId, mediaType, fileUpload]
371
- );
372
- const handleRemove = react.useCallback(() => {
373
- updateNodeData(nodeId, buildRemoveUpdateRef.current());
374
- setUrlValue("");
375
- }, [nodeId, updateNodeData]);
376
- const handleUrlSubmit = react.useCallback(async () => {
377
- if (!urlValue.trim()) return;
378
- try {
379
- let metadata;
380
- if (mediaType === "image") {
381
- metadata = await chunkEMUMKW5C_js.getImageDimensions(urlValue);
382
- } else {
383
- const meta = await chunkEMUMKW5C_js.getVideoMetadata(urlValue);
384
- metadata = {
385
- duration: meta.duration,
386
- width: meta.dimensions.width,
387
- height: meta.dimensions.height
388
- };
389
- }
390
- updateNodeData(nodeId, buildUrlUpdateRef.current(urlValue, metadata));
391
- } catch (_error) {
392
- updateNodeData(nodeId, buildUrlUpdateRef.current(urlValue, null));
393
- }
394
- setShowUrlInput(false);
395
- }, [nodeId, updateNodeData, urlValue, mediaType]);
396
- const handleUrlKeyDown = react.useCallback(
397
- (e) => {
398
- if (e.key === "Enter") {
399
- handleUrlSubmit();
400
- } else if (e.key === "Escape") {
401
- setShowUrlInput(false);
402
- setUrlValue(initialUrl);
403
- }
404
- },
405
- [handleUrlSubmit, initialUrl]
406
- );
407
- return {
408
- fileInputRef,
409
- showUrlInput,
410
- setShowUrlInput,
411
- urlValue,
412
- setUrlValue,
413
- isUploading,
414
- handleFileSelect,
415
- handleRemove,
416
- handleUrlSubmit,
417
- handleUrlKeyDown
418
- };
419
- }
420
- function usePromptAutocomplete({
421
- availableVariables,
422
- textareaRef,
423
- localTemplate,
424
- setLocalTemplate,
425
- onTemplateCommit
426
- }) {
427
- const [showAutocomplete, setShowAutocomplete] = react.useState(false);
428
- const [autocompletePosition, setAutocompletePosition] = react.useState({ top: 0, left: 0 });
429
- const [autocompleteFilter, setAutocompleteFilter] = react.useState("");
430
- const [selectedAutocompleteIndex, setSelectedAutocompleteIndex] = react.useState(0);
431
- const filteredAutocompleteVars = react.useMemo(() => {
432
- return availableVariables.filter(
433
- (v) => v.name.toLowerCase().includes(autocompleteFilter.toLowerCase())
434
- );
435
- }, [availableVariables, autocompleteFilter]);
436
- const handleAutocompleteSelect = react.useCallback(
437
- (varName) => {
438
- if (!textareaRef.current) return;
439
- const cursorPos = textareaRef.current.selectionStart;
440
- const textBeforeCursor = localTemplate.slice(0, cursorPos);
441
- const textAfterCursor = localTemplate.slice(cursorPos);
442
- const match = textBeforeCursor.match(/@(\w*)$/);
443
- if (!match) return;
444
- const atPosition = cursorPos - match[0].length;
445
- const newTemplate = `${localTemplate.slice(0, atPosition)}@${varName}${textAfterCursor}`;
446
- setLocalTemplate(newTemplate);
447
- onTemplateCommit?.(newTemplate);
448
- setShowAutocomplete(false);
449
- const newCursorPos = atPosition + varName.length + 1;
450
- setTimeout(() => {
451
- if (textareaRef.current) {
452
- textareaRef.current.focus();
453
- textareaRef.current.setSelectionRange(newCursorPos, newCursorPos);
454
- }
455
- }, 0);
456
- },
457
- [localTemplate, textareaRef, setLocalTemplate, onTemplateCommit]
458
- );
459
- const handleChange = react.useCallback(
460
- (e) => {
461
- const newValue = e.target.value;
462
- setLocalTemplate(newValue);
463
- const cursorPos = e.target.selectionStart;
464
- const textBeforeCursor = newValue.slice(0, cursorPos);
465
- const match = textBeforeCursor.match(/@(\w*)$/);
466
- if (match && textareaRef.current) {
467
- setAutocompleteFilter(match[1] || "");
468
- setSelectedAutocompleteIndex(0);
469
- const lineHeight = 20;
470
- const lines = textBeforeCursor.split("\n");
471
- const currentLine = lines.length - 1;
472
- const top = currentLine * lineHeight + 30;
473
- const left = 10;
474
- setAutocompletePosition({ top, left });
475
- setShowAutocomplete(true);
476
- } else {
477
- setShowAutocomplete(false);
478
- }
479
- },
480
- [textareaRef, setLocalTemplate]
481
- );
482
- const handleKeyDown = react.useCallback(
483
- (e) => {
484
- if (!showAutocomplete) return;
485
- if (e.key === "ArrowDown") {
486
- e.preventDefault();
487
- setSelectedAutocompleteIndex((prev) => (prev + 1) % filteredAutocompleteVars.length);
488
- } else if (e.key === "ArrowUp") {
489
- e.preventDefault();
490
- setSelectedAutocompleteIndex(
491
- (prev) => (prev - 1 + filteredAutocompleteVars.length) % filteredAutocompleteVars.length
492
- );
493
- } else if (e.key === "Enter" || e.key === "Tab") {
494
- if (filteredAutocompleteVars.length > 0) {
495
- e.preventDefault();
496
- handleAutocompleteSelect(filteredAutocompleteVars[selectedAutocompleteIndex].name);
497
- }
498
- } else if (e.key === "Escape") {
499
- e.preventDefault();
500
- e.stopPropagation();
501
- setShowAutocomplete(false);
502
- }
503
- },
504
- [
505
- showAutocomplete,
506
- filteredAutocompleteVars,
507
- selectedAutocompleteIndex,
508
- handleAutocompleteSelect
509
- ]
510
- );
511
- const closeAutocomplete = react.useCallback(() => {
512
- setShowAutocomplete(false);
513
- }, []);
514
- return {
515
- showAutocomplete,
516
- autocompletePosition,
517
- filteredAutocompleteVars,
518
- selectedAutocompleteIndex,
519
- handleChange,
520
- handleKeyDown,
521
- handleAutocompleteSelect,
522
- closeAutocomplete
523
- };
524
- }
525
-
526
- exports.useAIGenNode = useAIGenNode;
527
- exports.useAIGenNodeHeader = useAIGenNodeHeader;
528
- exports.useAutoLoadModelSchema = useAutoLoadModelSchema;
529
- exports.useCanGenerate = useCanGenerate;
530
- exports.useMediaUpload = useMediaUpload;
531
- exports.useModelSelection = useModelSelection;
532
- exports.useNodeExecution = useNodeExecution;
533
- exports.usePromptAutocomplete = usePromptAutocomplete;
534
- exports.useRequiredInputs = useRequiredInputs;