@d34dman/flowdrop 0.0.46 → 0.0.47

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.
@@ -756,6 +756,8 @@
756
756
  <ConfigForm
757
757
  node={currentNode}
758
758
  workflowId={$workflowStore?.id}
759
+ workflowNodes={$workflowStore?.nodes}
760
+ workflowEdges={$workflowStore?.edges}
759
761
  onChange={async (updatedConfig, uiExtensions) => {
760
762
  // Sync config changes to workflow immediately on field blur
761
763
  if (selectedNodeId && currentNode) {
@@ -780,6 +782,10 @@
780
782
 
781
783
  workflowActions.updateNode(selectedNodeId, nodeUpdates);
782
784
 
785
+ // Update the local editor state to reflect config changes immediately
786
+ // This is needed for nodeType changes to take effect visually
787
+ workflowEditorRef.updateNodeData(selectedNodeId, updatedData);
788
+
783
789
  // Refresh edge positions in case config changes affect handles
784
790
  await workflowEditorRef.refreshEdgePositions(selectedNodeId);
785
791
  }
@@ -22,6 +22,7 @@
22
22
  import type {
23
23
  ConfigSchema,
24
24
  WorkflowNode,
25
+ WorkflowEdge,
25
26
  NodeUIExtensions,
26
27
  ConfigEditOptions
27
28
  } from '../types/index.js';
@@ -35,6 +36,7 @@
35
36
  type DynamicSchemaResult
36
37
  } from '../services/dynamicSchemaService.js';
37
38
  import { globalSaveWorkflow } from '../services/globalSave.js';
39
+ import { getAvailableVariables } from '../services/variableService.js';
38
40
 
39
41
  interface Props {
40
42
  /** Optional workflow node (if provided, schema and values are derived from it) */
@@ -49,6 +51,16 @@
49
51
  workflowId?: string;
50
52
  /** Whether to also save the workflow when saving config */
51
53
  saveWorkflowWhenSavingConfig?: boolean;
54
+ /**
55
+ * All workflow nodes (used for deriving template variables from connected nodes).
56
+ * When provided along with workflowEdges, enables autocomplete for template fields.
57
+ */
58
+ workflowNodes?: WorkflowNode[];
59
+ /**
60
+ * All workflow edges (used for finding connections to derive template variables).
61
+ * When provided along with workflowNodes, enables autocomplete for template fields.
62
+ */
63
+ workflowEdges?: WorkflowEdge[];
52
64
  /** Callback when any field value changes (fired on blur for immediate sync) */
53
65
  onChange?: (config: Record<string, unknown>, uiExtensions?: NodeUIExtensions) => void;
54
66
  /** Callback when form is saved (includes both config and extensions if enabled) */
@@ -64,6 +76,8 @@
64
76
  showUIExtensions = true,
65
77
  workflowId,
66
78
  saveWorkflowWhenSavingConfig = false,
79
+ workflowNodes = [],
80
+ workflowEdges = [],
67
81
  onChange,
68
82
  onSave,
69
83
  onCancel
@@ -364,10 +378,46 @@
364
378
  }
365
379
 
366
380
  /**
367
- * Convert ConfigProperty to FieldSchema for FormField component
381
+ * Convert ConfigProperty to FieldSchema for FormField component.
382
+ * Processes template fields to inject computed variable schema.
383
+ *
384
+ * For template fields, the `variables` config controls which input ports
385
+ * provide variables for autocomplete.
368
386
  */
369
387
  function toFieldSchema(property: Record<string, unknown>): FieldSchema {
370
- return property as FieldSchema;
388
+ const fieldSchema = property as FieldSchema;
389
+
390
+ // Process template fields to compute variable schema
391
+ if (fieldSchema.format === 'template' && node && workflowNodes.length > 0 && workflowEdges.length > 0) {
392
+ // Get the variables config (may be undefined or partially defined)
393
+ const variablesConfig = fieldSchema.variables;
394
+
395
+ // Compute the variable schema with optional port filtering and port name prefixing
396
+ const computedSchema = getAvailableVariables(node, workflowNodes, workflowEdges, {
397
+ targetPortIds: variablesConfig?.ports,
398
+ includePortName: variablesConfig?.includePortName
399
+ });
400
+
401
+ // Merge computed schema with any pre-defined schema
402
+ const mergedSchema = variablesConfig?.schema
403
+ ? {
404
+ variables: {
405
+ ...computedSchema.variables,
406
+ ...variablesConfig.schema.variables
407
+ }
408
+ }
409
+ : computedSchema;
410
+
411
+ return {
412
+ ...fieldSchema,
413
+ variables: {
414
+ ...variablesConfig,
415
+ schema: mergedSchema
416
+ }
417
+ } as FieldSchema;
418
+ }
419
+
420
+ return fieldSchema;
371
421
  }
372
422
  </script>
373
423
 
@@ -1,4 +1,4 @@
1
- import type { ConfigSchema, WorkflowNode, NodeUIExtensions } from '../types/index.js';
1
+ import type { ConfigSchema, WorkflowNode, WorkflowEdge, NodeUIExtensions } from '../types/index.js';
2
2
  interface Props {
3
3
  /** Optional workflow node (if provided, schema and values are derived from it) */
4
4
  node?: WorkflowNode;
@@ -12,6 +12,16 @@ interface Props {
12
12
  workflowId?: string;
13
13
  /** Whether to also save the workflow when saving config */
14
14
  saveWorkflowWhenSavingConfig?: boolean;
15
+ /**
16
+ * All workflow nodes (used for deriving template variables from connected nodes).
17
+ * When provided along with workflowEdges, enables autocomplete for template fields.
18
+ */
19
+ workflowNodes?: WorkflowNode[];
20
+ /**
21
+ * All workflow edges (used for finding connections to derive template variables).
22
+ * When provided along with workflowNodes, enables autocomplete for template fields.
23
+ */
24
+ workflowEdges?: WorkflowEdge[];
15
25
  /** Callback when any field value changes (fired on blur for immediate sync) */
16
26
  onChange?: (config: Record<string, unknown>, uiExtensions?: NodeUIExtensions) => void;
17
27
  /** Callback when form is saved (includes both config and extensions if enabled) */
@@ -89,8 +89,11 @@
89
89
  type: 'string',
90
90
  title: 'Theme Preference',
91
91
  description: 'Choose your preferred color scheme',
92
- enum: ['light', 'dark', 'auto'],
93
- enumLabels: ['Light', 'Dark', 'Auto (System)'],
92
+ oneOf: [
93
+ { const: 'light', title: 'Light' },
94
+ { const: 'dark', title: 'Dark' },
95
+ { const: 'auto', title: 'Auto (System)' }
96
+ ],
94
97
  default: 'auto'
95
98
  }
96
99
  }
@@ -515,6 +515,32 @@
515
515
  */
516
516
  let nodeIdToRefresh = $state<string | null>(null);
517
517
 
518
+ /**
519
+ * Update a node's data in the local editor state.
520
+ * This should be called after updating the node in the global store to ensure
521
+ * the visual representation is updated immediately (e.g., for nodeType changes).
522
+ *
523
+ * @param nodeId - The ID of the node to update
524
+ * @param dataUpdates - Partial data updates to merge into the node's data
525
+ */
526
+ export function updateNodeData(
527
+ nodeId: string,
528
+ dataUpdates: Partial<WorkflowNodeType['data']>
529
+ ): void {
530
+ flowNodes = flowNodes.map((node) => {
531
+ if (node.id === nodeId) {
532
+ return {
533
+ ...node,
534
+ data: {
535
+ ...node.data,
536
+ ...dataUpdates
537
+ }
538
+ };
539
+ }
540
+ return node;
541
+ });
542
+ }
543
+
518
544
  /**
519
545
  * Force edge position recalculation after node config changes
520
546
  * This should be called after saving gateway/switch node configs where branches are reordered
@@ -16,6 +16,7 @@ interface Props {
16
16
  pipelineId?: string;
17
17
  }
18
18
  declare const WorkflowEditor: import("svelte").Component<Props, {
19
+ updateNodeData: (nodeId: string, dataUpdates: Partial<WorkflowNodeType["data"]>) => void;
19
20
  refreshEdgePositions: (nodeId: string) => Promise<void>;
20
21
  }, "">;
21
22
  type WorkflowEditor = ReturnType<typeof WorkflowEditor>;
@@ -17,12 +17,12 @@
17
17
  5. format: 'template' -> FormTemplateEditor (CodeMirror with Twig/Liquid syntax)
18
18
  6. enum with multiple: true -> FormCheckboxGroup
19
19
  7. enum -> FormSelect (simple values without labels)
20
- 8. format: 'multiline' -> FormTextarea
21
- 9. format: 'range' (number/integer) -> FormRangeField
22
- 10. type: 'string' -> FormTextField
23
- 11. type: 'number' or 'integer' -> FormNumberField
24
- 12. type: 'boolean' -> FormToggle
25
- 13. oneOf with const/title (labeled options) -> FormSelect
20
+ 8. oneOf with const/title (labeled options) -> FormSelect
21
+ 9. format: 'multiline' -> FormTextarea
22
+ 10. format: 'range' (number/integer) -> FormRangeField
23
+ 11. type: 'string' -> FormTextField
24
+ 12. type: 'number' or 'integer' -> FormNumberField
25
+ 13. type: 'boolean' -> FormToggle
26
26
  14. type: 'object' (without format) -> FormCodeEditor (for JSON objects)
27
27
  15. fallback -> FormTextField
28
28
  -->
@@ -122,6 +122,12 @@
122
122
  return 'select-enum';
123
123
  }
124
124
 
125
+ // oneOf with labeled options (standard JSON Schema) or legacy options -> select
126
+ // Must be checked before basic type checks since oneOf schemas often have type: 'string'
127
+ if ((schema.oneOf && schema.oneOf.length > 0) || schema.options) {
128
+ return 'select-options';
129
+ }
130
+
125
131
  // Multiline string -> textarea
126
132
  if (schema.type === 'string' && schema.format === 'multiline') {
127
133
  return 'textarea';
@@ -147,11 +153,6 @@
147
153
  return 'toggle';
148
154
  }
149
155
 
150
- // oneOf with labeled options (standard JSON Schema) or legacy options -> select
151
- if ((schema.oneOf && schema.oneOf.length > 0) || schema.options) {
152
- return 'select-options';
153
- }
154
-
155
156
  // Future: Array type support
156
157
  if (schema.type === 'array') {
157
158
  return 'array';
@@ -350,6 +351,7 @@
350
351
  {required}
351
352
  height={(schema.height as string | undefined) ?? '250px'}
352
353
  darkTheme={(schema.darkTheme as boolean | undefined) ?? false}
354
+ variables={schema.variables}
353
355
  variableHints={(schema.variableHints as string[] | undefined) ?? []}
354
356
  placeholderExample={(schema.placeholderExample as string | undefined) ??
355
357
  'Hello {{ name }}, your order #{{ order_id }} is ready!'}
@@ -22,12 +22,12 @@
22
22
  2. format: 'hidden' -> skip rendering (return nothing)
23
23
  3. enum with multiple: true -> FormCheckboxGroup
24
24
  4. enum -> FormSelect (simple values without labels)
25
- 5. format: 'multiline' -> FormTextarea
26
- 6. format: 'range' (number/integer) -> FormRangeField
27
- 7. type: 'string' -> FormTextField
28
- 8. type: 'number' or 'integer' -> FormNumberField
29
- 9. type: 'boolean' -> FormToggle
30
- 10. oneOf with const/title (labeled options) -> FormSelect
25
+ 5. oneOf with const/title (labeled options) -> FormSelect
26
+ 6. format: 'multiline' -> FormTextarea
27
+ 7. format: 'range' (number/integer) -> FormRangeField
28
+ 8. type: 'string' -> FormTextField
29
+ 9. type: 'number' or 'integer' -> FormNumberField
30
+ 10. type: 'boolean' -> FormToggle
31
31
  11. type: 'array' -> FormArray
32
32
  12. fallback -> FormTextField
33
33
  -->
@@ -43,6 +43,7 @@
43
43
  import FormCheckboxGroup from './FormCheckboxGroup.svelte';
44
44
  import FormArray from './FormArray.svelte';
45
45
  import { resolveFieldComponent } from '../../form/fieldRegistry.js';
46
+ import { resolvedTheme } from '../../stores/settingsStore.js';
46
47
  import type { FieldSchema } from './types.js';
47
48
  import { getSchemaOptions } from './types.js';
48
49
 
@@ -127,6 +128,12 @@
127
128
  return 'select-enum';
128
129
  }
129
130
 
131
+ // oneOf with labeled options (standard JSON Schema) or legacy options -> select
132
+ // Must be checked before basic type checks since oneOf schemas often have type: 'string'
133
+ if ((schema.oneOf && schema.oneOf.length > 0) || schema.options) {
134
+ return 'select-options';
135
+ }
136
+
130
137
  // Multiline string -> textarea
131
138
  if (schema.type === 'string' && schema.format === 'multiline') {
132
139
  return 'textarea';
@@ -152,11 +159,6 @@
152
159
  return 'toggle';
153
160
  }
154
161
 
155
- // oneOf with labeled options (standard JSON Schema) or legacy options -> select
156
- if ((schema.oneOf && schema.oneOf.length > 0) || schema.options) {
157
- return 'select-options';
158
- }
159
-
160
162
  // Array type
161
163
  if (schema.type === 'array') {
162
164
  return 'array';
@@ -226,6 +228,7 @@
226
228
  >
227
229
  {#if fieldType === 'registered' && registeredComponent}
228
230
  <!-- Render registered custom component -->
231
+ <!-- darkTheme: use schema value if explicitly set, otherwise derive from resolved theme -->
229
232
  <registeredComponent.component
230
233
  id={fieldKey}
231
234
  {value}
@@ -233,11 +236,12 @@
233
236
  {required}
234
237
  ariaDescribedBy={descriptionId}
235
238
  height={schema.height as string | undefined}
236
- darkTheme={schema.darkTheme as boolean | undefined}
239
+ darkTheme={schema.darkTheme ?? $resolvedTheme === 'dark'}
237
240
  autoFormat={schema.autoFormat as boolean | undefined}
238
241
  showToolbar={schema.showToolbar as boolean | undefined}
239
242
  showStatusBar={schema.showStatusBar as boolean | undefined}
240
243
  spellChecker={schema.spellChecker as boolean | undefined}
244
+ variables={schema.variables}
241
245
  variableHints={schema.variableHints as string[] | undefined}
242
246
  placeholderExample={schema.placeholderExample as string | undefined}
243
247
  onChange={(val: unknown) => onChange(val)}
@@ -4,10 +4,13 @@
4
4
 
5
5
  Features:
6
6
  - Custom syntax highlighting for {{ variable }} placeholders
7
+ - Inline autocomplete for template variables (triggered on {{ and .)
8
+ - Support for nested object drilling (user.address.city)
9
+ - Support for array index access (items[0].name)
7
10
  - Dark/light theme support
8
11
  - Consistent styling with other form components
9
12
  - Line wrapping for better template readability
10
- - Optional variable hints display
13
+ - Optional variable hints display (clickable buttons)
11
14
  - Proper ARIA attributes for accessibility
12
15
 
13
16
  Usage:
@@ -34,6 +37,11 @@
34
37
  import { history, historyKeymap, defaultKeymap, indentWithTab } from '@codemirror/commands';
35
38
  import { syntaxHighlighting, defaultHighlightStyle, indentOnInput } from '@codemirror/language';
36
39
  import { oneDark } from '@codemirror/theme-one-dark';
40
+ import type { VariableSchema, TemplateVariablesConfig } from '../../types/index.js';
41
+ import {
42
+ createTemplateAutocomplete,
43
+ createSimpleTemplateAutocomplete
44
+ } from './templateAutocomplete.js';
37
45
 
38
46
  interface Props {
39
47
  /** Field identifier */
@@ -48,7 +56,22 @@
48
56
  darkTheme?: boolean;
49
57
  /** Editor height in pixels or CSS value */
50
58
  height?: string;
51
- /** Available variable names for hints (optional) */
59
+ /**
60
+ * Configuration for template variable autocomplete.
61
+ * Controls which variables are available and how they are displayed.
62
+ */
63
+ variables?: TemplateVariablesConfig;
64
+ /**
65
+ * Variable schema for advanced autocomplete with nested drilling.
66
+ * When provided, enables dot notation (user.name) and array access (items[0]).
67
+ * @deprecated Use `variables.schema` instead
68
+ */
69
+ variableSchema?: VariableSchema;
70
+ /**
71
+ * Simple variable names for basic hints (backward compatible).
72
+ * Used when variableSchema is not provided.
73
+ * @deprecated Use `variables.schema` instead
74
+ */
52
75
  variableHints?: string[];
53
76
  /** Placeholder variable example for the hint */
54
77
  placeholderExample?: string;
@@ -67,6 +90,8 @@
67
90
  required = false,
68
91
  darkTheme = false,
69
92
  height = '250px',
93
+ variables,
94
+ variableSchema,
70
95
  variableHints = [],
71
96
  placeholderExample = 'Hello {{ name }}, your order #{{ order_id }} is ready!',
72
97
  disabled = false,
@@ -74,6 +99,37 @@
74
99
  onChange
75
100
  }: Props = $props();
