robobyte-front-builder 1.0.17 → 1.0.19

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.
@@ -0,0 +1,546 @@
1
+ import React, {useState, useEffect} from 'react';
2
+ import {
3
+ Dialog,
4
+ DialogTitle,
5
+ DialogContent,
6
+ DialogActions,
7
+ Button,
8
+ Grid,
9
+ TextField,
10
+ FormControl,
11
+ InputLabel,
12
+ Select,
13
+ MenuItem,
14
+ Typography,
15
+ Paper,
16
+ Box,
17
+ IconButton,
18
+ Divider,
19
+ FormControlLabel,
20
+ Switch,
21
+ Tooltip,
22
+ Autocomplete, Collapse
23
+ } from '@mui/material';
24
+ import {DeleteOutline, Plus, ChevronDown, ChevronUp} from 'mdi-material-ui';
25
+ import dynamic from 'next/dynamic';
26
+
27
+ const MonacoEditor = dynamic(() => import('@monaco-editor/react'), {ssr: false});
28
+
29
+ const FormattingSettingsDialog = ({open, onClose, field, onSave}) => {
30
+ const [settings, setSettings] = useState({
31
+ decimals: 0,
32
+ conditions: [],
33
+ fixedStyle: {
34
+ color: '',
35
+ backgroundColor: '',
36
+ fontWeight: 'normal',
37
+ flashing: false,
38
+ }
39
+ });
40
+
41
+ useEffect(() => {
42
+ if (field && field.formatting) {
43
+ setSettings(field.formatting);
44
+ } else {
45
+ setSettings({
46
+ decimals: 0,
47
+ conditions: [],
48
+ fixedStyle: {
49
+ color: '',
50
+ backgroundColor: '',
51
+ fontWeight: 'normal',
52
+ flashing: false,
53
+ }
54
+ });
55
+ }
56
+ }, [field, open]);
57
+
58
+ const handleSave = () => {
59
+ onSave(settings);
60
+ onClose();
61
+ };
62
+
63
+ const addCondition = () => {
64
+ setSettings(prev => ({
65
+ ...prev,
66
+ conditions: [
67
+ ...prev.conditions,
68
+ {
69
+ baseField: 'self', // 'self' or path of another field
70
+ operator: '==',
71
+ value: '',
72
+ valueType: 'static', // 'static' or 'field'
73
+ compareField: '', // path of field for comparison
74
+ style: {
75
+ color: '',
76
+ backgroundColor: '',
77
+ fontWeight: 'normal',
78
+ flashing: false,
79
+ }
80
+ }
81
+ ]
82
+ }));
83
+ };
84
+
85
+ const removeCondition = (index) => {
86
+ setSettings(prev => ({
87
+ ...prev,
88
+ conditions: prev.conditions.filter((_, i) => i !== index)
89
+ }));
90
+ };
91
+
92
+ const updateCondition = (index, key, value) => {
93
+ setSettings(prev => {
94
+ const newConditions = [...prev.conditions];
95
+ if (key.includes('.')) {
96
+ const [obj, prop] = key.split('.');
97
+ newConditions[index][obj][prop] = value;
98
+ } else {
99
+ newConditions[index][key] = value;
100
+ }
101
+ return {...prev, conditions: newConditions};
102
+ });
103
+ };
104
+
105
+ const updateFixedStyle = (key, value) => {
106
+ setSettings(prev => ({
107
+ ...prev,
108
+ fixedStyle: {
109
+ ...prev.fixedStyle,
110
+ [key]: value
111
+ }
112
+ }));
113
+ };
114
+
115
+ const [expandedEditors, setExpandedEditors] = useState({});
116
+
117
+ useEffect(() => {
118
+ // Expand math expression editors by default if they have content
119
+ if (open && settings.conditions) {
120
+ const initialExpanded = {};
121
+ settings.conditions.forEach((cond, index) => {
122
+ if (cond.valueType === 'expression') {
123
+ initialExpanded[index] = true;
124
+ }
125
+ });
126
+ setExpandedEditors(initialExpanded);
127
+ }
128
+ }, [open]);
129
+
130
+ const toggleEditorExpansion = (index) => {
131
+ setExpandedEditors(prev => ({
132
+ ...prev,
133
+ [index]: !prev[index]
134
+ }));
135
+ };
136
+
137
+ const isNumeric = field?.propertyType === 'Int' || field?.propertyType === 'Double';
138
+
139
+ const fieldOptions = field?.parentFields || []; // This would need to be passed if we want to base on other fields
140
+
141
+ return (
142
+ <Dialog open={open} onClose={onClose} maxWidth="lg" fullWidth dir="ltr">
143
+ <DialogTitle>Formatting Settings: {field?.title || field?.headerName}</DialogTitle>
144
+ <DialogContent>
145
+ <Grid container spacing={3} sx={{mt: 1}}>
146
+ {isNumeric && (
147
+ <Grid size={{ xs: 12 }}>
148
+ <TextField
149
+ label="Decimal Places"
150
+ type="number"
151
+ fullWidth
152
+ value={settings.decimals}
153
+ onChange={(e) => setSettings({...settings, decimals: parseInt(e.target.value) || 0})}
154
+ />
155
+ </Grid>
156
+ )}
157
+
158
+ <Grid size={{ xs: 12 }}>
159
+ <Typography variant="subtitle1" gutterBottom fontWeight="bold">Fixed Style</Typography>
160
+ <Grid container spacing={2}>
161
+ <Grid size={{ xs: 3 }}>
162
+ <TextField
163
+ label="Text Color"
164
+ type="color"
165
+ fullWidth
166
+ InputLabelProps={{shrink: true}}
167
+ value={settings.fixedStyle?.color || '#000000'}
168
+ onChange={(e) => updateFixedStyle('color', e.target.value)}
169
+ />
170
+ </Grid>
171
+ <Grid size={{ xs: 3 }}>
172
+ <TextField
173
+ label="Background Color"
174
+ type="color"
175
+ fullWidth
176
+ InputLabelProps={{shrink: true}}
177
+ value={settings.fixedStyle?.backgroundColor || '#ffffff'}
178
+ onChange={(e) => updateFixedStyle('backgroundColor', e.target.value)}
179
+ />
180
+ </Grid>
181
+ <Grid size={{ xs: 3 }}>
182
+ <FormControl fullWidth>
183
+ <InputLabel>Font Weight</InputLabel>
184
+ <Select
185
+ value={settings.fixedStyle?.fontWeight || 'normal'}
186
+ label="Font Weight"
187
+ onChange={(e) => updateFixedStyle('fontWeight', e.target.value)}
188
+ >
189
+ <MenuItem value="normal">Normal</MenuItem>
190
+ <MenuItem value="bold">Bold</MenuItem>
191
+ </Select>
192
+ </FormControl>
193
+ </Grid>
194
+ <Grid display="flex" alignItems="center" size={{ xs: 1 }}>
195
+ <FormControlLabel
196
+ control={
197
+ <Switch
198
+ checked={settings.fixedStyle?.flashing || false}
199
+ onChange={(e) => updateFixedStyle('flashing', e.target.checked)}
200
+ />
201
+ }
202
+ label="Flashing"
203
+ />
204
+ </Grid>
205
+ </Grid>
206
+ </Grid>
207
+
208
+ <Grid size={{ xs: 12 }}>
209
+ <Divider sx={{my: 2}} />
210
+ <Box display="flex" justifyContent="space-between" alignItems="center" mb={2}>
211
+ <Typography variant="subtitle1" fontWeight="bold">Conditional Formatting (Emphasis)</Typography>
212
+ <Button startIcon={<Plus />} variant="outlined" size="small" onClick={addCondition}>
213
+ Add Condition
214
+ </Button>
215
+ </Box>
216
+
217
+ {settings.conditions.map((condition, index) => (
218
+ <Paper key={index} variant="outlined" sx={{p: 2, mb: 2, backgroundColor: '#f9f9f9'}}>
219
+ <Grid container spacing={2} alignItems="center">
220
+ <Grid size={{ xs: 1.5 }}>
221
+ <FormControl fullWidth size="small">
222
+ <InputLabel>Type</InputLabel>
223
+ <Select
224
+ value={condition.valueType || 'static'}
225
+ label="Type"
226
+ onChange={(e) => {
227
+ const newType = e.target.value;
228
+ updateCondition(index, 'valueType', newType);
229
+ if (newType === 'expression') {
230
+ setExpandedEditors(prev => ({...prev, [index]: true}));
231
+ }
232
+ }}
233
+ >
234
+ <MenuItem value="static">Static Value</MenuItem>
235
+ <MenuItem value="field">Another Field</MenuItem>
236
+ <MenuItem value="expression">Math Expression</MenuItem>
237
+ </Select>
238
+ </FormControl>
239
+ </Grid>
240
+ {condition.valueType !== 'expression' && (
241
+ <Grid size={{ xs: 12, sm: 3 }}>
242
+ <Autocomplete
243
+ freeSolo
244
+ size="small"
245
+ options={['self', ...fieldOptions.map(f => f.path)]}
246
+ getOptionLabel={(option) => {
247
+ if (option === 'self') return 'self';
248
+ const f = fieldOptions.find(fo => fo.path === option);
249
+ return f ? `${f.title || f.headerName} (${f.path})` : option;
250
+ }}
251
+ isOptionEqualToValue={(option, value) => option === value}
252
+ value={condition.baseField || 'self'}
253
+ onChange={(e, newValue) => {
254
+ updateCondition(index, 'baseField', newValue || 'self');
255
+ }}
256
+ onBlur={(e) => {
257
+ const val = e.target.value;
258
+ if (val === 'self' || !val) {
259
+ updateCondition(index, 'baseField', 'self');
260
+ } else {
261
+ // Find if the typed value matches any of our options' labels or paths
262
+ const matchedOption = fieldOptions.find(f =>
263
+ f.path === val || `${f.title || f.headerName} (${f.path})` === val
264
+ );
265
+ updateCondition(index, 'baseField', matchedOption ? matchedOption.path : val);
266
+ }
267
+ }}
268
+ renderInput={(params) => (
269
+ <TextField {...params} label="Base Field" />
270
+ )}
271
+ />
272
+ </Grid>
273
+ )}
274
+ {condition.valueType !== 'expression' && (
275
+ <Grid size={{ xs: 12, sm: 2 }}>
276
+ <FormControl fullWidth size="small">
277
+ <InputLabel>Operator</InputLabel>
278
+ <Select
279
+ value={condition.operator}
280
+ label="Operator"
281
+ onChange={(e) => updateCondition(index, 'operator', e.target.value)}
282
+ >
283
+ <MenuItem value="==">Equals</MenuItem>
284
+ <MenuItem value="!=">Not Equals</MenuItem>
285
+ <MenuItem value=">">Greater Than</MenuItem>
286
+ <MenuItem value="<">Less Than</MenuItem>
287
+ <MenuItem value=">=">Greater Than or Equal</MenuItem>
288
+ <MenuItem value="<=">Less Than or Equal</MenuItem>
289
+ <MenuItem value="contains">Contains</MenuItem>
290
+ </Select>
291
+ </FormControl>
292
+ </Grid>
293
+ )}
294
+ <Grid dir="ltr" size={{ xs: 12, sm: condition.valueType === 'expression' ? 4.5 : 3.5 }}>
295
+ {condition.valueType === 'field' ? (
296
+ <Autocomplete
297
+ freeSolo
298
+ size="small"
299
+ options={fieldOptions.map(f => f.path)}
300
+ getOptionLabel={(option) => {
301
+ const f = fieldOptions.find(fo => fo.path === option);
302
+ return f ? `${f.title || f.headerName} (${f.path})` : option;
303
+ }}
304
+ isOptionEqualToValue={(option, value) => option === value}
305
+ value={condition.compareField || ''}
306
+ onChange={(e, newValue) => {
307
+ updateCondition(index, 'compareField', newValue || '');
308
+ }}
309
+ onBlur={(e) => {
310
+ const val = e.target.value;
311
+ const matchedOption = fieldOptions.find(f =>
312
+ f.path === val || `${f.title || f.headerName} (${f.path})` === val
313
+ );
314
+ updateCondition(index, 'compareField', matchedOption ? matchedOption.path : val);
315
+ }}
316
+ renderInput={(params) => (
317
+ <TextField {...params} label="Compare With" />
318
+ )}
319
+ />
320
+ ) : condition.valueType === 'expression' ? null : (
321
+ <TextField
322
+ label="Value"
323
+ size="small"
324
+ fullWidth
325
+ value={condition.value}
326
+ onChange={(e) => updateCondition(index, 'value', e.target.value)}
327
+ />
328
+ )}
329
+ </Grid>
330
+ <Grid size={{ xs: 1.5 }}>
331
+ <TextField
332
+ label="Color"
333
+ type="color"
334
+ size="small"
335
+ fullWidth
336
+ InputLabelProps={{shrink: true}}
337
+ value={condition.style.color || '#000000'}
338
+ onChange={(e) => updateCondition(index, 'style.color', e.target.value)}
339
+ />
340
+ </Grid>
341
+ <Grid size={{ xs: 1.5 }}>
342
+ <TextField
343
+ label="BG Color"
344
+ type="color"
345
+ size="small"
346
+ fullWidth
347
+ InputLabelProps={{shrink: true}}
348
+ value={condition.style.backgroundColor || '#ffffff'}
349
+ onChange={(e) => updateCondition(index, 'style.backgroundColor', e.target.value)}
350
+ />
351
+ </Grid>
352
+ <Grid size={{ xs: 1.5 }}>
353
+ <FormControl fullWidth size="small">
354
+ <InputLabel>Font Weight</InputLabel>
355
+ <Select
356
+ value={condition.style.fontWeight || 'normal'}
357
+ label="Font Weight"
358
+ onChange={(e) => updateCondition(index, 'style.fontWeight', e.target.value)}
359
+ >
360
+ <MenuItem value="normal">Normal</MenuItem>
361
+ <MenuItem value="bold">Bold</MenuItem>
362
+ </Select>
363
+ </FormControl>
364
+ </Grid>
365
+ <Grid size={{ xs: 1 }}>
366
+ <FormControlLabel
367
+ control={
368
+ <Switch
369
+ size="small"
370
+ checked={condition.style.flashing || false}
371
+ onChange={(e) => updateCondition(index, 'style.flashing', e.target.checked)}
372
+ />
373
+ }
374
+ label={<Typography variant="caption">Flash</Typography>}
375
+ />
376
+ </Grid>
377
+ <Grid display="flex" justifyContent="flex-end" size={{ xs: 0.5 }}>
378
+ <IconButton size="small" color="error" onClick={() => removeCondition(index)}>
379
+ <DeleteOutline />
380
+ </IconButton>
381
+ </Grid>
382
+
383
+ {/* Expression Editor in another row */}
384
+ {condition.valueType === 'expression' && (
385
+ <Grid size={{ xs: 12 }}>
386
+ <Box sx={{ border: '1px solid #ced4da', borderRadius: 1, overflow: 'hidden', mt: 1 }}>
387
+ <Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', px: 1, py: 0.5, backgroundColor: '#f0f0f0' }}>
388
+ <Typography variant="caption" fontWeight="bold">Math Expression</Typography>
389
+ <IconButton size="small" onClick={() => toggleEditorExpansion(index)}>
390
+ {expandedEditors[index] ? <ChevronUp size="small" /> : <ChevronDown size="small" />}
391
+ </IconButton>
392
+ </Box>
393
+ <Collapse in={expandedEditors[index]}>
394
+ <Box dir="ltr">
395
+ <MonacoEditor
396
+ height="200px"
397
+ language="mazajak-expression"
398
+ theme="vs-dark"
399
+ value={condition.expression || ''}
400
+ onChange={(newValue) => {
401
+ updateCondition(index, 'expression', newValue || '');
402
+ }}
403
+ onMount={(editor, monaco) => {
404
+ // Define a custom language for highlighting
405
+ const langId = 'mazajak-expression';
406
+
407
+ // Register the language if not already registered
408
+ if (!monaco.languages.getLanguages().some(l => l.id === langId)) {
409
+ monaco.languages.register({ id: langId });
410
+
411
+ // Define the tokenizer
412
+ monaco.languages.setMonarchTokensProvider(langId, {
413
+ tokenizer: {
414
+ root: [
415
+ // Double quotes for field placeholders (highlighted as tags/regex/special)
416
+ [/"[^"]*"/, 'tag'],
417
+
418
+ // Single quotes for string literals (standard string highlighting)
419
+ [/'[^']*'/, 'string'],
420
+
421
+ // Standard JavaScript-like tokens
422
+ [/[a-z_$][\w$]*/, {
423
+ cases: {
424
+ 'if|else|switch|case|break|default|return': 'keyword',
425
+ 'true|false|null': 'constant',
426
+ '@default': 'identifier'
427
+ }
428
+ }],
429
+ [/[{}()\[\]]/, '@brackets'],
430
+ [/[0-9]+/, 'number'],
431
+ [/[><=!|&?:,+*/%-]/, 'operator'],
432
+ [/[ \t\r\n]+/, 'white'],
433
+ ]
434
+ }
435
+ });
436
+
437
+ // Define custom theme colors for these tokens if needed,
438
+ // but 'tag' and 'string' already have different colors in vs-dark.
439
+ }
440
+
441
+ // Update the editor's model language
442
+ const model = editor.getModel();
443
+ if (model) {
444
+ monaco.editor.setModelLanguage(model, langId);
445
+ }
446
+
447
+ // Register completion provider for the custom language
448
+ const provider = monaco.languages.registerCompletionItemProvider(langId, {
449
+ triggerCharacters: ['"'],
450
+ provideCompletionItems: (model, position) => {
451
+ const textUntilPosition = model.getValueInRange({
452
+ startLineNumber: 1,
453
+ startColumn: 1,
454
+ endLineNumber: position.lineNumber,
455
+ endColumn: position.column
456
+ });
457
+
458
+ const quoteCount = (textUntilPosition.match(/"/g) || []).length;
459
+ const isInsideQuotes = quoteCount % 2 !== 0;
460
+
461
+ if (isInsideQuotes) {
462
+ return {
463
+ suggestions: fieldOptions.map(f => ({
464
+ label: `"${f.path}"`,
465
+ kind: monaco.languages.CompletionItemKind.Field,
466
+ documentation: f.title || f.headerName,
467
+ insertText: f.path, // Just the path
468
+ range: {
469
+ startLineNumber: position.lineNumber,
470
+ endLineNumber: position.lineNumber,
471
+ startColumn: position.column,
472
+ endColumn: position.column
473
+ }
474
+ }))
475
+ };
476
+ } else {
477
+ return {
478
+ suggestions: [
479
+ { label: '+', kind: monaco.languages.CompletionItemKind.Operator, insertText: '+ ', range: { startLineNumber: position.lineNumber, endLineNumber: position.lineNumber, startColumn: position.column, endColumn: position.column } },
480
+ { label: '-', kind: monaco.languages.CompletionItemKind.Operator, insertText: '- ', range: { startLineNumber: position.lineNumber, endLineNumber: position.lineNumber, startColumn: position.column, endColumn: position.column } },
481
+ { label: '*', kind: monaco.languages.CompletionItemKind.Operator, insertText: '* ', range: { startLineNumber: position.lineNumber, endLineNumber: position.lineNumber, startColumn: position.column, endColumn: position.column } },
482
+ { label: '/', kind: monaco.languages.CompletionItemKind.Operator, insertText: '/ ', range: { startLineNumber: position.lineNumber, endLineNumber: position.lineNumber, startColumn: position.column, endColumn: position.column } },
483
+ { label: '(', kind: monaco.languages.CompletionItemKind.Operator, insertText: '( ', range: { startLineNumber: position.lineNumber, endLineNumber: position.lineNumber, startColumn: position.column, endColumn: position.column } },
484
+ { label: ')', kind: monaco.languages.CompletionItemKind.Operator, insertText: ') ', range: { startLineNumber: position.lineNumber, endLineNumber: position.lineNumber, startColumn: position.column, endColumn: position.column } },
485
+ { label: '>', kind: monaco.languages.CompletionItemKind.Operator, insertText: '> ', range: { startLineNumber: position.lineNumber, endLineNumber: position.lineNumber, startColumn: position.column, endColumn: position.column } },
486
+ { label: '<', kind: monaco.languages.CompletionItemKind.Operator, insertText: '< ', range: { startLineNumber: position.lineNumber, endLineNumber: position.lineNumber, startColumn: position.column, endColumn: position.column } },
487
+ { label: '>=', kind: monaco.languages.CompletionItemKind.Operator, insertText: '>= ', range: { startLineNumber: position.lineNumber, endLineNumber: position.lineNumber, startColumn: position.column, endColumn: position.column } },
488
+ { label: '<=', kind: monaco.languages.CompletionItemKind.Operator, insertText: '<= ', range: { startLineNumber: position.lineNumber, endLineNumber: position.lineNumber, startColumn: position.column, endColumn: position.column } },
489
+ { label: '==', kind: monaco.languages.CompletionItemKind.Operator, insertText: '== ', range: { startLineNumber: position.lineNumber, endLineNumber: position.lineNumber, startColumn: position.column, endColumn: position.column } },
490
+ { label: '!=', kind: monaco.languages.CompletionItemKind.Operator, insertText: '!= ', range: { startLineNumber: position.lineNumber, endLineNumber: position.lineNumber, startColumn: position.column, endColumn: position.column } },
491
+ { label: '&&', kind: monaco.languages.CompletionItemKind.Operator, insertText: '&& ', range: { startLineNumber: position.lineNumber, endLineNumber: position.lineNumber, startColumn: position.column, endColumn: position.column } },
492
+ { label: '||', kind: monaco.languages.CompletionItemKind.Operator, insertText: '|| ', range: { startLineNumber: position.lineNumber, endLineNumber: position.lineNumber, startColumn: position.column, endColumn: position.column } },
493
+ { label: '?', kind: monaco.languages.CompletionItemKind.Operator, insertText: '? ', range: { startLineNumber: position.lineNumber, endLineNumber: position.lineNumber, startColumn: position.column, endColumn: position.column } },
494
+ { label: ':', kind: monaco.languages.CompletionItemKind.Operator, insertText: ': ', range: { startLineNumber: position.lineNumber, endLineNumber: position.lineNumber, startColumn: position.column, endColumn: position.column } },
495
+ { label: 'if', kind: monaco.languages.CompletionItemKind.Keyword, insertText: 'if ($1) {\n\t$0\n}', insertTextRules: monaco.languages.CompletionItemInsertRules.InsertAsSnippet, range: { startLineNumber: position.lineNumber, endLineNumber: position.lineNumber, startColumn: position.column, endColumn: position.column } },
496
+ { label: 'else', kind: monaco.languages.CompletionItemKind.Keyword, insertText: 'else {\n\t$0\n}', insertTextRules: monaco.languages.CompletionItemInsertRules.InsertAsSnippet, range: { startLineNumber: position.lineNumber, endLineNumber: position.lineNumber, startColumn: position.column, endColumn: position.column } },
497
+ { label: 'switch', kind: monaco.languages.CompletionItemKind.Keyword, insertText: 'switch ($1) {\n\tcase $2:\n\t\t$0\n\t\tbreak;\n}', insertTextRules: monaco.languages.CompletionItemInsertRules.InsertAsSnippet, range: { startLineNumber: position.lineNumber, endLineNumber: position.lineNumber, startColumn: position.column, endColumn: position.column } },
498
+ { label: 'case', kind: monaco.languages.CompletionItemKind.Keyword, insertText: 'case $1:\n\t$0\n\tbreak;', insertTextRules: monaco.languages.CompletionItemInsertRules.InsertAsSnippet, range: { startLineNumber: position.lineNumber, endLineNumber: position.lineNumber, startColumn: position.column, endColumn: position.column } },
499
+ { label: 'break', kind: monaco.languages.CompletionItemKind.Keyword, insertText: 'break;', range: { startLineNumber: position.lineNumber, endLineNumber: position.lineNumber, startColumn: position.column, endColumn: position.column } },
500
+ { label: 'default', kind: monaco.languages.CompletionItemKind.Keyword, insertText: 'default:\n\t$0', insertTextRules: monaco.languages.CompletionItemInsertRules.InsertAsSnippet, range: { startLineNumber: position.lineNumber, endLineNumber: position.lineNumber, startColumn: position.column, endColumn: position.column } },
501
+ { label: 'return', kind: monaco.languages.CompletionItemKind.Keyword, insertText: 'return $0;', insertTextRules: monaco.languages.CompletionItemInsertRules.InsertAsSnippet, range: { startLineNumber: position.lineNumber, endLineNumber: position.lineNumber, startColumn: position.column, endColumn: position.column } },
502
+ ]
503
+ };
504
+ }
505
+ }
506
+ });
507
+ editor.onDidDispose(() => provider.dispose());
508
+ }}
509
+ options={{
510
+ minimap: { enabled: false },
511
+ fontSize: 13,
512
+ lineNumbers: 'off',
513
+ folding: true,
514
+ scrollBeyondLastLine: false,
515
+ automaticLayout: true,
516
+ wordWrap: 'on',
517
+ formatOnPaste: true,
518
+ formatOnType: true,
519
+ suggestOnTriggerCharacters: true,
520
+ }}
521
+ />
522
+ </Box>
523
+ </Collapse>
524
+ {!expandedEditors[index] && (
525
+ <Box sx={{ p: 1, backgroundColor: '#333', color: '#fff', fontSize: '0.75rem', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', cursor: 'pointer' }} onClick={() => toggleEditorExpansion(index)}>
526
+ {condition.expression || 'Click to edit expression...'}
527
+ </Box>
528
+ )}
529
+ </Box>
530
+ </Grid>
531
+ )}
532
+ </Grid>
533
+ </Paper>
534
+ ))}
535
+ </Grid>
536
+ </Grid>
537
+ </DialogContent>
538
+ <DialogActions>
539
+ <Button onClick={onClose}>Cancel</Button>
540
+ <Button onClick={handleSave} variant="contained" color="primary">Save</Button>
541
+ </DialogActions>
542
+ </Dialog>
543
+ );
544
+ };
545
+
546
+ export default FormattingSettingsDialog;