@genfeedai/workflow-ui 0.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 (86) hide show
  1. package/dist/canvas.d.mts +27 -0
  2. package/dist/canvas.d.ts +27 -0
  3. package/dist/canvas.js +45 -0
  4. package/dist/canvas.mjs +16 -0
  5. package/dist/chunk-22PDGHNQ.mjs +737 -0
  6. package/dist/chunk-3SPPKCWR.js +458 -0
  7. package/dist/chunk-3YFFDHC5.js +300 -0
  8. package/dist/chunk-5HJFQVUR.js +61 -0
  9. package/dist/chunk-5LQ4QBR5.js +2 -0
  10. package/dist/chunk-6DOEUDD5.js +254 -0
  11. package/dist/chunk-7SKSRSS7.mjs +57 -0
  12. package/dist/chunk-AC6TWLRT.mjs +27 -0
  13. package/dist/chunk-ADWNF7V3.js +120 -0
  14. package/dist/chunk-BJ3R5R32.mjs +2163 -0
  15. package/dist/chunk-CETJJ73S.js +1555 -0
  16. package/dist/chunk-CSUBLSKZ.mjs +1002 -0
  17. package/dist/chunk-CV4M7CNU.mjs +251 -0
  18. package/dist/chunk-E323WAZG.mjs +272 -0
  19. package/dist/chunk-E544XUBL.js +378 -0
  20. package/dist/chunk-EC2ZIWOK.js +1007 -0
  21. package/dist/chunk-EFXQT23N.mjs +99 -0
  22. package/dist/chunk-EMUMKW5C.js +107 -0
  23. package/dist/chunk-FOMOOERN.js +2 -0
  24. package/dist/chunk-FT33LFII.mjs +21 -0
  25. package/dist/chunk-FT64PCUP.mjs +533 -0
  26. package/dist/chunk-H6LZKSLY.js +5678 -0
  27. package/dist/chunk-HPQT36RR.js +543 -0
  28. package/dist/chunk-JLWKW3G5.js +2 -0
  29. package/dist/chunk-L5TF4EHW.mjs +1 -0
  30. package/dist/chunk-LAJ34AH2.mjs +374 -0
  31. package/dist/chunk-LDN7IX4Y.mjs +1 -0
  32. package/dist/chunk-MLJJBBTB.mjs +1 -0
  33. package/dist/chunk-NSDLGLAQ.js +2166 -0
  34. package/dist/chunk-RJ262NXS.js +24 -0
  35. package/dist/chunk-RXNEDWK2.js +141 -0
  36. package/dist/chunk-SW7QNEZU.js +744 -0
  37. package/dist/chunk-UQQUWGHW.mjs +118 -0
  38. package/dist/chunk-VOGL2WCE.mjs +1542 -0
  39. package/dist/chunk-VRN3UWE5.mjs +138 -0
  40. package/dist/chunk-XV5Z5XYR.mjs +5640 -0
  41. package/dist/chunk-Z7PWFZG5.js +30 -0
  42. package/dist/chunk-ZJD5WMR3.mjs +418 -0
  43. package/dist/hooks.d.mts +255 -0
  44. package/dist/hooks.d.ts +255 -0
  45. package/dist/hooks.js +56 -0
  46. package/dist/hooks.mjs +11 -0
  47. package/dist/index.d.mts +29 -0
  48. package/dist/index.d.ts +29 -0
  49. package/dist/index.js +180 -0
  50. package/dist/index.mjs +19 -0
  51. package/dist/lib.d.mts +164 -0
  52. package/dist/lib.d.ts +164 -0
  53. package/dist/lib.js +144 -0
  54. package/dist/lib.mjs +3 -0
  55. package/dist/nodes.d.mts +128 -0
  56. package/dist/nodes.d.ts +128 -0
  57. package/dist/nodes.js +151 -0
  58. package/dist/nodes.mjs +14 -0
  59. package/dist/panels.d.mts +22 -0
  60. package/dist/panels.d.ts +22 -0
  61. package/dist/panels.js +21 -0
  62. package/dist/panels.mjs +4 -0
  63. package/dist/promptLibraryStore-BZnfmEkc.d.ts +464 -0
  64. package/dist/promptLibraryStore-zqb59nsu.d.mts +464 -0
  65. package/dist/provider.d.mts +29 -0
  66. package/dist/provider.d.ts +29 -0
  67. package/dist/provider.js +17 -0
  68. package/dist/provider.mjs +4 -0
  69. package/dist/stores.d.mts +96 -0
  70. package/dist/stores.d.ts +96 -0
  71. package/dist/stores.js +113 -0
  72. package/dist/stores.mjs +43 -0
  73. package/dist/toolbar.d.mts +73 -0
  74. package/dist/toolbar.d.ts +73 -0
  75. package/dist/toolbar.js +34 -0
  76. package/dist/toolbar.mjs +5 -0
  77. package/dist/types-ipAnBzAJ.d.mts +46 -0
  78. package/dist/types-ipAnBzAJ.d.ts +46 -0
  79. package/dist/ui.d.mts +67 -0
  80. package/dist/ui.d.ts +67 -0
  81. package/dist/ui.js +84 -0
  82. package/dist/ui.mjs +3 -0
  83. package/dist/workflowStore-4EGKJLYK.mjs +3 -0
  84. package/dist/workflowStore-KM32FDL7.js +12 -0
  85. package/package.json +117 -0
  86. package/src/styles/workflow-ui.css +186 -0