76
101
 
102
+ /**
103
+ * Get the effective variable schema.
104
+ * Prefers variables.schema, falls back to deprecated variableSchema prop.
105
+ */
106
+ const effectiveVariableSchema = $derived.by<VariableSchema | undefined>(() => {
107
+ if (variables?.schema && Object.keys(variables.schema.variables).length > 0) {
108
+ return variables.schema;
109
+ }
110
+ if (variableSchema && Object.keys(variableSchema.variables).length > 0) {
111
+ return variableSchema;
112
+ }
113
+ return undefined;
114
+ });
115
+
116
+ /**
117
+ * Whether to show the variable hints section.
118
+ * Controlled by variables.showHints (defaults to true).
119
+ */
120
+ const showHints = $derived(variables?.showHints !== false);
121
+
122
+ /**
123
+ * Derive the list of top-level variable names for the hints display.
124
+ * Prefers effectiveVariableSchema if available, falls back to variableHints.
125
+ */
126
+ const displayVariables = $derived.by(() => {
127
+ if (effectiveVariableSchema) {
128
+ return Object.keys(effectiveVariableSchema.variables);
129
+ }
130
+ return variableHints;
131
+ });
132
+
77
133
  /** Reference to the container element */
78
134
  let containerRef: HTMLDivElement | undefined = $state(undefined);
