@design.estate/dees-wcctools 1.0.100 → 1.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.
@@ -34,31 +34,65 @@ export class WccProperties extends DeesElement {
34
34
  @state()
35
35
  propertyContent: TemplateResult[] = [];
36
36
 
37
+ @state()
38
+ editingProperties: Array<{
39
+ id: string;
40
+ name: string;
41
+ value: any;
42
+ element: HTMLElement;
43
+ editorValue: string;
44
+ editorError: string;
45
+ }> = [];
46
+
47
+ public editorHeight: number = 300;
48
+
37
49
  public render(): TemplateResult {
38
50
  return html`
39
51
  <style>
40
52
  :host {
41
- font-family: 'Roboto', sans-serif;
53
+ /* CSS Variables - Always dark theme */
54
+ --background: #0a0a0a;
55
+ --foreground: #e5e5e5;
56
+ --card: #0f0f0f;
57
+ --card-foreground: #f0f0f0;
58
+ --muted: #1a1a1a;
59
+ --muted-foreground: #666;
60
+ --accent: #222;
61
+ --accent-foreground: #fff;
62
+ --border: rgba(255, 255, 255, 0.06);
63
+ --input: #141414;
64
+ --primary: #3b82f6;
65
+ --primary-foreground: #fff;
66
+ --ring: #3b82f6;
67
+ --radius: 4px;
68
+ --radius-sm: 2px;
69
+ --radius-md: 4px;
70
+ --radius-lg: 6px;
71
+
72
+ /* Base styles */
73
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif;
42
74
  box-sizing: border-box;
43
75
  position: absolute;
44
76
  left: 200px;
45
- height: 100px;
77
+ height: ${this.editingProperties.length > 0 ? 100 + this.editorHeight : 100}px;
46
78
  bottom: 0px;
47
79
  right: 0px;
48
80
  overflow: hidden;
49
- background: #111;
50
- color: #fff;
81
+ background: var(--background);
82
+ color: var(--foreground);
51
83
  }
52
84
  .grid {
53
85
  display: grid;
54
- grid-template-columns: auto 150px 300px 70px;
86
+ grid-template-columns: 1fr 150px 300px 70px;
87
+ height: 100%;
55
88
  }
56
89
  .properties {
57
- border-right: 1px solid #999;
58
- height: 100px;
90
+ background: transparent;
59
91
  overflow-y: auto;
60
92
  display: grid;
61
- grid-template-columns: 33% 33% 33%;
93
+ grid-template-columns: repeat(3, 1fr);
94
+ border-right: 1px solid var(--border);
95
+ align-content: start;
62
96
  }
63
97
 
64
98
  .material-symbols-outlined {
@@ -77,152 +111,543 @@ export class WccProperties extends DeesElement {
77
111
  }
78
112
 
79
113
  .properties .property {
80
- padding: 5px;
81
- background: #444;
82
- border: 1px solid #000;
114
+ padding: 0.4rem;
115
+ background: transparent;
116
+ border-right: 1px solid var(--border);
117
+ border-bottom: 1px solid var(--border);
118
+ transition: all 0.15s ease;
119
+ }
120
+
121
+ .properties .property:hover {
122
+ background: rgba(255, 255, 255, 0.02);
123
+ }
124
+
125
+ .properties .property-label {
126
+ font-size: 0.65rem;
127
+ font-weight: 400;
128
+ color: #888;
129
+ margin-bottom: 0.2rem;
130
+ text-transform: capitalize;
131
+ white-space: nowrap;
132
+ overflow: hidden;
133
+ text-overflow: ellipsis;
83
134
  }
84
135
 
85
- .properties input,
136
+ .properties input[type="text"],
137
+ .properties input[type="number"],
86
138
  .properties select {
87
139
  display: block;
88
140
  width: 100%;
89
- background: #333;
90
- border: none;
91
- color: #fff;
141
+ padding: 0.25rem 0.4rem;
142
+ background: var(--input);
143
+ border: 1px solid transparent;
144
+ color: var(--foreground);
145
+ border-radius: var(--radius-sm);
146
+ font-size: 0.7rem;
147
+ transition: all 0.15s ease;
148
+ outline: none;
149
+ }
150
+
151
+ .properties input[type="text"]:focus,
152
+ .properties input[type="number"]:focus,
153
+ .properties select:focus {
154
+ border-color: var(--primary);
155
+ background: rgba(59, 130, 246, 0.1);
156
+ }
157
+
158
+ .properties input[type="checkbox"] {
159
+ width: 1rem;
160
+ height: 1rem;
161
+ cursor: pointer;
162
+ accent-color: var(--primary);
163
+ }
164
+
165
+ .properties .editor-button {
166
+ padding: 0.25rem 0.5rem;
167
+ background: var(--input);
168
+ border: 1px solid transparent;
169
+ border-radius: var(--radius-sm);
170
+ color: var(--foreground);
171
+ font-size: 0.7rem;
172
+ cursor: pointer;
173
+ transition: all 0.15s ease;
174
+ text-align: center;
175
+ }
176
+
177
+ .properties .editor-button:hover {
178
+ border-color: var(--primary);
179
+ background: rgba(59, 130, 246, 0.1);
92
180
  }
93
181
 
94
182
  .viewportSelector,
95
183
  .themeSelector {
96
184
  user-select: none;
97
- border-right: 1px solid #999;
185
+ background: transparent;
186
+ display: flex;
187
+ flex-direction: column;
188
+ border-right: 1px solid var(--border);
98
189
  }
99
190
  .selectorButtons2 {
100
191
  display: grid;
101
- grid-template-columns: 50% 50%;
192
+ grid-template-columns: 1fr 1fr;
193
+ flex: 1;
102
194
  }
103
195
  .selectorButtons4 {
104
196
  display: grid;
105
- grid-template-columns: 25% 25% 25% 25%;
197
+ grid-template-columns: repeat(4, 1fr);
198
+ flex: 1;
106
199
  }
107
200
  .button {
108
- padding: 10px;
201
+ display: flex;
202
+ flex-direction: column;
203
+ align-items: center;
204
+ justify-content: center;
205
+ padding: 0.5rem 0.25rem;
109
206
  text-align: center;
110
- border: 1px solid #000;
111
- transition: all 0.2s;
207
+ background: transparent;
208
+ border: 1px solid var(--border);
209
+ transition: all 0.15s ease;
210
+ cursor: pointer;
211
+ font-size: 0.65rem;
212
+ gap: 0.2rem;
213
+ color: #999;
112
214
  }
215
+
113
216
  .button:hover {
114
- color: #333;
115
- background: #fff;
217
+ background: rgba(59, 130, 246, 0.05);
218
+ color: #bbb;
116
219
  }
117
220
 
118
221
  .button.selected {
119
- background: #455a64;
222
+ background: rgba(59, 130, 246, 0.15);
223
+ color: var(--primary);
224
+ border-color: rgba(59, 130, 246, 0.3);
120
225
  }
121
226
 
122
227
  .button.selected:hover {
123
- color: #ffffff;
124
- background: #455a64;
228
+ background: rgba(59, 130, 246, 0.2);
229
+ }
230
+
231
+ .button .material-symbols-outlined {
232
+ font-size: 18px;
233
+ font-variation-settings: 'FILL' 0, 'wght' 300;
234
+ }
235
+
236
+ .button.selected .material-symbols-outlined {
237
+ font-variation-settings: 'FILL' 1, 'wght' 400;
125
238
  }
126
239
 
127
240
  .panelheading {
128
- padding: 5px;
129
- font-weight: bold;
130
- background: #444;
131
- border: 1px solid #000;
241
+ padding: 0.3rem 0.5rem;
242
+ font-weight: 500;
243
+ font-size: 0.65rem;
244
+ background: rgba(59, 130, 246, 0.03);
245
+ border-bottom: 1px solid var(--border);
246
+ color: #888;
247
+ text-transform: uppercase;
248
+ letter-spacing: 0.08em;
132
249
  }
133
250
  .docs {
134
- text-align: center;
135
- line-height: 100px;
251
+ display: flex;
252
+ align-items: center;
253
+ justify-content: center;
136
254
  text-transform: uppercase;
255
+ background: transparent;
256
+ cursor: pointer;
257
+ font-size: 0.65rem;
258
+ font-weight: 500;
259
+ letter-spacing: 0.08em;
260
+ transition: all 0.15s ease;
261
+ color: #666;
137
262
  }
138
263
 
139
264
  .docs:hover {
140
- color: #333;
141
- background: #fff;
265
+ background: rgba(59, 130, 246, 0.05);
266
+ color: #999;
142
267
  }
143
268
 
144
269
  .warning {
145
270
  position: absolute;
146
- background: #222;
147
- color: #CCC;
148
- top: 0px;
149
- bottom: 0px;
150
- left: 0px;
151
- right: 520px;
152
- text-align: center;
153
- padding: 35px;
154
- font-size: 25px;
271
+ background: rgba(20, 20, 20, 0.8);
272
+ color: #888;
273
+ top: 0.5rem;
274
+ bottom: 0.5rem;
275
+ left: 0.5rem;
276
+ right: calc(520px + 0.5rem);
277
+ display: flex;
278
+ align-items: center;
279
+ justify-content: center;
280
+ padding: 1.5rem;
281
+ font-size: 0.85rem;
282
+ border-radius: var(--radius-md);
283
+ border: 1px solid var(--border);
284
+ backdrop-filter: blur(8px);
285
+ }
286
+
287
+ .advanced-editor-container {
288
+ position: absolute;
289
+ left: 0;
290
+ right: 0;
291
+ top: 0;
292
+ height: ${this.editorHeight}px;
293
+ background: #050505;
294
+ border-bottom: 1px solid rgba(255, 255, 255, 0.1);
295
+ display: flex;
296
+ flex-direction: column;
297
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
298
+ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.3), 0 2px 4px -1px rgba(0, 0, 0, 0.2);
299
+ }
300
+
301
+ .editor-header-bar {
302
+ padding: 0.5rem 0.75rem;
303
+ background: transparent;
304
+ border-bottom: 1px solid rgba(255, 255, 255, 0.05);
305
+ display: flex;
306
+ justify-content: space-between;
307
+ align-items: center;
308
+ height: 36px;
309
+ }
310
+
311
+ .editor-header-title {
312
+ font-size: 0.7rem;
313
+ font-weight: 500;
314
+ color: #666;
315
+ text-transform: uppercase;
316
+ letter-spacing: 0.08em;
317
+ }
318
+
319
+ .editor-close-all {
320
+ padding: 0.25rem 0.5rem;
321
+ background: transparent;
322
+ border: 1px solid rgba(255, 255, 255, 0.08);
323
+ border-radius: var(--radius-sm);
324
+ color: #999;
325
+ font-size: 0.65rem;
326
+ font-weight: 500;
327
+ cursor: pointer;
328
+ transition: all 0.15s ease;
329
+ }
330
+
331
+ .editor-close-all:hover {
332
+ background: rgba(255, 255, 255, 0.05);
333
+ border-color: rgba(255, 255, 255, 0.12);
334
+ color: #f87171;
335
+ }
336
+
337
+ .editors-container {
338
+ flex: 1;
339
+ display: flex;
340
+ overflow-x: auto;
341
+ overflow-y: hidden;
342
+ gap: 0;
343
+ background: rgba(255, 255, 255, 0.02);
344
+ padding: 0.75rem;
345
+ }
346
+
347
+ .editors-container::-webkit-scrollbar {
348
+ height: 8px;
349
+ }
350
+
351
+ .editors-container::-webkit-scrollbar-track {
352
+ background: rgba(255, 255, 255, 0.02);
353
+ border-radius: 4px;
354
+ }
355
+
356
+ .editors-container::-webkit-scrollbar-thumb {
357
+ background: rgba(255, 255, 255, 0.08);
358
+ border-radius: 4px;
359
+ }
360
+
361
+ .editors-container::-webkit-scrollbar-thumb:hover {
362
+ background: rgba(255, 255, 255, 0.12);
363
+ }
364
+
365
+ .editor-instance {
366
+ min-width: 320px;
367
+ flex: 1;
368
+ max-width: 480px;
369
+ background: rgba(10, 10, 10, 0.6);
370
+ display: flex;
371
+ flex-direction: column;
372
+ border-radius: var(--radius);
373
+ overflow: hidden;
374
+ margin-right: 0.75rem;
375
+ border: 1px solid rgba(255, 255, 255, 0.06);
376
+ transition: all 0.2s ease;
377
+ }
378
+
379
+ .editor-instance:hover {
380
+ border-color: rgba(255, 255, 255, 0.1);
381
+ }
382
+
383
+ .editor-instance:last-child {
384
+ margin-right: 0;
385
+ }
386
+
387
+ .editor-header {
388
+ padding: 0.5rem 0.75rem;
389
+ background: rgba(255, 255, 255, 0.02);
390
+ border-bottom: 1px solid rgba(255, 255, 255, 0.05);
391
+ display: flex;
392
+ justify-content: space-between;
393
+ align-items: center;
394
+ height: 36px;
395
+ }
396
+
397
+ .editor-title {
398
+ font-size: 0.75rem;
399
+ font-weight: 500;
400
+ color: #999;
401
+ overflow: hidden;
402
+ text-overflow: ellipsis;
403
+ white-space: nowrap;
404
+ font-family: 'Consolas', 'Monaco', monospace;
405
+ }
406
+
407
+ .editor-actions {
408
+ display: flex;
409
+ gap: 0.25rem;
410
+ }
411
+
412
+ .editor-button {
413
+ width: 24px;
414
+ height: 24px;
415
+ padding: 0;
416
+ background: transparent;
417
+ border: none;
418
+ color: #666;
419
+ font-size: 1rem;
420
+ cursor: pointer;
421
+ transition: all 0.15s ease;
422
+ border-radius: var(--radius-sm);
423
+ display: flex;
424
+ align-items: center;
425
+ justify-content: center;
426
+ }
427
+
428
+ .editor-button:hover {
429
+ background: rgba(255, 255, 255, 0.05);
430
+ color: #999;
431
+ }
432
+
433
+ .editor-button.primary {
434
+ color: #4ade80;
435
+ }
436
+
437
+ .editor-button.primary:hover {
438
+ background: rgba(74, 222, 128, 0.1);
439
+ }
440
+
441
+ .editor-content {
442
+ flex: 1;
443
+ display: flex;
444
+ flex-direction: column;
445
+ overflow: hidden;
446
+ min-height: 0;
447
+ position: relative;
448
+ }
449
+
450
+ .editor-textarea {
451
+ width: 100%;
452
+ height: 100%;
453
+ background: transparent;
454
+ border: none;
455
+ color: #d0d0d0;
456
+ font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
457
+ font-size: 0.8125rem;
458
+ line-height: 1.6;
459
+ padding: 0.75rem;
460
+ resize: none;
461
+ outline: none;
462
+ transition: all 0.15s ease;
463
+ overflow: auto;
464
+ }
465
+
466
+ .editor-textarea:focus {
467
+ background: rgba(255, 255, 255, 0.01);
468
+ }
469
+
470
+ .editor-textarea::selection {
471
+ background: rgba(59, 130, 246, 0.3);
472
+ }
473
+
474
+ .editor-error {
475
+ position: absolute;
476
+ bottom: 0;
477
+ left: 0;
478
+ right: 0;
479
+ padding: 0.5rem 0.75rem;
480
+ background: rgba(239, 68, 68, 0.9);
481
+ backdrop-filter: blur(4px);
482
+ color: #fff;
483
+ font-size: 0.7rem;
484
+ font-weight: 500;
485
+ display: flex;
486
+ align-items: center;
487
+ gap: 0.375rem;
488
+ border-top: 1px solid rgba(239, 68, 68, 0.5);
489
+ }
490
+
491
+ .editor-error::before {
492
+ content: '!';
493
+ display: inline-flex;
494
+ width: 16px;
495
+ height: 16px;
496
+ align-items: center;
497
+ justify-content: center;
498
+ background: rgba(255, 255, 255, 0.2);
499
+ border-radius: 50%;
500
+ font-size: 0.65rem;
501
+ font-weight: bold;
502
+ }
503
+
504
+ .main-content {
505
+ position: absolute;
506
+ left: 0;
507
+ right: 0;
508
+ bottom: 0;
509
+ height: 100px;
155
510
  }
156
511
  </style>
157
- <div class="grid">
158
- <div class="properties">
159
- <div class="panelheading">Properties</div>
160
- ${this.propertyContent}
161
- </div>
162
- <div class="themeSelector">
163
- <div class="panelheading">Theme</div>
164
- <div class="selectorButtons2">
165
- <div
166
- class="button ${this.selectedTheme === 'dark' ? 'selected' : null}"
167
- @click=${() => {
168
- this.selectTheme('dark');
169
- }}
170
- >
171
- Dark<br /><i class="material-symbols-outlined">brightness_3</i>
172
- </div>
173
- <div
174
- class="button ${this.selectedTheme === 'bright' ? 'selected' : null}"
175
- @click=${() => {
176
- this.selectTheme('bright');
177
- }}
178
- >
179
- Bright<br /><i class="material-symbols-outlined">flare</i>
180
- </div>
512
+ ${this.editingProperties.length > 0 ? html`
513
+ <div class="advanced-editor-container">
514
+ <div class="editor-header-bar">
515
+ <div class="editor-header-title">Property Editors</div>
516
+ <button class="editor-close-all" @click=${this.closeAllEditors}>
517
+ Close All
518
+ </button>
519
+ </div>
520
+ <div class="editors-container">
521
+ ${this.editingProperties.length === 0 ? html`
522
+ <div style="
523
+ flex: 1;
524
+ display: flex;
525
+ align-items: center;
526
+ justify-content: center;
527
+ color: #666;
528
+ font-size: 0.875rem;
529
+ text-align: center;
530
+ padding: 2rem;
531
+ ">
532
+ <div>
533
+ <div style="margin-bottom: 0.5rem; font-size: 1.5rem; opacity: 0.5;">{ }</div>
534
+ <div>No properties being edited</div>
535
+ <div style="font-size: 0.75rem; margin-top: 0.25rem; opacity: 0.7;">Click "Edit Object/Array" buttons to start editing</div>
536
+ </div>
537
+ </div>
538
+ ` : null}
539
+ ${this.editingProperties.map(prop => html`
540
+ <div class="editor-instance">
541
+ <div class="editor-header">
542
+ <div class="editor-title">${prop.name}</div>
543
+ <div class="editor-actions">
544
+ <button class="editor-button" @click=${() => this.handleEditorCancel(prop.id)}>✕</button>
545
+ <button class="editor-button primary" @click=${() => this.handleEditorSave(prop.id)}>✓</button>
546
+ </div>
547
+ </div>
548
+ <div class="editor-content">
549
+ <textarea
550
+ class="editor-textarea"
551
+ .value=${prop.editorValue}
552
+ @input=${(e: InputEvent) => {
553
+ const editor = this.editingProperties.find(p => p.id === prop.id);
554
+ if (editor) {
555
+ editor.editorValue = (e.target as HTMLTextAreaElement).value;
556
+ editor.editorError = '';
557
+ this.requestUpdate();
558
+ }
559
+ }}
560
+ @keydown=${(e: KeyboardEvent) => {
561
+ if (e.key === 'Tab') {
562
+ e.preventDefault();
563
+ const target = e.target as HTMLTextAreaElement;
564
+ const start = target.selectionStart;
565
+ const end = target.selectionEnd;
566
+ const value = target.value;
567
+ target.value = value.substring(0, start) + ' ' + value.substring(end);
568
+ target.selectionStart = target.selectionEnd = start + 2;
569
+ }
570
+ }}
571
+ ></textarea>
572
+ ${prop.editorError ? html`
573
+ <div class="editor-error">${prop.editorError}</div>
574
+ ` : null}
575
+ </div>
576
+ </div>
577
+ `)}
181
578
  </div>
182
579
  </div>
183
- <div class="viewportSelector">
184
- <div class="panelheading">Viewport</div>
185
- <div class="selectorButtons4">
186
- <div
187
- class="button ${this.selectedViewport === 'phone' ? 'selected' : null}"
188
- @click=${() => {
189
- this.selectViewport('phone');
190
- }}
191
- >
192
- Phone<br /><i class="material-symbols-outlined">smartphone</i>
193
- </div>
194
- <div
195
- class="button ${this.selectedViewport === 'phablet' ? 'selected' : null}"
196
- @click=${() => {
197
- this.selectViewport('phablet');
198
- }}
199
- >
200
- Phablet<br /><i class="material-symbols-outlined">smartphone</i>
201
- </div>
202
- <div
203
- class="button ${this.selectedViewport === 'tablet' ? 'selected' : null}"
204
- @click=${() => {
205
- this.selectViewport('tablet');
206
- }}
207
- >
208
- Tablet<br /><i class="material-symbols-outlined">tablet</i>
580
+ ` : null}
581
+ <div class="main-content">
582
+ <div class="grid">
583
+ <div class="properties">
584
+ ${this.propertyContent}
585
+ </div>
586
+ <div class="themeSelector">
587
+ <div class="panelheading">Theme</div>
588
+ <div class="selectorButtons2">
589
+ <div
590
+ class="button ${this.selectedTheme === 'dark' ? 'selected' : null}"
591
+ @click=${() => {
592
+ this.selectTheme('dark');
593
+ }}
594
+ >
595
+ Dark<i class="material-symbols-outlined">brightness_3</i>
596
+ </div>
597
+ <div
598
+ class="button ${this.selectedTheme === 'bright' ? 'selected' : null}"
599
+ @click=${() => {
600
+ this.selectTheme('bright');
601
+ }}
602
+ >
603
+ Bright<i class="material-symbols-outlined">flare</i>
604
+ </div>
209
605
  </div>
210
- <div
211
- class="button ${this.selectedViewport === 'desktop' ||
212
- this.selectedViewport === 'native'
213
- ? 'selected'
214
- : null}"
215
- @click=${() => {
216
- this.selectViewport('native');
217
- }}
218
- >
219
- Desktop<br /><i class="material-symbols-outlined">desktop_windows</i>
606
+ </div>
607
+ <div class="viewportSelector">
608
+ <div class="panelheading">Viewport</div>
609
+ <div class="selectorButtons4">
610
+ <div
611
+ class="button ${this.selectedViewport === 'phone' ? 'selected' : null}"
612
+ @click=${() => {
613
+ this.selectViewport('phone');
614
+ }}
615
+ >
616
+ Phone<i class="material-symbols-outlined">smartphone</i>
617
+ </div>
618
+ <div
619
+ class="button ${this.selectedViewport === 'phablet' ? 'selected' : null}"
620
+ @click=${() => {
621
+ this.selectViewport('phablet');
622
+ }}
623
+ >
624
+ Phablet<i class="material-symbols-outlined">smartphone</i>
625
+ </div>
626
+ <div
627
+ class="button ${this.selectedViewport === 'tablet' ? 'selected' : null}"
628
+ @click=${() => {
629
+ this.selectViewport('tablet');
630
+ }}
631
+ >
632
+ Tablet<i class="material-symbols-outlined">tablet</i>
633
+ </div>
634
+ <div
635
+ class="button ${this.selectedViewport === 'desktop' ||
636
+ this.selectedViewport === 'native'
637
+ ? 'selected'
638
+ : null}"
639
+ @click=${() => {
640
+ this.selectViewport('native');
641
+ }}
642
+ >
643
+ Desktop<i class="material-symbols-outlined">desktop_windows</i>
644
+ </div>
220
645
  </div>
221
646
  </div>
647
+ <div class="docs">Docs</div>
222
648
  </div>
223
- <div class="docs">Docs</div>
649
+ ${this.warning ? html`<div class="warning">${this.warning}</div>` : null}
224
650
  </div>
225
- ${this.warning ? html`<div class="warning">${this.warning}</div>` : null}
226
651
  `;
227
652
  }
228
653
 
@@ -356,7 +781,7 @@ export class WccProperties extends DeesElement {
356
781
  propertyArray.push(
357
782
  html`
358
783
  <div class="property">
359
- ${key} / ${propertyTypeString}<br />
784
+ <div class="property-label">${key} (${propertyTypeString})</div>
360
785
  ${(() => {
361
786
  switch (propertyTypeString) {
362
787
  case 'Boolean':
@@ -401,6 +826,17 @@ export class WccProperties extends DeesElement {
401
826
  `;
402
827
  })}
