@d34dman/flowdrop 0.0.46 → 0.0.48

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 (34) hide show
  1. package/dist/components/App.svelte +10 -0
  2. package/dist/components/App.svelte.d.ts +2 -0
  3. package/dist/components/ConfigForm.svelte +72 -6
  4. package/dist/components/ConfigForm.svelte.d.ts +13 -1
  5. package/dist/components/SchemaForm.svelte +4 -2
  6. package/dist/components/SettingsPanel.svelte +5 -2
  7. package/dist/components/WorkflowEditor.svelte +26 -0
  8. package/dist/components/WorkflowEditor.svelte.d.ts +1 -0
  9. package/dist/components/form/FormAutocomplete.svelte +7 -4
  10. package/dist/components/form/FormField.svelte +42 -13
  11. package/dist/components/form/FormField.svelte.d.ts +11 -0
  12. package/dist/components/form/FormFieldLight.svelte +16 -13
  13. package/dist/components/form/FormTemplateEditor.svelte +343 -21
  14. package/dist/components/form/FormTemplateEditor.svelte.d.ts +22 -2
  15. package/dist/components/form/index.d.ts +1 -0
  16. package/dist/components/form/index.js +2 -0
  17. package/dist/components/form/templateAutocomplete.d.ts +29 -0
  18. package/dist/components/form/templateAutocomplete.js +253 -0
  19. package/dist/components/form/types.d.ts +29 -3
  20. package/dist/components/nodes/TerminalNode.svelte +27 -15
  21. package/dist/registry/nodeComponentRegistry.d.ts +9 -9
  22. package/dist/registry/nodeComponentRegistry.js +10 -10
  23. package/dist/services/apiVariableService.d.ts +116 -0
  24. package/dist/services/apiVariableService.js +338 -0
  25. package/dist/services/variableService.d.ts +141 -0
  26. package/dist/services/variableService.js +462 -0
  27. package/dist/svelte-app.d.ts +2 -0
  28. package/dist/svelte-app.js +2 -1
  29. package/dist/types/index.d.ts +257 -0
  30. package/dist/utils/handlePositioning.d.ts +31 -0
  31. package/dist/utils/handlePositioning.js +35 -0
  32. package/dist/utils/nodeTypes.d.ts +15 -10
  33. package/dist/utils/nodeTypes.js +24 -22
  34. package/package.json +7 -3
@@ -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:
@@ -30,10 +33,19 @@
30
33
  type ViewUpdate,
31
34
  MatchDecorator
32
35
  } from '@codemirror/view';
33
- import { EditorState } from '@codemirror/state';
36
+ import { EditorState, Compartment } from '@codemirror/state';
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 {
41
+ VariableSchema,
42
+ TemplateVariablesConfig,
43
+ WorkflowNode,
44
+ WorkflowEdge,
45
+ AuthProvider
46
+ } from '../../types/index.js';
47
+ import { createTemplateAutocomplete } from './templateAutocomplete.js';
48
+ import { getVariableSchema } from '../../services/variableService.js';
37
49
 
38
50
  interface Props {
39
51
  /** Field identifier */
@@ -48,8 +60,17 @@
48
60
  darkTheme?: boolean;
49
61
  /** Editor height in pixels or CSS value */
50
62
  height?: string;
51
- /** Available variable names for hints (optional) */
52
- variableHints?: string[];
63
+ /**
64
+ * Configuration for template variable autocomplete.
65
+ * Controls which variables are available and how they are displayed.
66
+ */
67
+ variables?: TemplateVariablesConfig;
68
+ /**
69
+ * Variable schema for advanced autocomplete with nested drilling.
70
+ * When provided, enables dot notation (user.name) and array access (items[0]).
71
+ * @deprecated Use `variables.schema` instead
72
+ */
73
+ variableSchema?: VariableSchema;
53
74
  /** Placeholder variable example for the hint */
54
75
  placeholderExample?: string;
55
76
  /** Whether the field is disabled (read-only) */
@@ -58,6 +79,16 @@
58
79
  ariaDescribedBy?: string;
59
80
  /** Callback when value changes */
60
81
  onChange: (value: string) => void;
82
+ /** Current workflow node (required for API mode) */
83
+ node?: WorkflowNode;
84
+ /** All workflow nodes (required for port-derived variables) */
85
+ nodes?: WorkflowNode[];
86
+ /** All workflow edges (required for port-derived variables) */
87
+ edges?: WorkflowEdge[];
88
+ /** Workflow ID (required for API mode) */
89
+ workflowId?: string;
90
+ /** Auth provider for API requests */
91
+ authProvider?: AuthProvider;
61
92
  }