79
135
 
@@ -86,10 +142,15 @@
86
142
  /**
87
143
  * Create a MatchDecorator for {{ variable }} patterns
88
144
  * This highlights the entire {{ variable }} expression
145
+ * Supports:
146
+ * - Simple variables: {{ name }}
147
+ * - Dot notation: {{ user.name }}, {{ user.address.city }}
148
+ * - Array access: {{ items[0] }}, {{ items[0].name }}
149
+ * - Mixed: {{ orders[0].items[1].price }}
89
150
  */
90
151
  const variableMatcher = new MatchDecorator({
91
- // Match {{ variable_name }} patterns (with optional whitespace)
92
- regexp: /\{\{\s*[\w.]+\s*\}\}/g,
152
+ // Match {{ variable_name }} patterns with dot notation and array indices
153
+ regexp: /\{\{\s*[\w]+(?:\.[\w]+|\[\d+\]|\[\*\])*\s*\}\}/g,
93
154
  decoration: Decoration.mark({ class: 'cm-template-variable' })
94
155
  });
95
156
 
@@ -125,7 +186,7 @@
125
186
 
126
187
  /**
127
188
  * Create editor extensions array for template editing
128
- * Uses minimal setup for better performance (no auto-closing brackets, no autocompletion)
189
+ * Includes autocomplete when variables are available
129
190
  * When disabled is true, adds readOnly/editable so the editor cannot be modified
130
191
  */
