@design.estate/dees-wcctools 1.0.101 → 1.1.1

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