62
93
 
63
94
  let {
@@ -67,13 +98,102 @@
67
98
  required = false,
68
99
  darkTheme = false,
69
100
  height = '250px',
70
- variableHints = [],
101
+ variables,
102
+ variableSchema,
71
103
  placeholderExample = 'Hello {{ name }}, your order #{{ order_id }} is ready!',
72
104
  disabled = false,
73
105
  ariaDescribedBy,
74
- onChange
106
+ onChange,
107
+ node,
108
+ nodes = [],
109
+ edges = [],
110
+ workflowId,
111
+ authProvider
75
112
  }: Props = $props();
76
113
 
114
+ /** Loading state for API variable fetching */
115
+ let isLoadingVariables = $state(false);
116
+
117
+ /** Error state for API variable fetching */
118
+ let variableLoadError = $state<string | null>(null);
119
+
120
+ /** The effective variable schema (loaded synchronously or asynchronously) */
121
+ let effectiveVariableSchema = $state<VariableSchema | undefined>(undefined);
122
+
123
+ /**
124
+ * Load variable schema on mount or when configuration changes.
125
+ * Handles both synchronous (schema-based) and asynchronous (API-based) loading.
126
+ */
127
+ async function loadVariableSchema() {
128
+ // Reset error state
129
+ variableLoadError = null;
130
+
131
+ // If we have deprecated variableSchema prop, use it directly
132
+ if (variableSchema && Object.keys(variableSchema.variables).length > 0) {
133
+ effectiveVariableSchema = variableSchema;
134
+ return;
135
+ }
136
+
137
+ // If no variables config, clear schema
138
+ if (!variables) {
139
+ effectiveVariableSchema = undefined;
140
+ return;
141
+ }
142
+
143
+ // If variables config has static schema only (no API), use it directly
144
+ if (variables.schema && !variables.api && Object.keys(variables.schema.variables).length > 0) {
145
+ effectiveVariableSchema = variables.schema;
146
+ return;
147
+ }
148
+
149
+ // If variables config requires node context (ports or API mode)
150
+ if ((variables.ports !== undefined || variables.api) && node && nodes && edges) {
151
+ try {
152
+ isLoadingVariables = true;
153
+ effectiveVariableSchema = await getVariableSchema(
154
+ node,
155
+ nodes,
156
+ edges,
157
+ variables,
158
+ workflowId,
159
+ authProvider
160
+ );
161
+ } catch (error) {
162
+ console.error('Failed to load variable schema:', error);
163
+ variableLoadError = error instanceof Error ? error.message : 'Failed to load variables';
164
+ effectiveVariableSchema = undefined;
165
+ } finally {
166
+ isLoadingVariables = false;
167
+ }
168
+ } else {
169
+ // No schema available
170
+ effectiveVariableSchema = undefined;
171
+ }
172
+ }
173
+
174
+ /**
175
+ * Retry loading variables after an error
176
+ */
177
+ function retryLoadVariables() {
178
+ loadVariableSchema();
179
+ }
180
+
181
+ /**
182
+ * Whether to show the variable hints section.
183
+ * Controlled by variables.showHints (defaults to true).
184
+ */
185
+ const showHints = $derived(variables?.showHints !== false);
186
+
187
+ /**
188
+ * Derive the list of top-level variable names for the hints display.
189
+ */
190
+ const displayVariables = $derived.by(() => {
191
+ if (effectiveVariableSchema) {
192
+ return Object.keys(effectiveVariableSchema.variables);
193
+ }
194
+ return [];
195
+ });
196
+
77
197
  /** Reference to the container element */
78
198
  let containerRef: HTMLDivElement | undefined = $state(undefined);
79
199
 
@@ -83,13 +203,21 @@
83
203
  /** Flag to prevent update loops */
84
204
  let isInternalUpdate = false;
85
205
 
206
+ /** Compartment for dynamic autocomplete reconfiguration */
207
+ const autocompleteCompartment = new Compartment();
208
+
86
209
  /**
87
210
  * Create a MatchDecorator for {{ variable }} patterns
88
211
  * This highlights the entire {{ variable }} expression
212
+ * Supports:
213
+ * - Simple variables: {{ name }}
214
+ * - Dot notation: {{ user.name }}, {{ user.address.city }}
215
+ * - Array access: {{ items[0] }}, {{ items[0].name }}
216
+ * - Mixed: {{ orders[0].items[1].price }}
89
217
  */