131
192
  function createExtensions() {
@@ -158,7 +219,7 @@
158
219
  // Update listener (only fires on user edit when not disabled)
159
220
  EditorView.updateListener.of(handleUpdate),
160
221
 
161
- // Custom theme
222
+ // Custom theme with autocomplete styling
162
223
  EditorView.theme({
163
224
  '&': {
164
225
  height: height,
@@ -185,20 +246,73 @@
185
246
  borderRadius: '3px',
186
247
  padding: '1px 2px',
187
248
  fontWeight: '500'
249
+ },
250
+ // Autocomplete dropdown styling
251
+ '.cm-tooltip.cm-tooltip-autocomplete': {
252
+ backgroundColor: 'var(--fd-background, #ffffff)',
253
+ border: '1px solid var(--fd-border, #e5e7eb)',
254
+ borderRadius: 'var(--fd-radius-lg, 0.5rem)',
255
+ boxShadow: 'var(--fd-shadow-lg, 0 10px 15px -3px rgba(0, 0, 0, 0.1))',
256
+ padding: '0.25rem',
257
+ maxHeight: '200px',
258
+ overflow: 'auto'
259
+ },
260
+ '.cm-tooltip.cm-tooltip-autocomplete > ul': {
261
+ fontFamily: "'JetBrains Mono', 'Fira Code', 'Monaco', 'Menlo', monospace",
262
+ fontSize: '0.8125rem'
263
+ },
264
+ '.cm-tooltip.cm-tooltip-autocomplete > ul > li': {
265
+ padding: '0.375rem 0.625rem',
266
+ borderRadius: 'var(--fd-radius-md, 0.375rem)',
267
+ display: 'flex',
268
+ alignItems: 'center',
269
+ gap: '0.5rem'
270
+ },
271
+ '.cm-tooltip.cm-tooltip-autocomplete > ul > li[aria-selected]': {
272
+ backgroundColor: 'var(--fd-accent-muted, rgba(168, 85, 247, 0.1))',
273
+ color: 'var(--fd-accent-hover, #7c3aed)'
274
+ },
275
+ '.cm-completionLabel': {
276
+ flex: '1'
277
+ },
278
+ '.cm-completionDetail': {
279
+ fontSize: '0.6875rem',
280
+ color: 'var(--fd-muted-foreground, #6b7280)',
281
+ opacity: '0.8'
188
282
  }
189
283
  }),
190
284
  EditorView.lineWrapping,
191
285
  EditorState.tabSize.of(2)
192
286
  ];
