slicejs-web-framework 1.0.31 → 1.0.33

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.
@@ -1,3 +1,5 @@
1
+ // ✅ VERSIÓN ANTI-INTERFERENCIA - Aislada del Router y con debugging
2
+
1
3
  export default class Debugger extends HTMLElement {
2
4
  constructor() {
3
5
  super();
@@ -6,12 +8,21 @@ export default class Debugger extends HTMLElement {
6
8
  this.selectedComponentSliceId = null;
7
9
  this.isActive = false;
8
10
  this.activeTab = 'props';
11
+ this.currentComponent = null;
12
+ this.componentProps = {};
13
+ this.currentEditingProp = null;
14
+ this.currentEditingType = null;
15
+
16
+ // ✅ Flag para prevenir interferencias externas
17
+ this.isDebuggerInput = false;
9
18
  }
10
19
 
11
20
  async enableDebugMode() {
12
- // Cargar HTML y CSS desde archivos externos
13
- const html = await slice.controller.fetchText('Debugger', 'html', 'Structural');
14
- const css = await slice.controller.fetchText('Debugger', 'css', 'Structural');
21
+ //const html = await slice.controller.fetchText('Debugger', 'html', 'Structural');
22
+ //const css = await slice.controller.fetchText('Debugger', 'css', 'Structural');
23
+
24
+ const html = productionOnlyHtml();
25
+ const css = productionOnlyCSS();
15
26
 
16
27
  this.innerHTML = html;
17
28
  slice.stylesManager.registerComponentStyles('Debugger', css);
@@ -20,7 +31,7 @@ export default class Debugger extends HTMLElement {
20
31
  this.setupEventListeners();
21
32
  this.makeDraggable();
22
33
 
23
- slice.logger.logInfo('Logger', 'Advanced Debug mode enabled');
34
+ slice.logger.logInfo('Debugger', 'Advanced Debug mode enabled');
24
35
  return true;
25
36
  }
26
37
 
@@ -74,11 +85,13 @@ export default class Debugger extends HTMLElement {
74
85
  });
75
86
 
76
87
  // Action buttons
77
- this.querySelector('#apply-changes').addEventListener('click', () => {
88
+ this.querySelector('#apply-changes')?.addEventListener('click', (e) => {
89
+ e.stopPropagation();
78
90
  this.applyAllChanges();
79
91
  });
80
92
 
81
- this.querySelector('#reset-values').addEventListener('click', () => {
93
+ this.querySelector('#reset-values')?.addEventListener('click', (e) => {
94
+ e.stopPropagation();
82
95
  this.resetValues();
83
96
  });
84
97
 
@@ -94,59 +107,73 @@ export default class Debugger extends HTMLElement {
94
107
  }
95
108
  });
96
109
 
97
- // ✅ SIMPLIFICADO: Solo Enter para aplicar, sin más eventos automáticos
110
+ // ✅ EVENTOS PRINCIPALES - Con protección anti-interferencia
111
+ this.addEventListener('mousedown', (event) => {
112
+ if (event.target.classList.contains('prop-control')) {
113
+ this.isDebuggerInput = true;
114
+ // Prevenir interferencias del Router u otros sistemas
115
+ event.stopPropagation();
116
+ }
117
+ });
118
+
119
+ this.addEventListener('focus', (event) => {
120
+ if (event.target.classList.contains('prop-control')) {
121
+ this.isDebuggerInput = true;
122
+ event.stopPropagation();
123
+ }
124
+ }, true);
125
+
126
+ this.addEventListener('blur', (event) => {
127
+ if (event.target.classList.contains('prop-control')) {
128
+ this.isDebuggerInput = false;
129
+ }
130
+ }, true);
131
+
98
132
  this.addEventListener('keypress', (event) => {
99
133
  if (event.key === 'Enter' && event.target.classList.contains('prop-control')) {
100
134
  event.preventDefault();
135
+ event.stopPropagation();
101
136
  this.applyPropertyChange(event.target);
102
137
  }
103
138
  });
104
139
 
105
- // ✅ SIMPLIFICADO: Solo cambio visual para checkboxes
106
140
  this.addEventListener('change', (event) => {
107
141
  if (event.target.type === 'checkbox' && event.target.classList.contains('prop-control')) {
108
- const span = event.target.nextElementSibling;
109
- if (span) {
110
- span.textContent = event.target.checked ? 'true' : 'false';
111
- }
142
+ event.stopPropagation();
112
143
  this.applyPropertyChange(event.target);
113
144
  }
114
145
  });
115
146
 
116
- // ✅ DEBUG: Agregar logs para entender qué está pasando
147
+ // ✅ PROTECCIÓN GLOBAL: Prevenir que eventos externos interfieran
117
148
  this.addEventListener('click', (event) => {
118
- if (event.target.classList.contains('prop-control')) {
119
- console.log('🎯 Debug: Input clicked', event.target.dataset.prop);
149
+ if (this.contains(event.target)) {
150
+ event.stopPropagation();
120
151
  }
121
152
  });
122
153
 
123
- this.addEventListener('focus', (event) => {
124
- if (event.target.classList.contains('prop-control')) {
125
- console.log('🎯 Debug: Input focused', event.target.dataset.prop);
126
- }
127
- }, true);
128
-
129
- this.addEventListener('blur', (event) => {
130
- if (event.target.classList.contains('prop-control')) {
131
- console.log('🎯 Debug: Input blurred', event.target.dataset.prop);
132
- }
133
- }, true);
154
+ // Los eventos DOMNodeInserted/Removed están deprecated,
155
+ // pero la protección con stopPropagation() ya es suficiente
134
156
  }
135
157
 
136
158
  switchTab(tabName) {
137
159
  this.activeTab = tabName;
138
160
 
139
- // Update tab buttons
140
161
  this.querySelectorAll('.tab-btn').forEach(btn => {
141
162
  btn.classList.toggle('active', btn.dataset.tab === tabName);
142
163
  });
143
164
 
144
- // Update tab panes
145
165
  this.querySelectorAll('.tab-pane').forEach(pane => {
146
166
  pane.classList.toggle('active', pane.id === `${tabName}-tab`);
147
167
  });
148
168
  }
149
169
 
170
+ switchEditorType(type) {
171
+ this.querySelectorAll('.type-btn').forEach(btn => {
172
+ btn.classList.toggle('active', btn.dataset.type === type);
173
+ });
174
+ this.currentEditingType = type;
175
+ }
176
+
150
177
  attachDebugMode(component) {
151
178
  if (this.toggleClick === 'right') {
152
179
  this.toggle = 'contextmenu';
@@ -211,280 +238,278 @@ export default class Debugger extends HTMLElement {
211
238
  }
212
239
  });
213
240
 
241
+ // ✅ Crear UI sin interferencias
214
242
  this.updateDebuggerContent();
215
243
  this.debuggerContainer.classList.add('active');
216
244
  }
217
245
 
218
246
  updateDebuggerContent() {
219
- console.log('🔥 DEBUG: updateDebuggerContent called - this recreates ALL inputs!');
220
- console.trace(); // Esto nos dirá desde dónde se está llamando
221
247
  this.updatePropsTab();
222
248
  this.updateInfoTab();
223
249
  }
224
250
 
225
251
  updatePropsTab() {
226
- console.log('🔥 DEBUG: updatePropsTab called - this recreates props inputs!');
227
- console.trace();
252
+ const propsContainer = this.querySelector('.props-container');
253
+ if (!propsContainer) {
254
+ return;
255
+ }
228
256
 
229
- const component = this.currentComponent;
230
- const ComponentClass = component.constructor;
231
- const hasStaticProps = ComponentClass.props && !slice.isProduction();
232
- const staticProps = ComponentClass.props || {};
233
-
234
- this.propsContainer.innerHTML = '';
257
+ propsContainer.innerHTML = '';
235
258
 
236
- if (hasStaticProps) {
237
- // Enhanced props view
238
- const usedSection = document.createElement('div');
239
- usedSection.className = 'props-section';
240
- usedSection.innerHTML = '<div class="section-title">📋 Component Properties</div>';
259
+ const realComponentProps = this.getComponentPropsForDebugger(this.currentComponent);
260
+ const ComponentClass = this.currentComponent.constructor;
261
+ const configuredProps = ComponentClass.props || {};
241
262
 
242
- Object.entries(staticProps).forEach(([prop, config]) => {
243
- const propItem = this.createPropItem(prop, config, this.componentProps[prop]);
244
- usedSection.appendChild(propItem);
245
- });
263
+ realComponentProps.forEach(prop => {
264
+ const propElement = this.createPropElement(prop, configuredProps[prop]);
265
+ propsContainer.appendChild(propElement);
266
+ });
267
+ }
246
268
 
247
- this.propsContainer.appendChild(usedSection);
269
+ createPropElement(prop, config = {}) {
270
+ const propWrapper = document.createElement('div');
271
+ propWrapper.className = 'prop-item';
272
+ propWrapper.dataset.prop = prop;
273
+
274
+ const currentValue = this.currentComponent[prop];
275
+ const valueType = this.getValueType(currentValue);
276
+
277
+ // Status based on usage
278
+ let status, statusClass;
279
+ if (currentValue !== undefined && currentValue !== null) {
280
+ status = 'Used';
281
+ statusClass = 'status-used';
282
+ } else if (config.required) {
283
+ status = 'Missing';
284
+ statusClass = 'status-missing';
248
285
  } else {
249
- // Legacy props view
250
- const legacySection = document.createElement('div');
251
- legacySection.className = 'props-section';
252
- legacySection.innerHTML = '<div class="section-title">📋 Properties (Legacy)</div>';
253
-
254
- Object.entries(this.componentProps).forEach(([prop, value]) => {
255
- if (value !== null) {
256
- const propItem = this.createLegacyPropItem(prop, value);
257
- legacySection.appendChild(propItem);
258
- }
259
- });
260
-
261
- this.propsContainer.appendChild(legacySection);
286
+ status = 'Optional';
287
+ statusClass = 'status-optional';
262
288
  }
263
- }
264
-
265
- createPropItem(prop, config, value) {
266
- const isUsed = value !== undefined;
267
- const isRequired = config.required;
268
-
269
- const propItem = document.createElement('div');
270
- propItem.className = 'prop-item';
271
-
272
- const statusClass = isRequired && !isUsed ? 'status-missing' :
273
- isUsed ? 'status-used' : 'status-optional';
274
- const statusText = isRequired && !isUsed ? '❌ Missing' :
275
- isUsed ? '✅ Used' : '⚪ Optional';
276
289
 
277
- const inputType = this.getInputType(config.type, value);
278
- const inputHtml = this.createPropertyInput(prop, value, config, inputType);
279
-
280
- propItem.innerHTML = `
290
+ propWrapper.innerHTML = `
281
291
  <div class="prop-header">
282
- <div class="prop-name ${isRequired ? 'required' : ''}">${prop}</div>
283
- <div class="prop-meta">
284
- <span class="prop-type">${config.type || 'any'}</span>
285
- <span class="prop-status ${statusClass}">${statusText}</span>
292
+ <div class="prop-title">
293
+ <strong>${prop}</strong>
294
+ <span class="prop-type">${valueType}</span>
286
295
  </div>
296
+ <div class="prop-status ${statusClass}">${status}</div>
287
297
  </div>
288
- <div class="prop-input">${inputHtml}</div>
289
- ${!isUsed && config.default !== undefined ?
290
- `<div class="default-value">Default: ${JSON.stringify(config.default)}</div>` : ''}
291
- `;
292
-
293
- return propItem;
294
- }
295
-
296
- createLegacyPropItem(prop, value) {
297
- const propItem = document.createElement('div');
298
- propItem.className = 'prop-item';
299
-
300
- const inputType = this.getInputType(typeof value, value);
301
- const inputHtml = this.createPropertyInput(prop, value, null, inputType);
302
-
303
- propItem.innerHTML = `
304
- <div class="prop-header">
305
- <div class="prop-name">${prop}</div>
306
- <div class="prop-meta">
307
- <span class="prop-type">${typeof value}</span>
308
- <span class="prop-status status-used">✅ Used</span>
309
- </div>
298
+ <div class="prop-input">
299
+ ${this.createInputForType(prop, currentValue, valueType, config)}
310
300
  </div>
311
- <div class="prop-input">${inputHtml}</div>
301
+ ${config.default !== undefined ? `<div class="default-value">Default: ${JSON.stringify(config.default)}</div>` : ''}
312
302
  `;
313
303
 
314
- return propItem;
315
- }
316
-
317
- getInputType(type, value) {
318
- if (typeof value === 'object' || type === 'object') return 'object';
319
- if (typeof value === 'function' || type === 'function') return 'function';
320
- if (typeof value === 'boolean' || type === 'boolean') return 'boolean';
321
- if (typeof value === 'number' || type === 'number') return 'number';
322
- return 'text';
304
+ return propWrapper;
323
305
  }
324
306
 
325
- createPropertyInput(prop, value, config, inputType) {
326
- const hasComplexEditor = inputType === 'object' || inputType === 'function';
327
- const displayValue = this.formatValueForDisplay(value);
307
+ createInputForType(prop, value, type, config = {}) {
308
+ const serializedValue = this.serializeValue(value);
328
309
 
329
- if (hasComplexEditor) {
310
+ if (type === 'boolean') {
311
+ return `
312
+ <div class="input-group">
313
+ <input type="checkbox"
314
+ class="prop-control debugger-input"
315
+ data-prop="${prop}"
316
+ ${value ? 'checked' : ''}
317
+ data-debugger-input="true">
318
+ <span class="checkbox-label">${value ? 'true' : 'false'}</span>
319
+ </div>
320
+ `;
321
+ } else if (type === 'number') {
330
322
  return `
331
323
  <div class="input-group">
332
- <input type="text" class="prop-control"
333
- value="${displayValue}"
324
+ <input type="number"
325
+ class="prop-control debugger-input"
334
326
  data-prop="${prop}"
335
- readonly>
336
- <button class="edit-btn" onclick="slice.debugger.openEditor('${prop}', '${inputType}')">✏️</button>
327
+ value="${serializedValue}"
328
+ step="any"
329
+ placeholder="Enter number..."
330
+ data-debugger-input="true">
337
331
  </div>
338
332
  `;
339
- } else if (inputType === 'boolean') {
340
- const checked = value ? 'checked' : '';
333
+ } else if (type === 'object' || type === 'array' || type === 'function') {
341
334
  return `
342
- <label style="display: flex; align-items: center; gap: 8px; cursor: pointer;">
343
- <input type="checkbox" ${checked} data-prop="${prop}" class="prop-control">
344
- <span style="font-size: 13px; color: var(--font-secondary-color);">
345
- ${value ? 'true' : 'false'}
346
- </span>
347
- </label>
335
+ <div class="input-group">
336
+ <input type="text"
337
+ class="prop-control debugger-input"
338
+ data-prop="${prop}"
339
+ value="${serializedValue}"
340
+ readonly
341
+ title="Click edit button to modify"
342
+ data-debugger-input="true">
343
+ <button class="edit-btn" onclick="slice.debugger.openAdvancedEditor('${prop}', '${type}')">✏️</button>
344
+ </div>
348
345
  `;
349
346
  } else {
350
- // ✅ CORREGIDO: Inputs normales SIN readonly para permitir edición
351
347
  return `
352
- <input type="${inputType === 'number' ? 'number' : 'text'}"
353
- class="prop-control"
354
- value="${displayValue}"
355
- data-prop="${prop}"
356
- placeholder="Enter ${inputType} value...">
348
+ <div class="input-group">
349
+ <input type="text"
350
+ class="prop-control debugger-input"
351
+ data-prop="${prop}"
352
+ value="${serializedValue}"
353
+ placeholder="Enter value..."
354
+ data-debugger-input="true">
355
+ </div>
357
356
  `;
358
357
  }
359
358
  }
360
359
 
361
- formatValueForDisplay(value) {
362
- if (value === null || value === undefined) return '';
363
- if (typeof value === 'function') return '[Function]';
364
- if (typeof value === 'object') return JSON.stringify(value);
365
- return String(value);
366
- }
360
+ applyPropertyChange(inputElement) {
361
+ const prop = inputElement.dataset.prop;
362
+ if (!prop) return;
367
363
 
368
- updateInfoTab() {
369
- const component = this.currentComponent;
364
+ let newValue;
370
365
 
371
- const infoItems = [
372
- { label: 'Component Name', value: component.constructor.name },
373
- { label: 'Slice ID', value: component.sliceId },
374
- { label: 'Connected to DOM', value: component.isConnected ? 'Yes' : 'No' },
375
- { label: 'Has Static Props', value: component.constructor.props ? 'Yes' : 'No' },
376
- { label: 'Props Count', value: Object.keys(this.componentProps).length },
377
- { label: 'Custom Element', value: component.tagName.toLowerCase() }
378
- ];
366
+ if (inputElement.type === 'checkbox') {
367
+ newValue = inputElement.checked;
368
+ const label = inputElement.parentNode.querySelector('.checkbox-label');
369
+ if (label) {
370
+ label.textContent = newValue ? 'true' : 'false';
371
+ }
372
+ } else if (inputElement.type === 'number') {
373
+ newValue = Number(inputElement.value);
374
+ } else {
375
+ newValue = inputElement.value;
376
+
377
+ // Convert string values
378
+ if (newValue === 'true') newValue = true;
379
+ if (newValue === 'false') newValue = false;
380
+ if (!isNaN(newValue) && newValue !== '' && newValue !== null) newValue = Number(newValue);
381
+ }
379
382
 
380
- this.infoContainer.innerHTML = infoItems.map(item => `
381
- <div class="info-item">
382
- <div class="info-label">${item.label}</div>
383
- <div class="info-value">${item.value}</div>
384
- </div>
385
- `).join('');
383
+ const oldValue = this.currentComponent[prop];
384
+
385
+ this.currentComponent[prop] = newValue;
386
+ slice.logger.logInfo('Debugger', `Updated ${prop}: ${oldValue} → ${newValue}`);
387
+
388
+ this.showVisualFeedback(inputElement);
386
389
  }
387
390
 
388
- openEditor(prop, type) {
389
- this.currentEditingProp = prop;
390
- this.currentEditingType = type;
391
+ showVisualFeedback(inputElement) {
392
+ const originalBorder = inputElement.style.borderColor;
393
+ const originalBoxShadow = inputElement.style.boxShadow;
391
394
 
392
- const value = this.componentProps[prop];
393
- this.modalTitle.textContent = `Edit ${prop}`;
395
+ inputElement.style.borderColor = '#4CAF50';
396
+ inputElement.style.boxShadow = '0 0 0 2px rgba(76, 175, 80, 0.3)';
394
397
 
395
- // Set editor type
396
- this.querySelectorAll('.type-btn').forEach(btn => {
397
- btn.classList.toggle('active', btn.dataset.type === type);
398
+ setTimeout(() => {
399
+ inputElement.style.borderColor = originalBorder;
400
+ inputElement.style.boxShadow = originalBoxShadow;
401
+ }, 1500);
402
+ }
403
+
404
+ applyAllChanges() {
405
+ const inputs = this.querySelectorAll('.prop-control:not([readonly])');
406
+ let changeCount = 0;
407
+
408
+ inputs.forEach(input => {
409
+ if (!input.readOnly) {
410
+ this.applyPropertyChange(input);
411
+ changeCount++;
412
+ }
398
413
  });
399
414
 
400
- // Set editor content
401
- if (type === 'function') {
402
- this.propertyEditor.value = typeof value === 'function' ?
403
- value.toString() : 'function() {\n // Your code here\n}';
415
+ slice.logger.logInfo('Debugger', `Applied ${changeCount} property changes`);
416
+ this.showApplyFeedback(changeCount);
417
+ }
418
+
419
+ showApplyFeedback(changeCount) {
420
+ const applyBtn = this.querySelector('#apply-changes');
421
+ if (!applyBtn) return;
422
+
423
+ const originalText = applyBtn.textContent;
424
+
425
+ if (changeCount > 0) {
426
+ applyBtn.textContent = `✅ Applied ${changeCount} changes!`;
427
+ applyBtn.style.background = '#4CAF50';
404
428
  } else {
405
- this.propertyEditor.value = JSON.stringify(value, null, 2);
429
+ applyBtn.textContent = '✅ No changes to apply';
430
+ applyBtn.style.background = '#9E9E9E';
406
431
  }
407
-
408
- this.editorModal.classList.add('active');
409
- this.propertyEditor.focus();
410
- this.validateEditor();
432
+
433
+ setTimeout(() => {
434
+ applyBtn.textContent = originalText;
435
+ applyBtn.style.background = '';
436
+ }, 2000);
411
437
  }
412
438
 
413
- switchEditorType(type) {
439
+ openAdvancedEditor(prop, type) {
440
+ this.currentEditingProp = prop;
414
441
  this.currentEditingType = type;
415
442
 
443
+ const value = this.currentComponent[prop];
444
+
445
+ this.modalTitle.textContent = `Edit ${prop} (${type})`;
446
+
416
447
  this.querySelectorAll('.type-btn').forEach(btn => {
417
448
  btn.classList.toggle('active', btn.dataset.type === type);
418
449
  });
419
-
420
- const value = this.componentProps[this.currentEditingProp];
421
450
 
422
451
  if (type === 'function') {
423
- this.propertyEditor.value = typeof value === 'function' ?
424
- value.toString() : 'function() {\n // Your code here\n}';
452
+ if (typeof value === 'function') {
453
+ this.propertyEditor.value = value.toString();
454
+ } else {
455
+ this.propertyEditor.value = 'function() {\n // Your code here\n}';
456
+ }
425
457
  } else {
426
458
  this.propertyEditor.value = JSON.stringify(value, null, 2);
427
459
  }
428
460
 
429
- this.validateEditor();
461
+ this.editorModal.classList.add('active');
462
+ this.propertyEditor.focus();
430
463
  }
431
464
 
432
465
  validateEditor() {
433
- const content = this.propertyEditor.value;
434
- const saveBtn = this.querySelector('#modal-save');
466
+ const value = this.propertyEditor.value.trim();
467
+ const type = this.currentEditingType;
435
468
 
436
469
  try {
437
- if (this.currentEditingType === 'function') {
438
- // Basic function validation
439
- if (content.trim().startsWith('function') || content.trim().startsWith('(') || content.includes('=>')) {
440
- new Function('return ' + content);
441
- this.validationMessage.textContent = '✅ Valid function syntax';
442
- this.validationMessage.style.color = 'var(--success-color)';
443
- saveBtn.disabled = false;
444
- } else {
445
- throw new Error('Invalid function syntax');
446
- }
470
+ if (type === 'function') {
471
+ new Function('return ' + value)();
447
472
  } else {
448
- JSON.parse(content);
449
- this.validationMessage.textContent = '✅ Valid JSON';
450
- this.validationMessage.style.color = 'var(--success-color)';
451
- saveBtn.disabled = false;
473
+ JSON.parse(value);
452
474
  }
475
+
476
+ this.validationMessage.textContent = '✅ Valid syntax';
477
+ this.validationMessage.style.color = '#4CAF50';
478
+ this.querySelector('#modal-save').disabled = false;
453
479
  } catch (error) {
454
480
  this.validationMessage.textContent = `❌ ${error.message}`;
455
- this.validationMessage.style.color = 'var(--danger-color)';
456
- saveBtn.disabled = true;
481
+ this.validationMessage.style.color = '#F44336';
482
+ this.querySelector('#modal-save').disabled = true;
457
483
  }
458
484
  }
459
485
 
460
486
  savePropertyValue() {
461
- const content = this.propertyEditor.value;
487
+ const value = this.propertyEditor.value.trim();
488
+ const type = this.currentEditingType;
462
489
 
463
490
  try {
464
491
  let newValue;
465
492
 
466
- if (this.currentEditingType === 'function') {
467
- newValue = new Function('return ' + content)();
493
+ if (type === 'function') {
494
+ newValue = new Function('return ' + value)();
468
495
  } else {
469
- newValue = JSON.parse(content);
496
+ newValue = JSON.parse(value);
470
497
  }
471
-
472
- // Update component property
473
- this.currentComponent[this.currentEditingProp] = newValue;
474
- this.componentProps[this.currentEditingProp] = newValue;
475
498
 
476
- // CORREGIDO: Solo actualizar UI después de cerrar modal
499
+ this.currentComponent[this.currentEditingProp] = newValue;
477
500
  this.closeModal();
478
501
 
479
- // ✅ Recrear props solo después de editar objeto/función (necesario)
480
- setTimeout(() => {
481
- this.updatePropsTab();
482
- }, 50);
483
-
484
502
  slice.logger.logInfo('Debugger', `Updated ${this.currentEditingProp} via advanced editor`);
503
+
504
+ const input = this.querySelector(`[data-prop="${this.currentEditingProp}"]`);
505
+ if (input) {
506
+ input.value = this.serializeValue(newValue);
507
+ this.showVisualFeedback(input);
508
+ }
509
+
485
510
  } catch (error) {
486
511
  this.validationMessage.textContent = `❌ ${error.message}`;
487
- this.validationMessage.style.color = 'var(--danger-color)';
512
+ this.validationMessage.style.color = '#F44336';
488
513
  }
489
514
  }
490
515
 
@@ -495,121 +520,96 @@ export default class Debugger extends HTMLElement {
495
520
  this.validationMessage.textContent = '';
496
521
  }
497
522
 
498
- // ✅ NUEVO: Aplicar cambio de una propiedad específica SIN tocar UI
499
- applyPropertyChange(inputElement) {
500
- const prop = inputElement.dataset.prop;
501
- if (!prop) return;
502
-
503
- let newValue;
504
-
505
- if (inputElement.type === 'checkbox') {
506
- newValue = inputElement.checked;
507
- } else if (inputElement.type === 'number') {
508
- newValue = Number(inputElement.value);
509
- } else {
510
- newValue = inputElement.value;
511
-
512
- // Convert string values
513
- if (newValue === 'true') newValue = true;
514
- if (newValue === 'false') newValue = false;
515
- if (!isNaN(newValue) && newValue !== '') newValue = Number(newValue);
516
- }
517
-
518
- const oldValue = this.currentComponent[prop];
519
-
520
- if (JSON.stringify(newValue) !== JSON.stringify(oldValue)) {
521
- this.currentComponent[prop] = newValue;
522
- slice.logger.logInfo('Debugger', `Updated ${prop}: ${oldValue} → ${newValue}`);
523
- }
524
- }
525
-
526
- // ✅ SIMPLIFICADO: Solo para el botón Apply Changes
527
- applyAllChanges() {
528
- const inputs = this.propsContainer.querySelectorAll('.prop-control');
529
- let changesCount = 0;
530
-
531
- inputs.forEach(input => {
532
- const prop = input.dataset.prop;
533
- if (!prop) return;
534
-
535
- let newValue;
536
-
537
- if (input.type === 'checkbox') {
538
- newValue = input.checked;
539
- } else if (input.type === 'number') {
540
- newValue = Number(input.value);
541
- } else {
542
- newValue = input.value;
543
-
544
- if (newValue === 'true') newValue = true;
545
- if (newValue === 'false') newValue = false;
546
- if (!isNaN(newValue) && newValue !== '') newValue = Number(newValue);
547
- }
548
-
549
- const oldValue = this.currentComponent[prop];
550
-
551
- if (JSON.stringify(newValue) !== JSON.stringify(oldValue)) {
552
- this.currentComponent[prop] = newValue;
553
- changesCount++;
554
- }
555
- });
556
-
557
- slice.logger.logInfo('Debugger', `Applied ${changesCount} changes via button`);
558
-
559
- if (changesCount > 0) {
560
- this.showApplyFeedback(changesCount);
561
- }
562
- }
563
-
564
- // ✅ NUEVO: Mostrar feedback visual
565
- showApplyFeedback(changesCount) {
566
- const applyBtn = this.querySelector('#apply-changes');
567
- const originalText = applyBtn.textContent;
568
-
569
- applyBtn.textContent = `✅ Applied ${changesCount} changes!`;
570
- applyBtn.style.background = 'var(--success-color)';
571
-
572
- setTimeout(() => {
573
- applyBtn.textContent = originalText;
574
- applyBtn.style.background = 'var(--primary-color)';
575
- }, 1500);
576
- }
577
-
578
523
  resetValues() {
579
524
  const ComponentClass = this.currentComponent.constructor;
580
- const staticProps = ComponentClass.props || {};
525
+ const configuredProps = ComponentClass.props || {};
581
526
  let resetCount = 0;
582
527
 
583
- Object.entries(staticProps).forEach(([prop, config]) => {
528
+ Object.entries(configuredProps).forEach(([prop, config]) => {
584
529
  if (config.default !== undefined) {
585
530
  this.currentComponent[prop] = config.default;
586
- resetCount++;
531
+
532
+ const input = this.querySelector(`[data-prop="${prop}"]`);
533
+ if (input && !input.readOnly) {
534
+ if (input.type === 'checkbox') {
535
+ input.checked = config.default;
536
+ const label = input.parentNode.querySelector('.checkbox-label');
537
+ if (label) {
538
+ label.textContent = config.default ? 'true' : 'false';
539
+ }
540
+ } else {
541
+ input.value = this.serializeValue(config.default);
542
+ }
543
+ resetCount++;
544
+ }
587
545
  }
588
546
  });
589
547
 
590
548
  slice.logger.logInfo('Debugger', 'Reset values to defaults');
591
-
592
- // ✅ CORREGIDO: Solo recrear UI después del reset (necesario)
593
- if (resetCount > 0) {
594
- this.updatePropsTab(); // Necesario para mostrar los nuevos valores
595
- this.showResetFeedback(resetCount);
596
- }
549
+ this.showResetFeedback(resetCount);
597
550
  }
598
551
 
599
- // ✅ NUEVO: Mostrar feedback visual para reset
600
552
  showResetFeedback(resetCount) {
601
553
  const resetBtn = this.querySelector('#reset-values');
554
+ if (!resetBtn) return;
555
+
602
556
  const originalText = resetBtn.textContent;
603
557
 
604
558
  resetBtn.textContent = `🔄 Reset ${resetCount} values!`;
605
- resetBtn.style.background = 'var(--warning-color)';
559
+ resetBtn.style.background = '#FF9800';
606
560
 
607
561
  setTimeout(() => {
608
562
  resetBtn.textContent = originalText;
609
- resetBtn.style.background = 'var(--secondary-color)';
563
+ resetBtn.style.background = '';
610
564
  }, 1500);
611
565
  }
612
566
 
567
+ updateInfoTab() {
568
+ const infoContainer = this.querySelector('.info-list');
569
+ if (!infoContainer) return;
570
+
571
+ const component = this.currentComponent;
572
+
573
+ const info = [
574
+ { label: 'Component Type', value: component.constructor.name },
575
+ { label: 'Slice ID', value: component.sliceId || 'Not assigned' },
576
+ { label: 'Tag Name', value: component.tagName },
577
+ { label: 'Connected', value: component.isConnected ? 'Yes' : 'No' },
578
+ { label: 'Props Count', value: Object.keys(this.componentProps).length },
579
+ { label: 'Children', value: component.children.length }
580
+ ];
581
+
582
+ infoContainer.innerHTML = info.map(item => `
583
+ <div class="info-item">
584
+ <span class="info-label">${item.label}</span>
585
+ <span class="info-value">${item.value}</span>
586
+ </div>
587
+ `).join('');
588
+ }
589
+
590
+ getValueType(value) {
591
+ if (value === null) return 'null';
592
+ if (value === undefined) return 'undefined';
593
+ if (Array.isArray(value)) return 'array';
594
+ return typeof value;
595
+ }
596
+
597
+ serializeValue(value) {
598
+ if (value === null || value === undefined) {
599
+ return '';
600
+ }
601
+
602
+ if (typeof value === 'object' || typeof value === 'function') {
603
+ try {
604
+ return JSON.stringify(value);
605
+ } catch {
606
+ return String(value);
607
+ }
608
+ }
609
+
610
+ return String(value);
611
+ }
612
+
613
613
  getComponentPropsForDebugger(component) {
614
614
  const ComponentClass = component.constructor;
615
615
 
@@ -643,4 +643,706 @@ export default class Debugger extends HTMLElement {
643
643
  }
644
644
  }
645
645
 
646
- customElements.define('slice-debugger', Debugger);
646
+ customElements.define('slice-debugger', Debugger);
647
+
648
+ function productionOnlyCSS(){
649
+ return `
650
+ #debugger-container {
651
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
652
+ display: none;
653
+ position: fixed;
654
+ top: 20px;
655
+ right: 20px;
656
+ width: 420px;
657
+ height: 85vh;
658
+ max-height: 85vh;
659
+ background: var(--primary-background-color);
660
+ border: 1px solid var(--medium-color);
661
+ border-radius: 12px;
662
+ box-shadow: 0 20px 40px rgba(var(--primary-color-rgb), 0.15), 0 4px 12px rgba(0, 0, 0, 0.1);
663
+ z-index: 10000;
664
+ overflow: hidden;
665
+ backdrop-filter: blur(10px);
666
+ }
667
+
668
+ #debugger-container.active {
669
+ display: flex;
670
+ flex-direction: column;
671
+ }
672
+
673
+ .debugger-header {
674
+ background: linear-gradient(135deg, var(--primary-color), var(--primary-color-shade));
675
+ color: var(--primary-color-contrast);
676
+ padding: 12px 16px;
677
+ border-radius: 12px 12px 0 0;
678
+ user-select: none;
679
+ cursor: grab;
680
+ }
681
+
682
+ .debugger-header:active {
683
+ cursor: grabbing;
684
+ }
685
+
686
+ .header-content {
687
+ display: flex;
688
+ justify-content: space-between;
689
+ align-items: center;
690
+ }
691
+
692
+ .component-info {
693
+ display: flex;
694
+ align-items: center;
695
+ gap: 10px;
696
+ }
697
+
698
+ .component-icon {
699
+ font-size: 20px;
700
+ opacity: 0.9;
701
+ }
702
+
703
+ .component-name {
704
+ font-size: 14px;
705
+ font-weight: 600;
706
+ margin-bottom: 2px;
707
+ }
708
+
709
+ .component-id {
710
+ font-size: 11px;
711
+ opacity: 0.8;
712
+ }
713
+
714
+ .header-actions {
715
+ display: flex;
716
+ gap: 8px;
717
+ }
718
+
719
+ .minimize-btn, #close-debugger {
720
+ background: rgba(255, 255, 255, 0.2);
721
+ border: none;
722
+ color: var(--primary-color-contrast);
723
+ width: 28px;
724
+ height: 28px;
725
+ border-radius: 6px;
726
+ cursor: pointer;
727
+ display: flex;
728
+ align-items: center;
729
+ justify-content: center;
730
+ font-size: 16px;
731
+ font-weight: bold;
732
+ transition: background 0.2s ease;
733
+ }
734
+
735
+ .minimize-btn:hover, #close-debugger:hover {
736
+ background: rgba(255, 255, 255, 0.3);
737
+ }
738
+
739
+ .debugger-content {
740
+ flex: 1;
741
+ display: flex;
742
+ flex-direction: column;
743
+ overflow: hidden;
744
+ }
745
+
746
+ .tabs-container {
747
+ border-bottom: 1px solid var(--medium-color);
748
+ }
749
+
750
+ .tab-nav {
751
+ display: flex;
752
+ background: var(--tertiary-background-color);
753
+ }
754
+
755
+ .tab-btn {
756
+ flex: 1;
757
+ padding: 10px 14px;
758
+ border: none;
759
+ background: transparent;
760
+ color: var(--font-secondary-color);
761
+ font-size: 12px;
762
+ font-weight: 500;
763
+ cursor: pointer;
764
+ transition: all 0.2s ease;
765
+ border-bottom: 2px solid transparent;
766
+ }
767
+
768
+ .tab-btn:hover {
769
+ background: var(--secondary-background-color);
770
+ color: var(--font-primary-color);
771
+ }
772
+
773
+ .tab-btn.active {
774
+ background: var(--primary-background-color);
775
+ color: var(--primary-color);
776
+ border-bottom-color: var(--primary-color);
777
+ font-weight: 600;
778
+ }
779
+
780
+ .tab-content {
781
+ flex: 1;
782
+ overflow: hidden;
783
+ height: calc(85vh - 100px);
784
+ }
785
+
786
+ .tab-pane {
787
+ display: none;
788
+ height: 100%;
789
+ overflow-y: auto;
790
+ overflow-x: hidden;
791
+ padding: 16px;
792
+ }
793
+
794
+ .tab-pane.active {
795
+ display: block;
796
+ }
797
+
798
+ .tab-pane::-webkit-scrollbar {
799
+ width: 4px;
800
+ }
801
+
802
+ .tab-pane::-webkit-scrollbar-track {
803
+ background: var(--tertiary-background-color);
804
+ border-radius: 2px;
805
+ }
806
+
807
+ .tab-pane::-webkit-scrollbar-thumb {
808
+ background: var(--medium-color);
809
+ border-radius: 2px;
810
+ }
811
+
812
+ .tab-pane::-webkit-scrollbar-thumb:hover {
813
+ background: var(--primary-color);
814
+ }
815
+
816
+ .props-container {
817
+ display: flex;
818
+ flex-direction: column;
819
+ gap: 12px;
820
+ margin-bottom: 16px;
821
+ }
822
+
823
+ .props-actions {
824
+ border-top: 1px solid var(--medium-color);
825
+ padding-top: 16px;
826
+ margin-top: 8px;
827
+ }
828
+
829
+ .actions-note {
830
+ margin-top: 12px;
831
+ padding: 8px 12px;
832
+ background: var(--tertiary-background-color);
833
+ border-radius: 6px;
834
+ border: 1px solid var(--medium-color);
835
+ }
836
+
837
+ .actions-note small {
838
+ color: var(--font-secondary-color);
839
+ font-size: 11px;
840
+ display: flex;
841
+ align-items: center;
842
+ gap: 6px;
843
+ }
844
+
845
+ .props-section {
846
+ background: var(--tertiary-background-color);
847
+ border: 1px solid var(--medium-color);
848
+ border-radius: 8px;
849
+ padding: 12px;
850
+ }
851
+
852
+ .section-title {
853
+ font-size: 12px;
854
+ font-weight: 600;
855
+ color: var(--font-primary-color);
856
+ margin-bottom: 12px;
857
+ display: flex;
858
+ align-items: center;
859
+ gap: 6px;
860
+ }
861
+
862
+ .prop-item {
863
+ display: flex;
864
+ flex-direction: column;
865
+ gap: 6px;
866
+ padding: 12px;
867
+ background: var(--primary-background-color);
868
+ border: 1px solid var(--medium-color);
869
+ border-radius: 6px;
870
+ margin-bottom: 8px;
871
+ transition: border-color 0.2s ease;
872
+ }
873
+
874
+ .prop-item:hover {
875
+ border-color: var(--primary-color);
876
+ }
877
+
878
+ .prop-header {
879
+ display: flex;
880
+ justify-content: space-between;
881
+ align-items: center;
882
+ }
883
+
884
+ .prop-name {
885
+ font-size: 13px;
886
+ font-weight: 600;
887
+ color: var(--font-primary-color);
888
+ }
889
+
890
+ .prop-name.required::after {
891
+ content: " *";
892
+ color: var(--danger-color);
893
+ }
894
+
895
+ .prop-meta {
896
+ display: flex;
897
+ align-items: center;
898
+ gap: 8px;
899
+ }
900
+
901
+ .prop-type {
902
+ font-size: 11px;
903
+ padding: 2px 6px;
904
+ background: var(--secondary-color);
905
+ color: var(--secondary-color-contrast);
906
+ border-radius: 4px;
907
+ font-family: monospace;
908
+ font-weight: 500;
909
+ }
910
+
911
+ .prop-status {
912
+ font-size: 12px;
913
+ font-weight: 500;
914
+ }
915
+
916
+ .status-used {
917
+ color: var(--success-color);
918
+ }
919
+
920
+ .status-missing {
921
+ color: var(--danger-color);
922
+ }
923
+
924
+ .status-optional {
925
+ color: var(--medium-color);
926
+ }
927
+
928
+ .prop-input {
929
+ margin-top: 8px;
930
+ }
931
+
932
+ .input-group {
933
+ position: relative;
934
+ }
935
+
936
+ .prop-control {
937
+ width: 100%;
938
+ padding: 8px 32px 8px 10px;
939
+ border: 1px solid var(--medium-color);
940
+ border-radius: 6px;
941
+ background: var(--primary-background-color);
942
+ color: var(--font-primary-color);
943
+ font-size: 13px;
944
+ transition: border-color 0.2s ease, box-shadow 0.2s ease;
945
+ font-family: monospace;
946
+ }
947
+
948
+ .prop-control:focus {
949
+ outline: none;
950
+ border-color: var(--primary-color);
951
+ box-shadow: 0 0 0 3px rgba(var(--primary-color-rgb), 0.1);
952
+ }
953
+
954
+ .prop-control:disabled {
955
+ background: var(--disabled-color);
956
+ color: var(--font-secondary-color);
957
+ cursor: not-allowed;
958
+ }
959
+
960
+ .prop-control[readonly] {
961
+ background: var(--tertiary-background-color);
962
+ cursor: pointer;
963
+ }
964
+
965
+ .prop-control[readonly]:focus {
966
+ border-color: var(--accent-color);
967
+ box-shadow: 0 0 0 3px rgba(var(--accent-color), 0.1);
968
+ }
969
+
970
+ /* Estilos específicos para checkboxes */
971
+ .prop-control[type="checkbox"] {
972
+ width: auto;
973
+ padding: 0;
974
+ margin: 0;
975
+ cursor: pointer;
976
+ }
977
+
978
+ .edit-btn {
979
+ position: absolute;
980
+ right: 4px;
981
+ top: 50%;
982
+ transform: translateY(-50%);
983
+ background: var(--accent-color);
984
+ border: none;
985
+ color: white;
986
+ width: 24px;
987
+ height: 24px;
988
+ border-radius: 4px;
989
+ cursor: pointer;
990
+ font-size: 12px;
991
+ display: flex;
992
+ align-items: center;
993
+ justify-content: center;
994
+ transition: background 0.2s ease;
995
+ }
996
+
997
+ .edit-btn:hover {
998
+ background: var(--primary-color);
999
+ }
1000
+
1001
+ .default-value {
1002
+ font-size: 11px;
1003
+ color: var(--font-secondary-color);
1004
+ font-style: italic;
1005
+ margin-top: 4px;
1006
+ }
1007
+
1008
+ .info-list {
1009
+ display: flex;
1010
+ flex-direction: column;
1011
+ gap: 12px;
1012
+ }
1013
+
1014
+ .info-item {
1015
+ display: flex;
1016
+ justify-content: space-between;
1017
+ padding: 12px;
1018
+ background: var(--tertiary-background-color);
1019
+ border-radius: 6px;
1020
+ border: 1px solid var(--medium-color);
1021
+ }
1022
+
1023
+ .info-label {
1024
+ font-weight: 600;
1025
+ color: var(--font-primary-color);
1026
+ font-size: 13px;
1027
+ }
1028
+
1029
+ .info-value {
1030
+ color: var(--font-secondary-color);
1031
+ font-family: monospace;
1032
+ font-size: 12px;
1033
+ }
1034
+
1035
+ .actions-container {
1036
+ display: flex;
1037
+ flex-direction: column;
1038
+ gap: 16px;
1039
+ }
1040
+
1041
+ .action-buttons {
1042
+ display: flex;
1043
+ flex-direction: column;
1044
+ gap: 8px;
1045
+ }
1046
+
1047
+ .action-btn {
1048
+ padding: 12px 16px;
1049
+ border: none;
1050
+ border-radius: 6px;
1051
+ font-size: 13px;
1052
+ font-weight: 500;
1053
+ cursor: pointer;
1054
+ transition: all 0.2s ease;
1055
+ display: flex;
1056
+ align-items: center;
1057
+ justify-content: center;
1058
+ gap: 8px;
1059
+ }
1060
+
1061
+ .action-btn.primary {
1062
+ background: var(--primary-color);
1063
+ color: var(--primary-color-contrast);
1064
+ }
1065
+
1066
+ .action-btn.primary:hover {
1067
+ background: var(--primary-color-shade);
1068
+ }
1069
+
1070
+ .action-btn.secondary {
1071
+ background: var(--secondary-color);
1072
+ color: var(--secondary-color-contrast);
1073
+ }
1074
+
1075
+ .action-btn.secondary:hover {
1076
+ opacity: 0.9;
1077
+ }
1078
+
1079
+ .action-btn.tertiary {
1080
+ background: var(--tertiary-background-color);
1081
+ color: var(--font-primary-color);
1082
+ border: 1px solid var(--medium-color);
1083
+ }
1084
+
1085
+ .action-btn.tertiary:hover {
1086
+ background: var(--secondary-background-color);
1087
+ }
1088
+
1089
+ /* Modal Styles */
1090
+ .editor-modal {
1091
+ display: none;
1092
+ position: fixed;
1093
+ top: 0;
1094
+ left: 0;
1095
+ width: 100%;
1096
+ height: 100%;
1097
+ background: rgba(0, 0, 0, 0.6);
1098
+ z-index: 20000;
1099
+ backdrop-filter: blur(4px);
1100
+ }
1101
+
1102
+ .editor-modal.active {
1103
+ display: flex;
1104
+ align-items: center;
1105
+ justify-content: center;
1106
+ }
1107
+
1108
+ .modal-content {
1109
+ background: var(--primary-background-color);
1110
+ border-radius: 12px;
1111
+ width: 90%;
1112
+ max-width: 600px;
1113
+ max-height: 80%;
1114
+ display: flex;
1115
+ flex-direction: column;
1116
+ box-shadow: 0 25px 50px rgba(0, 0, 0, 0.25);
1117
+ border: 1px solid var(--medium-color);
1118
+ }
1119
+
1120
+ .modal-header {
1121
+ padding: 16px 20px;
1122
+ background: var(--tertiary-background-color);
1123
+ border-radius: 12px 12px 0 0;
1124
+ border-bottom: 1px solid var(--medium-color);
1125
+ display: flex;
1126
+ justify-content: space-between;
1127
+ align-items: center;
1128
+ }
1129
+
1130
+ .modal-header h3 {
1131
+ margin: 0;
1132
+ font-size: 16px;
1133
+ font-weight: 600;
1134
+ color: var(--font-primary-color);
1135
+ }
1136
+
1137
+ .modal-close {
1138
+ background: none;
1139
+ border: none;
1140
+ font-size: 20px;
1141
+ color: var(--font-secondary-color);
1142
+ cursor: pointer;
1143
+ width: 32px;
1144
+ height: 32px;
1145
+ border-radius: 6px;
1146
+ display: flex;
1147
+ align-items: center;
1148
+ justify-content: center;
1149
+ transition: background 0.2s ease;
1150
+ }
1151
+
1152
+ .modal-close:hover {
1153
+ background: var(--secondary-background-color);
1154
+ }
1155
+
1156
+ .modal-body {
1157
+ flex: 1;
1158
+ padding: 20px;
1159
+ display: flex;
1160
+ flex-direction: column;
1161
+ gap: 16px;
1162
+ overflow: hidden;
1163
+ }
1164
+
1165
+ .editor-type-selector {
1166
+ display: flex;
1167
+ gap: 4px;
1168
+ background: var(--tertiary-background-color);
1169
+ padding: 4px;
1170
+ border-radius: 6px;
1171
+ }
1172
+
1173
+ .type-btn {
1174
+ flex: 1;
1175
+ padding: 8px 12px;
1176
+ border: none;
1177
+ background: transparent;
1178
+ color: var(--font-secondary-color);
1179
+ font-size: 12px;
1180
+ font-weight: 500;
1181
+ cursor: pointer;
1182
+ border-radius: 4px;
1183
+ transition: all 0.2s ease;
1184
+ }
1185
+
1186
+ .type-btn.active {
1187
+ background: var(--primary-color);
1188
+ color: var(--primary-color-contrast);
1189
+ }
1190
+
1191
+ .editor-container {
1192
+ flex: 1;
1193
+ position: relative;
1194
+ min-height: 200px;
1195
+ }
1196
+
1197
+ #property-editor {
1198
+ width: 100%;
1199
+ height: 100%;
1200
+ border: 1px solid var(--medium-color);
1201
+ border-radius: 6px;
1202
+ padding: 12px;
1203
+ background: var(--primary-background-color);
1204
+ color: var(--font-primary-color);
1205
+ font-family: 'Monaco', 'Consolas', monospace;
1206
+ font-size: 13px;
1207
+ line-height: 1.5;
1208
+ resize: none;
1209
+ outline: none;
1210
+ min-height: 200px;
1211
+ }
1212
+
1213
+ #property-editor:focus {
1214
+ border-color: var(--primary-color);
1215
+ box-shadow: 0 0 0 3px rgba(var(--primary-color-rgb), 0.1);
1216
+ }
1217
+
1218
+ .validation-message {
1219
+ font-size: 12px;
1220
+ color: var(--danger-color);
1221
+ min-height: 18px;
1222
+ display: flex;
1223
+ align-items: center;
1224
+ gap: 6px;
1225
+ }
1226
+
1227
+ .modal-actions {
1228
+ padding: 16px 20px;
1229
+ background: var(--tertiary-background-color);
1230
+ border-radius: 0 0 12px 12px;
1231
+ border-top: 1px solid var(--medium-color);
1232
+ display: flex;
1233
+ gap: 12px;
1234
+ justify-content: flex-end;
1235
+ }
1236
+
1237
+ .modal-btn {
1238
+ padding: 10px 20px;
1239
+ border: none;
1240
+ border-radius: 6px;
1241
+ font-size: 13px;
1242
+ font-weight: 500;
1243
+ cursor: pointer;
1244
+ transition: all 0.2s ease;
1245
+ }
1246
+
1247
+ .modal-btn.cancel {
1248
+ background: var(--tertiary-background-color);
1249
+ color: var(--font-primary-color);
1250
+ border: 1px solid var(--medium-color);
1251
+ }
1252
+
1253
+ .modal-btn.cancel:hover {
1254
+ background: var(--secondary-background-color);
1255
+ }
1256
+
1257
+ .modal-btn.save {
1258
+ background: var(--success-color);
1259
+ color: var(--success-contrast);
1260
+ }
1261
+
1262
+ .modal-btn.save:hover {
1263
+ opacity: 0.9;
1264
+ }
1265
+
1266
+ .modal-btn.save:disabled {
1267
+ background: var(--disabled-color);
1268
+ cursor: not-allowed;
1269
+ }
1270
+ `
1271
+ }
1272
+
1273
+ function productionOnlyHtml(){
1274
+ return `
1275
+ <div id="debugger-container">
1276
+ <div class="debugger-header">
1277
+ <div class="header-content">
1278
+ <div class="component-info">
1279
+ <div class="component-icon">🔍</div>
1280
+ <div class="component-details">
1281
+ <div class="component-name">Component Inspector</div>
1282
+ <div class="component-id">Ready to debug</div>
1283
+ </div>
1284
+ </div>
1285
+ <div class="header-actions">
1286
+ <button class="minimize-btn" title="Minimize">−</button>
1287
+ <button id="close-debugger" title="Close">×</button>
1288
+ </div>
1289
+ </div>
1290
+ </div>
1291
+
1292
+ <div class="debugger-content">
1293
+ <div class="tabs-container">
1294
+ <div class="tab-nav">
1295
+ <button class="tab-btn active" data-tab="props">📋 Props</button>
1296
+ <button class="tab-btn" data-tab="info">ℹ️ Info</button>
1297
+ </div>
1298
+ </div>
1299
+
1300
+ <div class="tab-content">
1301
+ <div class="tab-pane active" id="props-tab">
1302
+ <div class="props-container"></div>
1303
+ <div class="props-actions">
1304
+ <div class="action-buttons">
1305
+ <button class="action-btn primary" id="apply-changes">✅ Apply Changes</button>
1306
+ <button class="action-btn secondary" id="reset-values">🔄 Reset Values</button>
1307
+ </div>
1308
+ <div class="actions-note">
1309
+ <small>💡 Press Enter on any input to apply changes automatically</small>
1310
+ </div>
1311
+ </div>
1312
+ </div>
1313
+
1314
+ <div class="tab-pane" id="info-tab">
1315
+ <div class="info-container">
1316
+ <div class="info-list"></div>
1317
+ </div>
1318
+ </div>
1319
+ </div>
1320
+ </div>
1321
+
1322
+ <!-- Modal para editar objetos/funciones -->
1323
+ <div class="editor-modal" id="editor-modal">
1324
+ <div class="modal-content">
1325
+ <div class="modal-header">
1326
+ <h3 id="modal-title">Edit Property</h3>
1327
+ <button class="modal-close" id="modal-close">×</button>
1328
+ </div>
1329
+ <div class="modal-body">
1330
+ <div class="editor-type-selector">
1331
+ <button class="type-btn active" data-type="json">📋 JSON</button>
1332
+ <button class="type-btn" data-type="function">⚡ Function</button>
1333
+ </div>
1334
+ <div class="editor-container">
1335
+ <textarea id="property-editor" spellcheck="false"></textarea>
1336
+ </div>
1337
+ <div class="editor-footer">
1338
+ <div class="validation-message"></div>
1339
+ </div>
1340
+ </div>
1341
+ <div class="modal-actions">
1342
+ <button class="modal-btn cancel" id="modal-cancel">Cancel</button>
1343
+ <button class="modal-btn save" id="modal-save">Save Changes</button>
1344
+ </div>
1345
+ </div>
1346
+ </div>
1347
+ </div>`
1348
+ }