90
218
  const variableMatcher = new MatchDecorator({
91
- // Match {{ variable_name }} patterns (with optional whitespace)
92
- regexp: /\{\{\s*[\w.]+\s*\}\}/g,
219
+ // Match {{ variable_name }} patterns with dot notation and array indices
220
+ regexp: /\{\{\s*[\w]+(?:\.[\w]+|\[\d+\]|\[\*\])*\s*\}\}/g,
93
221
  decoration: Decoration.mark({ class: 'cm-template-variable' })
94
222
  });
95
223
 
@@ -125,7 +253,7 @@
125
253
 
126
254
  /**
127
255
  * Create editor extensions array for template editing
128
- * Uses minimal setup for better performance (no auto-closing brackets, no autocompletion)
256
+ * Includes autocomplete when variables are available
129
257
  * When disabled is true, adds readOnly/editable so the editor cannot be modified
130
258
  */
131
259
  function createExtensions() {
@@ -158,7 +286,7 @@
158
286
  // Update listener (only fires on user edit when not disabled)
159
287
  EditorView.updateListener.of(handleUpdate),
160
288
 
161
- // Custom theme
289
+ // Custom theme with autocomplete styling
162
290
  EditorView.theme({
163
291
  '&': {
164
292
  height: height,
@@ -185,20 +313,70 @@
185
313
  borderRadius: '3px',
186
314
  padding: '1px 2px',
187
315
  fontWeight: '500'
316
+ },
317
+ // Autocomplete dropdown styling
318
+ '.cm-tooltip.cm-tooltip-autocomplete': {
319
+ backgroundColor: 'var(--fd-background, #ffffff)',
320
+ border: '1px solid var(--fd-border, #e5e7eb)',
321
+ borderRadius: 'var(--fd-radius-lg, 0.5rem)',
322
+ boxShadow: 'var(--fd-shadow-lg, 0 10px 15px -3px rgba(0, 0, 0, 0.1))',
323
+ padding: '0.25rem',
324
+ maxHeight: '200px',
325
+ overflow: 'auto'
326
+ },
327
+ '.cm-tooltip.cm-tooltip-autocomplete > ul': {
328
+ fontFamily: "'JetBrains Mono', 'Fira Code', 'Monaco', 'Menlo', monospace",
329
+ fontSize: '0.8125rem'
330
+ },
331
+ '.cm-tooltip.cm-tooltip-autocomplete > ul > li': {
332
+ padding: '0.375rem 0.625rem',
333
+ borderRadius: 'var(--fd-radius-md, 0.375rem)',
334
+ display: 'flex',
335
+ alignItems: 'center',
336
+ gap: '0.5rem'
337
+ },
338
+ '.cm-tooltip.cm-tooltip-autocomplete > ul > li[aria-selected]': {
339
+ backgroundColor: 'var(--fd-accent-muted, rgba(168, 85, 247, 0.1))',
340
+ color: 'var(--fd-accent-hover, #7c3aed)'
341
+ },
342
+ '.cm-completionLabel': {
343
+ flex: '1'
344
+ },
345
+ '.cm-completionDetail': {
346
+ fontSize: '0.6875rem',
347
+ color: 'var(--fd-muted-foreground, #6b7280)',
348
+ opacity: '0.8'
188
349
  }
189
350
  }),
190
351
  EditorView.lineWrapping,
191
352
  EditorState.tabSize.of(2)
192
353
  ];
193
354
 
355
+ // Add autocomplete compartment (can be reconfigured dynamically)
356
+ // When disabled or no schema, use empty array
357
+ if (!disabled && effectiveVariableSchema) {
358
+ extensions.push(autocompleteCompartment.of(createTemplateAutocomplete(effectiveVariableSchema)));
359
+ } else {
360
+ extensions.push(autocompleteCompartment.of([]));
361
+ }
362
+
194
363
  if (darkTheme) {
195
364
  extensions.push(oneDark);
196
- // Add dark theme override for variable highlighting
365
+ // Add dark theme override for variable highlighting and autocomplete
197
366
  extensions.push(
198
367
  EditorView.theme({
199
368
  '.cm-template-variable': {
200
369
  color: '#c084fc',
201
370
  backgroundColor: 'rgba(192, 132, 252, 0.15)'
371
+ },
372
+ '.cm-tooltip.cm-tooltip-autocomplete': {
373
+ backgroundColor: '#1e1e1e',
374
+ border: '1px solid #3e4451',
375
+ boxShadow: '0 10px 15px -3px rgba(0, 0, 0, 0.3)'
376
+ },
377
+ '.cm-tooltip.cm-tooltip-autocomplete > ul > li[aria-selected]': {
378
+ backgroundColor: 'rgba(192, 132, 252, 0.2)',
379
+ color: '#c084fc'
202
380
  }
203
381
  })
204
382
  );
@@ -227,19 +405,23 @@
227
405
  }