193
287
 
288
+ // Add autocomplete extension when variables are available (and not disabled)
289
+ if (!disabled) {
290
+ if (effectiveVariableSchema) {
291
+ // Use full autocomplete with nested drilling
292
+ extensions.push(createTemplateAutocomplete(effectiveVariableSchema));
293
+ } else if (variableHints.length > 0) {
294
+ // Fallback to simple autocomplete with just variable names
295
+ extensions.push(createSimpleTemplateAutocomplete(variableHints));
296
+ }
297
+ }
298
+
194
299
  if (darkTheme) {
195
300
  extensions.push(oneDark);
196
- // Add dark theme override for variable highlighting
301
+ // Add dark theme override for variable highlighting and autocomplete
197
302
  extensions.push(
198
303
  EditorView.theme({
199
304
  '.cm-template-variable': {
200
305
  color: '#c084fc',
201
306
  backgroundColor: 'rgba(192, 132, 252, 0.15)'
307
+ },
308
+ '.cm-tooltip.cm-tooltip-autocomplete': {
309
+ backgroundColor: '#1e1e1e',
310
+ border: '1px solid #3e4451',
311
+ boxShadow: '0 10px 15px -3px rgba(0, 0, 0, 0.3)'
312
+ },
313
+ '.cm-tooltip.cm-tooltip-autocomplete > ul > li[aria-selected]': {
314
+ backgroundColor: 'rgba(192, 132, 252, 0.2)',
315
+ color: '#c084fc'
202
316
  }
203
317
  })
204
318
  );
@@ -298,12 +412,12 @@
298
412
  aria-label="Template editor"
299
413
  ></div>
300
414
 
301
- <!-- Variable hints section (shown when variables are available) -->
302
- {#if variableHints.length > 0}
415
+ <!-- Variable hints section (shown when variables are available and showHints is true) -->
416
+ {#if showHints && displayVariables.length > 0}
303
417
  <div class="form-template-editor__hints">
304
418
  <span class="form-template-editor__hints-label">Available variables:</span>
305
419
  <div class="form-template-editor__hints-list">
306
- {#each variableHints as varName (varName)}
420
+ {#each displayVariables as varName (varName)}
307
421
  <button
308
422
  type="button"
309
423
  class="form-template-editor__hint-btn"
@@ -1,3 +1,4 @@
1
+ import type { VariableSchema, TemplateVariablesConfig } from '../../types/index.js';
1
2
  interface Props {
2
3
  /** Field identifier */
3
4
  id: string;
@@ -11,7 +12,22 @@ interface Props {
11
12
  darkTheme?: boolean;
12
13
  /** Editor height in pixels or CSS value */
13
14
  height?: string;
14
- /** Available variable names for hints (optional) */
15
+ /**
16
+ * Configuration for template variable autocomplete.
17
+ * Controls which variables are available and how they are displayed.
18
+ */
19
+ variables?: TemplateVariablesConfig;
20
+ /**
21
+ * Variable schema for advanced autocomplete with nested drilling.
22
+ * When provided, enables dot notation (user.name) and array access (items[0]).
23
+ * @deprecated Use `variables.schema` instead
24
+ */
25
+ variableSchema?: VariableSchema;
26
+ /**
27
+ * Simple variable names for basic hints (backward compatible).
28
+ * Used when variableSchema is not provided.
29
+ * @deprecated Use `variables.schema` instead
30
+ */
15
31
  variableHints?: string[];
16
32
  /** Placeholder variable example for the hint */
17
33
  placeholderExample?: string;
@@ -44,3 +44,4 @@ export { default as FormCodeEditor } from './FormCodeEditor.svelte';
44
44
  export { default as FormMarkdownEditor } from './FormMarkdownEditor.svelte';
45
45
  export { default as FormTemplateEditor } from './FormTemplateEditor.svelte';
46
46
  export { default as FormAutocomplete } from './FormAutocomplete.svelte';
47
+ export { createTemplateAutocomplete, createSimpleTemplateAutocomplete } from './templateAutocomplete.js';
@@ -48,3 +48,5 @@ export { default as FormCodeEditor } from './FormCodeEditor.svelte';
48
48
  export { default as FormMarkdownEditor } from './FormMarkdownEditor.svelte';
49
49
  export { default as FormTemplateEditor } from './FormTemplateEditor.svelte';
50
50
  export { default as FormAutocomplete } from './FormAutocomplete.svelte';
51
+ // Template autocomplete utilities
52
+ export { createTemplateAutocomplete, createSimpleTemplateAutocomplete } from './templateAutocomplete.js';
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Template Variable Autocomplete Extension for CodeMirror
3
+ * Provides autocomplete suggestions for {{ variable }} syntax in template editors.
4
+ *
5
+ * Features:
6
+ * - Triggers on `{{` to show top-level variables
7
+ * - Triggers on `.` to show child properties for objects
8
+ * - Triggers on `[` to show array index options
9
+ * - Supports deep nesting (e.g., `user.address.city`)
10
+ *
11
+ * @module components/form/templateAutocomplete
12
+ */
13
+ import type { Extension } from "@codemirror/state";
14
+ import type { VariableSchema } from "../../types/index.js";
15
+ /**
16
+ * Creates a CodeMirror extension for template variable autocomplete.
17
+ *
18
+ * @param schema - The variable schema containing available variables
19
+ * @returns A CodeMirror extension that provides autocomplete
20
+ *
21
+ * @example
22
+ * ```typescript
23
+ * const extensions = [
24
+ * // ... other extensions
25
+ * createTemplateAutocomplete(variableSchema)
26
+ * ];
27
+ * ```
28
+ */
29
+ export declare function createTemplateAutocomplete(schema: VariableSchema): Extension;
30
+ /**
31
+ * Creates a simple autocomplete extension that triggers when user types {{
32
+ * and shows top-level variables only (no drilling).
33
+ * Used as a fallback when full variable schema is not available.
34
+ *
35
+ * @param variableHints - Simple array of variable names
36
+ * @returns A CodeMirror extension that provides basic autocomplete
37
+ */
38
+ export declare function createSimpleTemplateAutocomplete(variableHints: string[]): Extension;