403
828
  </select>`;
829
+ case 'Object':
830
+ case 'Array':
831
+ return html`<button
832
+ class="editor-button"
833
+ style="width: 100%; margin-top: 0.25rem;"
834
+ @click="${() => this.openAdvancedEditor(key, firstFoundInstantiatedElement[key], firstFoundInstantiatedElement)}"
835
+ >
836
+ Edit ${propertyTypeString}
837
+ </button>`;
838
+ default:
839
+ return html`<div style="color: #666; font-size: 0.7rem;">Unsupported type</div>`;
404
840
  }
405
841
  })()}
406
842
  </div>
@@ -452,4 +888,93 @@ export class WccProperties extends DeesElement {
452
888
  );
453
889
  this.dashboardRef.buildUrl();
454
890
  }
891
+
892
+ private openAdvancedEditor(propertyName: string, value: any, element: HTMLElement) {
893
+ // Check if this property is already being edited
894
+ const existingEditor = this.editingProperties.find(p => p.name === propertyName && p.element === element);
895
+ if (existingEditor) {
896
+ return; // Property is already open for editing
897
+ }
898
+
899
+ const newEditor = {
900
+ id: `${propertyName}-${Date.now()}`,
901
+ name: propertyName,
902
+ value: value,
903
+ element: element,
904
+ editorValue: JSON.stringify(value, null, 2),
905
+ editorError: ''
906
+ };
907
+
908
+ this.editingProperties = [...this.editingProperties, newEditor];
909
+
910
+ // Notify parent to resize frame if this is the first editor
911
+ if (this.editingProperties.length === 1) {
912
+ this.dispatchEvent(
913
+ new CustomEvent('editorStateChanged', {
914
+ detail: { isOpen: true },
915
+ bubbles: true
916
+ })
917
+ );
918
+ }
919
+ }
920
+
921
+ private handleEditorSave(editorId: string) {
922
+ const editor = this.editingProperties.find(p => p.id === editorId);
923
+ if (!editor) return;
924
+
925
+ try {
926
+ const parsedValue = JSON.parse(editor.editorValue);
927
+ editor.element[editor.name] = parsedValue;
928
+
929
+ // Remove this editor from the list
930
+ this.editingProperties = this.editingProperties.filter(p => p.id !== editorId);
931
+
932
+ // If no more editors, notify parent to resize frame
933
+ if (this.editingProperties.length === 0) {
934
+ this.dispatchEvent(
935
+ new CustomEvent('editorStateChanged', {
936
+ detail: { isOpen: false },
937
+ bubbles: true
938
+ })
939
+ );
940
+ }
941
+
942
+ // Refresh properties display
943
+ this.createProperties();
944
+ } catch (error) {
945
+ // Update error for this specific editor
946
+ const editorIndex = this.editingProperties.findIndex(p => p.id === editorId);
947
+ if (editorIndex !== -1) {
948
+ this.editingProperties[editorIndex].editorError = `Invalid JSON: ${error.message}`;
949
+ this.requestUpdate();
950
+ }
951
+ }
952
+ }
953
+
954
+ private handleEditorCancel(editorId: string) {
955
+ // Remove this editor from the list
956
+ this.editingProperties = this.editingProperties.filter(p => p.id !== editorId);
957
+
958
+ // If no more editors, notify parent to resize frame
959
+ if (this.editingProperties.length === 0) {
960
+ this.dispatchEvent(
961
+ new CustomEvent('editorStateChanged', {
962
+ detail: { isOpen: false },
963
+ bubbles: true
964
+ })
965
+ );
966
+ }
967
+ }
968
+
969
+ private closeAllEditors() {
970
+ this.editingProperties = [];
971
+
972
+ // Notify parent to resize frame back
973
+ this.dispatchEvent(
974
+ new CustomEvent('editorStateChanged', {
975
+ detail: { isOpen: false },
976
+ bubbles: true
977
+ })
978
+ );
979
+ }
455
980
  }