228
406
 
229
407
  /**
230
- * Initialize CodeMirror editor on mount
408
+ * Initialize CodeMirror editor and load variables on mount
231
409
  */
232
410
  onMount(() => {
233
411
  if (!containerRef) {
234
412
  return;
235
413
  }
236
414
 
237
- editorView = new EditorView({
238
- state: EditorState.create({
239
- doc: value,
240
- extensions: createExtensions()
241
- }),
242
- parent: containerRef
415
+ // Load variables first
416
+ loadVariableSchema().then(() => {
417
+ // Then create editor with loaded schema
418
+ editorView = new EditorView({
419
+ state: EditorState.create({
420
+ doc: value,
421
+ extensions: createExtensions()
422
+ }),
423
+ parent: containerRef
424
+ });
243
425
  });
244
426
  });
245
427
 
@@ -275,6 +457,28 @@
275
457
  isInternalUpdate = false;
276
458
  }
277
459
  });
460
+
461
+ /**
462
+ * Reconfigure editor when variable schema changes (e.g., after async loading)
463
+ */
464
+ $effect(() => {
465
+ // Only track effectiveVariableSchema changes
466
+ const schema = effectiveVariableSchema;
467
+
468
+ if (!editorView) {
469
+ return;
470
+ }
471
+
472
+ // When effectiveVariableSchema changes, reconfigure the autocomplete compartment
473
+ // This happens after async API loading completes
474
+ const newAutocomplete = !disabled && schema
475
+ ? createTemplateAutocomplete(schema)
476
+ : [];
477
+
478
+ editorView.dispatch({
479
+ effects: [autocompleteCompartment.reconfigure(newAutocomplete)]
480
+ });
481
+ });
278
482
  </script>
279
483
 
280
484
  <div class="form-template-editor">
@@ -298,12 +502,66 @@
298
502
  aria-label="Template editor"
299
503
  ></div>
300
504
 