@@ -0,0 +1,543 @@
1
+ 'use strict';
2
+
3
+ var chunk5HJFQVUR_js = require('./chunk-5HJFQVUR.js');
4
+ var chunkEMUMKW5C_js = require('./chunk-EMUMKW5C.js');
5
+ var chunkEC2ZIWOK_js = require('./chunk-EC2ZIWOK.js');
6
+ var chunkNSDLGLAQ_js = require('./chunk-NSDLGLAQ.js');
7
+ var chunkRJ262NXS_js = require('./chunk-RJ262NXS.js');
8
+ var chunkZ7PWFZG5_js = require('./chunk-Z7PWFZG5.js');
9
+ var react = require('react');
10
+ var lucideReact = require('lucide-react');
11
+ var jsxRuntime = require('react/jsx-runtime');
12
+ var shallow = require('zustand/react/shallow');
13
+
14
+ function useAIGenNode({
15
+ nodeId,
16
+ selectedModel,
17
+ schemaParams
18
+ }) {
19
+ const updateNodeData = chunkNSDLGLAQ_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 = chunkNSDLGLAQ_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
+
140
+ // src/hooks/useRequiredInputs.ts
141
+ var import_types = chunkZ7PWFZG5_js.__toESM(chunkNSDLGLAQ_js.require_dist());
142
+ function useRequiredInputs(nodeId, nodeType) {
143
+ const edges = chunkNSDLGLAQ_js.useWorkflowStore((state) => state.edges);
144
+ return react.useMemo(() => {
145
+ const nodeDef = import_types.NODE_DEFINITIONS[nodeType];
146
+ if (!nodeDef) {
147
+ return { hasRequiredInputs: true, missingInputs: [], connectionStatus: /* @__PURE__ */ new Map() };
148
+ }
149
+ const incomingEdges = edges.filter((e) => e.target === nodeId);
150
+ const connectedHandles = new Set(incomingEdges.map((e) => e.targetHandle).filter(Boolean));
151
+ const connectionStatus = /* @__PURE__ */ new Map();
152
+ const missingInputs = [];
153
+ for (const input of nodeDef.inputs) {
154
+ const isConnected = connectedHandles.has(input.id);
155
+ connectionStatus.set(input.id, isConnected);
156
+ if (input.required && !isConnected) {
157
+ missingInputs.push(input.id);
158
+ }
159
+ }
160
+ return {
161
+ hasRequiredInputs: missingInputs.length === 0,
162
+ missingInputs,
163
+ connectionStatus
164
+ };
165
+ }, [nodeId, nodeType, edges]);
166
+ }
167
+
168
+ // src/hooks/useCanGenerate.ts
169
+ var import_types2 = chunkZ7PWFZG5_js.__toESM(chunkNSDLGLAQ_js.require_dist());
170
+ function extractOutputValue(node, handleType) {
171
+ const data = node.data;
172
+ if (handleType === "text") {
173
+ return data.outputText ?? data.prompt;
174
+ } else if (handleType === "image") {
175
+ return data.outputImage ?? data.image;
176
+ } else if (handleType === "video") {
177
+ return data.outputVideo ?? data.video;
178
+ } else if (handleType === "audio") {
179
+ return data.outputAudio ?? data.audio;
180
+ }
181
+ return void 0;
182
+ }
183
+ function useCanGenerate({
184
+ nodeId,
185
+ nodeType,
186
+ inputSchema,
187
+ schemaParams
188
+ }) {
189
+ const { hasRequiredInputs, missingInputs } = useRequiredInputs(nodeId, nodeType);
190
+ const getConnectedInputs = chunkNSDLGLAQ_js.useWorkflowStore((state) => state.getConnectedInputs);
191
+ const incomingEdgesSelector = react.useCallback(
192
+ (state) => state.edges.filter((e) => e.target === nodeId),
193
+ [nodeId]
194
+ );
195
+ const incomingEdges = chunkNSDLGLAQ_js.useWorkflowStore(shallow.useShallow(incomingEdgesSelector));
196
+ const connectedOutputsSelector = react.useCallback(
197
+ (state) => {
198
+ const outputs = {};
199
+ for (const edge of incomingEdges) {
200
+ const sourceNode = state.nodes.find((n) => n.id === edge.source);
201
+ if (sourceNode) {
202
+ outputs[edge.source] = extractOutputValue(sourceNode, edge.sourceHandle);
203
+ }
204
+ }
205
+ return outputs;
206
+ },
207
+ [incomingEdges]
208
+ );
209
+ chunkNSDLGLAQ_js.useWorkflowStore(shallow.useShallow(connectedOutputsSelector));
210
+ return react.useMemo(() => {
211
+ const missingItems = [];
212
+ for (const inputId of missingInputs) {
213
+ missingItems.push({
214
+ type: "connection",
215
+ field: inputId,
216
+ message: `Missing connection: ${inputId}`
217
+ });
218
+ }
219
+ const connectedInputs = getConnectedInputs(nodeId);
220
+ const nodeDef = import_types2.NODE_DEFINITIONS[nodeType];
221
+ const requiredHandleIds = new Set(
222
+ nodeDef?.inputs.filter((h) => h.required).map((h) => h.id) ?? []
223
+ );
224
+ let hasRequiredData = true;
225
+ let hasConnectedData = true;
226
+ if (hasRequiredInputs) {
227
+ for (const edge of incomingEdges) {
228
+ const handleId = edge.targetHandle;
229
+ if (!handleId) continue;
230
+ if (!connectedInputs.has(handleId)) {
231
+ hasConnectedData = false;
232
+ if (requiredHandleIds.has(handleId)) {
233
+ hasRequiredData = false;
234
+ }
235
+ }
236
+ }
237
+ }
238
+ const schemaValidation = chunkEMUMKW5C_js.validateRequiredSchemaFields(
239
+ inputSchema,
240
+ schemaParams ?? {},
241
+ chunkEMUMKW5C_js.CONNECTION_FIELDS
242
+ );
243
+ for (const field of schemaValidation.missingFields) {
244
+ missingItems.push({
245
+ type: "schema",
246
+ field,
247
+ message: `Required field: ${field}`
248
+ });
249
+ }
250
+ const canGenerate = hasRequiredInputs && hasRequiredData && schemaValidation.isValid;
251
+ return {
252
+ canGenerate,
253
+ missingItems,
254
+ hasRequiredConnections: hasRequiredInputs,
255
+ hasConnectedData,
256
+ hasRequiredSchemaFields: schemaValidation.isValid
257
+ };
258
+ }, [
259
+ nodeId,
260
+ nodeType,
261
+ hasRequiredInputs,
262
+ missingInputs,
263
+ inputSchema,
264
+ schemaParams,
265
+ getConnectedInputs,
266
+ incomingEdges
267
+ ]);
268
+ }
269
+ function useModelSelection({ nodeId, modelMap, fallbackModel }) {
270
+ const updateNodeData = chunkNSDLGLAQ_js.useWorkflowStore((state) => state.updateNodeData);
271
+ const handleModelSelect = react.useCallback(
272
+ (model) => {
273
+ const internalModel = modelMap[model.id] ?? fallbackModel;
274
+ const schemaDefaults = chunkEMUMKW5C_js.getSchemaDefaults(model.inputSchema);
275
+ const selectedModel = {
276
+ provider: model.provider,
277
+ modelId: model.id,
278
+ displayName: model.displayName,
279
+ inputSchema: model.inputSchema,
280
+ componentSchemas: model.componentSchemas
281
+ };
282
+ updateNodeData(nodeId, {
283
+ model: internalModel,
284
+ provider: model.provider,
285
+ selectedModel,
286
+ schemaParams: schemaDefaults
287
+ });
288
+ },
289
+ [nodeId, modelMap, fallbackModel, updateNodeData]
290
+ );
291
+ return { handleModelSelect };
292
+ }
293
+
294
+ // src/hooks/useNodeExecution.ts
295
+ var import_types3 = chunkZ7PWFZG5_js.__toESM(chunkNSDLGLAQ_js.require_dist());
296
+ function useNodeExecution(nodeId) {
297
+ const updateNodeData = chunkNSDLGLAQ_js.useWorkflowStore((state) => state.updateNodeData);
298
+ const executeNode = chunkEC2ZIWOK_js.useExecutionStore((state) => state.executeNode);
299
+ const stopNodeExecution = chunkEC2ZIWOK_js.useExecutionStore((state) => state.stopNodeExecution);
300
+ const handleGenerate = react.useCallback(() => {
301
+ updateNodeData(nodeId, { status: import_types3.NodeStatusEnum.PROCESSING });
302
+ executeNode(nodeId);
303
+ }, [nodeId, executeNode, updateNodeData]);
304
+ const handleStop = react.useCallback(() => {
305
+ stopNodeExecution(nodeId);
306
+ }, [nodeId, stopNodeExecution]);
307
+ return { handleGenerate, handleStop };
308
+ }
309
+ function readFileAsBase64(file, nodeId, getMetadata, buildUploadUpdate, updateNodeData, onComplete) {
310
+ const reader = new FileReader();
311
+ reader.onload = async (event) => {
312
+ const dataUrl = event.target?.result;
313
+ const metadata = await getMetadata(dataUrl);
314
+ updateNodeData(nodeId, buildUploadUpdate(dataUrl, file.name, metadata));
315
+ };
316
+ reader.readAsDataURL(file);
317
+ }
318
+ function useMediaUpload({
319
+ nodeId,
320
+ mediaType,
321
+ initialUrl = "",
322
+ getMetadata,
323
+ buildUploadUpdate,
324
+ buildUrlUpdate,
325
+ buildRemoveUpdate
326
+ }) {
327
+ const updateNodeData = chunkNSDLGLAQ_js.useWorkflowStore((state) => state.updateNodeData);
328
+ const workflowId = chunkNSDLGLAQ_js.useWorkflowStore((state) => state.workflowId);
329
+ const { fileUpload } = chunkRJ262NXS_js.useWorkflowUIConfig();
330
+ const fileInputRef = react.useRef(null);
331
+ const [showUrlInput, setShowUrlInput] = react.useState(false);
332
+ const [urlValue, setUrlValue] = react.useState(initialUrl);
333
+ const [isUploading, setIsUploading] = react.useState(false);
334
+ const getMetadataRef = react.useRef(getMetadata);
335
+ getMetadataRef.current = getMetadata;
336
+ const buildUploadUpdateRef = react.useRef(buildUploadUpdate);
337
+ buildUploadUpdateRef.current = buildUploadUpdate;
338
+ const buildUrlUpdateRef = react.useRef(buildUrlUpdate);
339
+ buildUrlUpdateRef.current = buildUrlUpdate;
340
+ const buildRemoveUpdateRef = react.useRef(buildRemoveUpdate);
341
+ buildRemoveUpdateRef.current = buildRemoveUpdate;
342
+ const handleFileSelect = react.useCallback(
343
+ async (e) => {
344
+ const file = e.target.files?.[0];
345
+ if (!file) return;
346
+ if (workflowId && fileUpload) {
347
+ setIsUploading(true);
348
+ try {
349
+ const result = await fileUpload.uploadFile(
350
+ `/files/workflows/${workflowId}/input/${mediaType}`,
351
+ file
352
+ );
353
+ const metadata = await getMetadataRef.current(result.url);
354
+ updateNodeData(
355
+ nodeId,
356
+ buildUploadUpdateRef.current(result.url, result.filename, metadata)
357
+ );
358
+ } catch (_error) {
359
+ readFileAsBase64(
360
+ file,
361
+ nodeId,
362
+ getMetadataRef.current,
363
+ buildUploadUpdateRef.current,
364
+ updateNodeData
365
+ );
366
+ } finally {
367
+ setIsUploading(false);
368
+ }
369
+ } else {
370
+ readFileAsBase64(
371
+ file,
372
+ nodeId,
373
+ getMetadataRef.current,
374
+ buildUploadUpdateRef.current,
375
+ updateNodeData
376
+ );
377
+ }
378
+ },
379
+ [nodeId, updateNodeData, workflowId, mediaType, fileUpload]
380
+ );
381
+ const handleRemove = react.useCallback(() => {
382
+ updateNodeData(nodeId, buildRemoveUpdateRef.current());
383
+ setUrlValue("");
384
+ }, [nodeId, updateNodeData]);
385
+ const handleUrlSubmit = react.useCallback(async () => {
386
+ if (!urlValue.trim()) return;
387
+ try {
388
+ let metadata;
389
+ if (mediaType === "image") {
390
+ metadata = await chunkEMUMKW5C_js.getImageDimensions(urlValue);
391
+ } else {
392
+ const meta = await chunkEMUMKW5C_js.getVideoMetadata(urlValue);
393
+ metadata = {
394
+ duration: meta.duration,
395
+ width: meta.dimensions.width,
396
+ height: meta.dimensions.height
397
+ };
398
+ }
399
+ updateNodeData(nodeId, buildUrlUpdateRef.current(urlValue, metadata));
400
+ } catch (_error) {
401
+ updateNodeData(nodeId, buildUrlUpdateRef.current(urlValue, null));
402
+ }
403
+ setShowUrlInput(false);
404
+ }, [nodeId, updateNodeData, urlValue, mediaType]);
405
+ const handleUrlKeyDown = react.useCallback(
406
+ (e) => {
407
+ if (e.key === "Enter") {
408
+ handleUrlSubmit();
409
+ } else if (e.key === "Escape") {
410
+ setShowUrlInput(false);
411
+ setUrlValue(initialUrl);
412
+ }
413
+ },
414
+ [handleUrlSubmit, initialUrl]
415
+ );
416
+ return {
417
+ fileInputRef,
418
+ showUrlInput,
419
+ setShowUrlInput,
420
+ urlValue,
421
+ setUrlValue,
422
+ isUploading,
423
+ handleFileSelect,
424
+ handleRemove,
425
+ handleUrlSubmit,
426
+ handleUrlKeyDown
427
+ };
428
+ }
429
+ function usePromptAutocomplete({
430
+ availableVariables,
431
+ textareaRef,
432
+ localTemplate,
433
+ setLocalTemplate,
434
+ onTemplateCommit
435
+ }) {
436
+ const [showAutocomplete, setShowAutocomplete] = react.useState(false);
437
+ const [autocompletePosition, setAutocompletePosition] = react.useState({ top: 0, left: 0 });
438
+ const [autocompleteFilter, setAutocompleteFilter] = react.useState("");
439
+ const [selectedAutocompleteIndex, setSelectedAutocompleteIndex] = react.useState(0);
440
+ const filteredAutocompleteVars = react.useMemo(() => {
441
+ return availableVariables.filter(
442
+ (v) => v.name.toLowerCase().includes(autocompleteFilter.toLowerCase())
443
+ );
444
+ }, [availableVariables, autocompleteFilter]);
445
+ const handleAutocompleteSelect = react.useCallback(
446
+ (varName) => {
447
+ if (!textareaRef.current) return;
448
+ const cursorPos = textareaRef.current.selectionStart;
449
+ const textBeforeCursor = localTemplate.slice(0, cursorPos);
450
+ const textAfterCursor = localTemplate.slice(cursorPos);
451
+ const match = textBeforeCursor.match(/@(\w*)$/);
452
+ if (!match) return;
453
+ const atPosition = cursorPos - match[0].length;
454
+ const newTemplate = `${localTemplate.slice(0, atPosition)}@${varName}${textAfterCursor}`;
455
+ setLocalTemplate(newTemplate);
456
+ onTemplateCommit?.(newTemplate);
457
+ setShowAutocomplete(false);
458
+ const newCursorPos = atPosition + varName.length + 1;
459
+ setTimeout(() => {
460
+ if (textareaRef.current) {
461
+ textareaRef.current.focus();
462
+ textareaRef.current.setSelectionRange(newCursorPos, newCursorPos);
463
+ }
464
+ }, 0);
465
+ },
466
+ [localTemplate, textareaRef, setLocalTemplate, onTemplateCommit]
467
+ );
468
+ const handleChange = react.useCallback(
469
+ (e) => {
470
+ const newValue = e.target.value;
471
+ setLocalTemplate(newValue);
472
+ const cursorPos = e.target.selectionStart;
473
+ const textBeforeCursor = newValue.slice(0, cursorPos);
474
+ const match = textBeforeCursor.match(/@(\w*)$/);
475
+ if (match && textareaRef.current) {
476
+ setAutocompleteFilter(match[1] || "");
477
+ setSelectedAutocompleteIndex(0);
478
+ const lineHeight = 20;
479
+ const lines = textBeforeCursor.split("\n");
480
+ const currentLine = lines.length - 1;
481
+ const top = currentLine * lineHeight + 30;
482
+ const left = 10;
483
+ setAutocompletePosition({ top, left });
484
+ setShowAutocomplete(true);
485
+ } else {
486
+ setShowAutocomplete(false);
487
+ }
488
+ },
489
+ [textareaRef, setLocalTemplate]
490
+ );
491
+ const handleKeyDown = react.useCallback(
492
+ (e) => {
493
+ if (!showAutocomplete) return;
494
+ if (e.key === "ArrowDown") {
495
+ e.preventDefault();
496
+ setSelectedAutocompleteIndex((prev) => (prev + 1) % filteredAutocompleteVars.length);
497
+ } else if (e.key === "ArrowUp") {
498
+ e.preventDefault();
499
+ setSelectedAutocompleteIndex(
500
+ (prev) => (prev - 1 + filteredAutocompleteVars.length) % filteredAutocompleteVars.length
501
+ );
502
+ } else if (e.key === "Enter" || e.key === "Tab") {
503
+ if (filteredAutocompleteVars.length > 0) {
504
+ e.preventDefault();
505
+ handleAutocompleteSelect(filteredAutocompleteVars[selectedAutocompleteIndex].name);
506
+ }
507
+ } else if (e.key === "Escape") {
508
+ e.preventDefault();
509
+ e.stopPropagation();
510
+ setShowAutocomplete(false);
511
+ }
512
+ },
513
+ [
514
+ showAutocomplete,
515
+ filteredAutocompleteVars,
516
+ selectedAutocompleteIndex,
517
+ handleAutocompleteSelect
518
+ ]
519
+ );
520
+ const closeAutocomplete = react.useCallback(() => {
521
+ setShowAutocomplete(false);
522
+ }, []);
523
+ return {
524
+ showAutocomplete,
525
+ autocompletePosition,
526
+ filteredAutocompleteVars,
527
+ selectedAutocompleteIndex,
528
+ handleChange,
529
+ handleKeyDown,
530
+ handleAutocompleteSelect,
531
+ closeAutocomplete
532
+ };
533
+ }
534
+
535
+ exports.useAIGenNode = useAIGenNode;
536
+ exports.useAIGenNodeHeader = useAIGenNodeHeader;
537
+ exports.useAutoLoadModelSchema = useAutoLoadModelSchema;
538
+ exports.useCanGenerate = useCanGenerate;
539
+ exports.useMediaUpload = useMediaUpload;
540
+ exports.useModelSelection = useModelSelection;
541
+ exports.useNodeExecution = useNodeExecution;
542
+ exports.usePromptAutocomplete = usePromptAutocomplete;
543
+ exports.useRequiredInputs = useRequiredInputs;
@@ -0,0 +1,2 @@
1
+ 'use strict';
2
+
@@ -0,0 +1 @@
1
+