301
- <!-- Variable hints section (shown when variables are available) -->
302
- {#if variableHints.length > 0}
505
+ <!-- Loading banner (shown while fetching variables from API) -->
506
+ {#if isLoadingVariables}
507
+ <div class="form-template-editor__banner form-template-editor__banner--loading">
508
+ <svg
509
+ class="form-template-editor__banner-icon form-template-editor__banner-icon--spin"
510
+ xmlns="http://www.w3.org/2000/svg"
511
+ fill="none"
512
+ viewBox="0 0 24 24"
513
+ >
514
+ <circle
515
+ class="opacity-25"
516
+ cx="12"
517
+ cy="12"
518
+ r="10"
519
+ stroke="currentColor"
520
+ stroke-width="4"
521
+ ></circle>
522
+ <path
523
+ class="opacity-75"
524
+ fill="currentColor"
525
+ d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
526
+ ></path>
527
+ </svg>
528
+ <span>Loading variables...</span>
529
+ </div>
530
+ {/if}
531
+
532
+ <!-- Error banner (shown when API fetch fails) -->
533
+ {#if variableLoadError}
534
+ <div class="form-template-editor__banner form-template-editor__banner--error">
535
+ <svg
536
+ class="form-template-editor__banner-icon"
537
+ xmlns="http://www.w3.org/2000/svg"
538
+ viewBox="0 0 20 20"
539
+ fill="currentColor"
540
+ >
541
+ <path
542
+ fill-rule="evenodd"
543
+ d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-8-5a.75.75 0 01.75.75v4.5a.75.75 0 01-1.5 0v-4.5A.75.75 0 0110 5zm0 10a1 1 0 100-2 1 1 0 000 2z"
544
+ clip-rule="evenodd"
545
+ />
546
+ </svg>
547
+ <span>{variableLoadError}</span>
548
+ <button
549
+ type="button"
550
+ class="form-template-editor__banner-btn"
551
+ onclick={retryLoadVariables}
552
+ title="Retry loading variables"
553
+ >
554
+ Retry
555
+ </button>
556
+ </div>
557
+ {/if}
558
+
559
+ <!-- Variable hints section (shown when variables are available and showHints is true) -->
560
+ {#if showHints && displayVariables.length > 0}
303
561
  <div class="form-template-editor__hints">
304
562
  <span class="form-template-editor__hints-label">Available variables:</span>
305
563
  <div class="form-template-editor__hints-list">
306
- {#each variableHints as varName (varName)}
564
+ {#each displayVariables as varName (varName)}
307
565
  <button
308
566
  type="button"
309
567
  class="form-template-editor__hint-btn"
@@ -499,4 +757,68 @@
499
757
  font-family: 'JetBrains Mono', 'Fira Code', 'Monaco', 'Menlo', monospace;
500
758
  font-size: 0.625rem;
501
759
  }
760
+
761
+ /* Loading and error banners */
762
+ .form-template-editor__banner {
763
+ display: flex;
764
+ align-items: center;
765
+ gap: 0.5rem;
766
+ margin-top: 0.625rem;
767
+ padding: 0.625rem 0.75rem;
768
+ border-radius: var(--fd-radius-md);
769
+ font-size: 0.75rem;
770
+ }
771
+
772
+ .form-template-editor__banner--loading {
773
+ background-color: rgba(59, 130, 246, 0.1);
774
+ border: 1px solid rgba(59, 130, 246, 0.3);
775
+ color: rgb(29, 78, 216);
776
+ }
777
+
778
+ .form-template-editor__banner--error {
779
+ background-color: rgba(239, 68, 68, 0.1);
780
+ border: 1px solid rgba(239, 68, 68, 0.3);
781
+ color: rgb(185, 28, 28);
782
+ }
783
+
784
+ .form-template-editor__banner-icon {
785
+ width: 1rem;
786
+ height: 1rem;
787
+ flex-shrink: 0;
788
+ }
789
+
790
+ .form-template-editor__banner-icon--spin {
791
+ animation: spin 1s linear infinite;
792
+ }
793
+
794
+ @keyframes spin {
795
+ from {
796
+ transform: rotate(0deg);
797
+ }
798
+ to {
799
+ transform: rotate(360deg);
800
+ }
801
+ }
802
+
803
+ .form-template-editor__banner-btn {
804
+ margin-left: auto;
805
+ padding: 0.25rem 0.625rem;
806
+ background-color: rgba(239, 68, 68, 0.15);
807
+ border: 1px solid rgba(239, 68, 68, 0.3);
808
+ border-radius: var(--fd-radius-sm);
809
+ font-size: 0.6875rem;
810
+ font-weight: 500;
811
+ color: rgb(185, 28, 28);
812
+ cursor: pointer;
813
+ transition: all var(--fd-transition-fast);
814
+ }
815
+
816
+ .form-template-editor__banner-btn:hover {
817
+ background-color: rgba(239, 68, 68, 0.25);
818
+ border-color: rgba(239, 68, 68, 0.5);
819
+ }
820
+
821
+ .form-template-editor__banner-btn:active {
822
+ transform: scale(0.98);
823
+ }
502
824
  </style>
@@ -1,3 +1,4 @@
1
+ import type { VariableSchema, TemplateVariablesConfig, WorkflowNode, WorkflowEdge, AuthProvider } from '../../types/index.js';
1
2
  interface Props {
2
3
  /** Field identifier */
3
4
  id: string;
@@ -11,8 +12,17 @@ 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
- variableHints?: string[];
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;
16
26
  /** Placeholder variable example for the hint */
17
27
  placeholderExample?: string;
18
28
  /** Whether the field is disabled (read-only) */
@@ -21,6 +31,16 @@ interface Props {
21
31
  ariaDescribedBy?: string;
22
32
  /** Callback when value changes */
23
33
  onChange: (value: string) => void;
34
+ /** Current workflow node (required for API mode) */
35
+ node?: WorkflowNode;
36
+ /** All workflow nodes (required for port-derived variables) */
37
+ nodes?: WorkflowNode[];
38
+ /** All workflow edges (required for port-derived variables) */
39
+ edges?: WorkflowEdge[];
40
+ /** Workflow ID (required for API mode) */
41
+ workflowId?: string;
42
+ /** Auth provider for API requests */
43
+ authProvider?: AuthProvider;
24
44
  }
25
45
  declare const FormTemplateEditor: import("svelte").Component<Props, {}, "">;
26
46
  type FormTemplateEditor = ReturnType<typeof FormTemplateEditor>;
@@ -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 } 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 } from './templateAutocomplete.js';
@@ -0,0 +1,29 @@
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;