slicejs-web-framework 1.0.31 → 1.0.32

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,10 +8,16 @@ 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
21
  const html = await slice.controller.fetchText('Debugger', 'html', 'Structural');
14
22
  const css = await slice.controller.fetchText('Debugger', 'css', 'Structural');
15
23
 
@@ -20,7 +28,7 @@ export default class Debugger extends HTMLElement {
20
28
  this.setupEventListeners();
21
29
  this.makeDraggable();
22
30
 
23
- slice.logger.logInfo('Logger', 'Advanced Debug mode enabled');
31
+ slice.logger.logInfo('Debugger', 'Advanced Debug mode enabled');
24
32
  return true;
25
33
  }
26
34
 
@@ -74,11 +82,13 @@ export default class Debugger extends HTMLElement {
74
82
  });
75
83
 
76
84
  // Action buttons
77
- this.querySelector('#apply-changes').addEventListener('click', () => {
85
+ this.querySelector('#apply-changes')?.addEventListener('click', (e) => {
86
+ e.stopPropagation();
78
87
  this.applyAllChanges();
79
88
  });
80
89
 
81
- this.querySelector('#reset-values').addEventListener('click', () => {
90
+ this.querySelector('#reset-values')?.addEventListener('click', (e) => {
91
+ e.stopPropagation();
82
92
  this.resetValues();
83
93
  });
84
94
 
@@ -94,59 +104,73 @@ export default class Debugger extends HTMLElement {
94
104
  }
95
105
  });
96
106
 
97
- // ✅ SIMPLIFICADO: Solo Enter para aplicar, sin más eventos automáticos
107
+ // ✅ EVENTOS PRINCIPALES - Con protección anti-interferencia
108
+ this.addEventListener('mousedown', (event) => {
109
+ if (event.target.classList.contains('prop-control')) {
110
+ this.isDebuggerInput = true;
111
+ // Prevenir interferencias del Router u otros sistemas
112
+ event.stopPropagation();
113
+ }
114
+ });
115
+
116
+ this.addEventListener('focus', (event) => {
117
+ if (event.target.classList.contains('prop-control')) {
118
+ this.isDebuggerInput = true;
119
+ event.stopPropagation();
120
+ }
121
+ }, true);
122
+
123
+ this.addEventListener('blur', (event) => {
124
+ if (event.target.classList.contains('prop-control')) {
125
+ this.isDebuggerInput = false;
126
+ }
127
+ }, true);
128
+
98
129
  this.addEventListener('keypress', (event) => {
99
130
  if (event.key === 'Enter' && event.target.classList.contains('prop-control')) {
100
131
  event.preventDefault();
132
+ event.stopPropagation();
101
133
  this.applyPropertyChange(event.target);
102
134
  }
103
135
  });
104
136
 
105
- // ✅ SIMPLIFICADO: Solo cambio visual para checkboxes
106
137
  this.addEventListener('change', (event) => {
107
138
  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
- }
139
+ event.stopPropagation();
112
140
  this.applyPropertyChange(event.target);
113
141
  }
114
142
  });
115
143
 
116
- // ✅ DEBUG: Agregar logs para entender qué está pasando
144
+ // ✅ PROTECCIÓN GLOBAL: Prevenir que eventos externos interfieran
117
145
  this.addEventListener('click', (event) => {
118
- if (event.target.classList.contains('prop-control')) {
119
- console.log('🎯 Debug: Input clicked', event.target.dataset.prop);
146
+ if (this.contains(event.target)) {
147
+ event.stopPropagation();
120
148
  }
121
149
  });
122
150
 
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);
151
+ // Los eventos DOMNodeInserted/Removed están deprecated,
152
+ // pero la protección con stopPropagation() ya es suficiente
134
153
  }
135
154
 
136
155
  switchTab(tabName) {
137
156
  this.activeTab = tabName;
138
157
 
139
- // Update tab buttons
140
158
  this.querySelectorAll('.tab-btn').forEach(btn => {
141
159
  btn.classList.toggle('active', btn.dataset.tab === tabName);
142
160
  });
143
161
 
144
- // Update tab panes
145
162
  this.querySelectorAll('.tab-pane').forEach(pane => {
146
163
  pane.classList.toggle('active', pane.id === `${tabName}-tab`);
147
164
  });
148
165
  }
149
166
 
167
+ switchEditorType(type) {
168
+ this.querySelectorAll('.type-btn').forEach(btn => {
169
+ btn.classList.toggle('active', btn.dataset.type === type);
170
+ });
171
+ this.currentEditingType = type;
172
+ }
173
+
150
174
  attachDebugMode(component) {
151
175
  if (this.toggleClick === 'right') {
152
176
  this.toggle = 'contextmenu';
@@ -211,280 +235,278 @@ export default class Debugger extends HTMLElement {
211
235
  }
212
236
  });
213
237
 
238
+ // ✅ Crear UI sin interferencias
214
239
  this.updateDebuggerContent();
215
240
  this.debuggerContainer.classList.add('active');
216
241
  }
217
242
 
218
243
  updateDebuggerContent() {
219
- console.log('🔥 DEBUG: updateDebuggerContent called - this recreates ALL inputs!');
220
- console.trace(); // Esto nos dirá desde dónde se está llamando
221
244
  this.updatePropsTab();
222
245
  this.updateInfoTab();
223
246
  }
224
247
 
225
248
  updatePropsTab() {
226
- console.log('🔥 DEBUG: updatePropsTab called - this recreates props inputs!');
227
- console.trace();
249
+ const propsContainer = this.querySelector('.props-container');
250
+ if (!propsContainer) {
251
+ return;
252
+ }
228
253
 
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 = '';
254
+ propsContainer.innerHTML = '';
235
255
 
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>';
256
+ const realComponentProps = this.getComponentPropsForDebugger(this.currentComponent);
257
+ const ComponentClass = this.currentComponent.constructor;
258
+ const configuredProps = ComponentClass.props || {};
241
259
 
242
- Object.entries(staticProps).forEach(([prop, config]) => {
243
- const propItem = this.createPropItem(prop, config, this.componentProps[prop]);
244
- usedSection.appendChild(propItem);
245
- });
260
+ realComponentProps.forEach(prop => {
261
+ const propElement = this.createPropElement(prop, configuredProps[prop]);
262
+ propsContainer.appendChild(propElement);
263
+ });
264
+ }
246
265
 
247
- this.propsContainer.appendChild(usedSection);
266
+ createPropElement(prop, config = {}) {
267
+ const propWrapper = document.createElement('div');
268
+ propWrapper.className = 'prop-item';
269
+ propWrapper.dataset.prop = prop;
270
+
271
+ const currentValue = this.currentComponent[prop];
272
+ const valueType = this.getValueType(currentValue);
273
+
274
+ // Status based on usage
275
+ let status, statusClass;
276
+ if (currentValue !== undefined && currentValue !== null) {
277
+ status = 'Used';
278
+ statusClass = 'status-used';
279
+ } else if (config.required) {
280
+ status = 'Missing';
281
+ statusClass = 'status-missing';
248
282
  } 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);
283
+ status = 'Optional';
284
+ statusClass = 'status-optional';
262
285
  }
263
- }
264
286
 
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
-
277
- const inputType = this.getInputType(config.type, value);
278
- const inputHtml = this.createPropertyInput(prop, value, config, inputType);
279
-
280
- propItem.innerHTML = `
287
+ propWrapper.innerHTML = `
281
288
  <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>
289
+ <div class="prop-title">
290
+ <strong>${prop}</strong>
291
+ <span class="prop-type">${valueType}</span>
286
292
  </div>
293
+ <div class="prop-status ${statusClass}">${status}</div>
287
294
  </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>
295
+ <div class="prop-input">
296
+ ${this.createInputForType(prop, currentValue, valueType, config)}
310
297
  </div>
311
- <div class="prop-input">${inputHtml}</div>
298
+ ${config.default !== undefined ? `<div class="default-value">Default: ${JSON.stringify(config.default)}</div>` : ''}
312
299
  `;
313
300
 
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';
301
+ return propWrapper;
323
302
  }
324
303
 
325
- createPropertyInput(prop, value, config, inputType) {
326
- const hasComplexEditor = inputType === 'object' || inputType === 'function';
327
- const displayValue = this.formatValueForDisplay(value);
304
+ createInputForType(prop, value, type, config = {}) {
305
+ const serializedValue = this.serializeValue(value);
328
306
 
329
- if (hasComplexEditor) {
307
+ if (type === 'boolean') {
330
308
  return `
331
309
  <div class="input-group">
332
- <input type="text" class="prop-control"
333
- value="${displayValue}"
310
+ <input type="checkbox"
311
+ class="prop-control debugger-input"
334
312
  data-prop="${prop}"
335
- readonly>
336
- <button class="edit-btn" onclick="slice.debugger.openEditor('${prop}', '${inputType}')">✏️</button>
313
+ ${value ? 'checked' : ''}
314
+ data-debugger-input="true">
315
+ <span class="checkbox-label">${value ? 'true' : 'false'}</span>
337
316
  </div>
338
317
  `;
339
- } else if (inputType === 'boolean') {
340
- const checked = value ? 'checked' : '';
318
+ } else if (type === 'number') {
341
319
  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>
320
+ <div class="input-group">
321
+ <input type="number"
322
+ class="prop-control debugger-input"
323
+ data-prop="${prop}"
324
+ value="${serializedValue}"
325
+ step="any"
326
+ placeholder="Enter number..."
327
+ data-debugger-input="true">
328
+ </div>
329
+ `;
330
+ } else if (type === 'object' || type === 'array' || type === 'function') {
331
+ return `
332
+ <div class="input-group">
333
+ <input type="text"
334
+ class="prop-control debugger-input"
335
+ data-prop="${prop}"
336
+ value="${serializedValue}"
337
+ readonly
338
+ title="Click edit button to modify"
339
+ data-debugger-input="true">
340
+ <button class="edit-btn" onclick="slice.debugger.openAdvancedEditor('${prop}', '${type}')">✏️</button>
341
+ </div>
348
342
  `;
349
343
  } else {
350
- // ✅ CORREGIDO: Inputs normales SIN readonly para permitir edición
351
344
  return `
352
- <input type="${inputType === 'number' ? 'number' : 'text'}"
353
- class="prop-control"
354
- value="${displayValue}"
355
- data-prop="${prop}"
356
- placeholder="Enter ${inputType} value...">
345
+ <div class="input-group">
346
+ <input type="text"
347
+ class="prop-control debugger-input"
348
+ data-prop="${prop}"
349
+ value="${serializedValue}"
350
+ placeholder="Enter value..."
351
+ data-debugger-input="true">
352
+ </div>
357
353
  `;
358
354
  }
359
355
  }
360
356
 
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
- }
357
+ applyPropertyChange(inputElement) {
358
+ const prop = inputElement.dataset.prop;
359
+ if (!prop) return;
367
360
 
368
- updateInfoTab() {
369
- const component = this.currentComponent;
361
+ let newValue;
370
362
 
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
- ];
363
+ if (inputElement.type === 'checkbox') {
364
+ newValue = inputElement.checked;
365
+ const label = inputElement.parentNode.querySelector('.checkbox-label');
366
+ if (label) {
367
+ label.textContent = newValue ? 'true' : 'false';
368
+ }
369
+ } else if (inputElement.type === 'number') {
370
+ newValue = Number(inputElement.value);
371
+ } else {
372
+ newValue = inputElement.value;
373
+
374
+ // Convert string values
375
+ if (newValue === 'true') newValue = true;
376
+ if (newValue === 'false') newValue = false;
377
+ if (!isNaN(newValue) && newValue !== '' && newValue !== null) newValue = Number(newValue);
378
+ }
379
379
 
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('');
380
+ const oldValue = this.currentComponent[prop];
381
+
382
+ this.currentComponent[prop] = newValue;
383
+ slice.logger.logInfo('Debugger', `Updated ${prop}: ${oldValue} → ${newValue}`);
384
+
385
+ this.showVisualFeedback(inputElement);
386
386
  }
387
387
 
388
- openEditor(prop, type) {
389
- this.currentEditingProp = prop;
390
- this.currentEditingType = type;
388
+ showVisualFeedback(inputElement) {
389
+ const originalBorder = inputElement.style.borderColor;
390
+ const originalBoxShadow = inputElement.style.boxShadow;
391
391
 
392
- const value = this.componentProps[prop];
393
- this.modalTitle.textContent = `Edit ${prop}`;
392
+ inputElement.style.borderColor = '#4CAF50';
393
+ inputElement.style.boxShadow = '0 0 0 2px rgba(76, 175, 80, 0.3)';
394
394
 
395
- // Set editor type
396
- this.querySelectorAll('.type-btn').forEach(btn => {
397
- btn.classList.toggle('active', btn.dataset.type === type);
395
+ setTimeout(() => {
396
+ inputElement.style.borderColor = originalBorder;
397
+ inputElement.style.boxShadow = originalBoxShadow;
398
+ }, 1500);
399
+ }
400
+
401
+ applyAllChanges() {
402
+ const inputs = this.querySelectorAll('.prop-control:not([readonly])');
403
+ let changeCount = 0;
404
+
405
+ inputs.forEach(input => {
406
+ if (!input.readOnly) {
407
+ this.applyPropertyChange(input);
408
+ changeCount++;
409
+ }
398
410
  });
399
411
 
400
- // Set editor content
401
- if (type === 'function') {
402
- this.propertyEditor.value = typeof value === 'function' ?
403
- value.toString() : 'function() {\n // Your code here\n}';
412
+ slice.logger.logInfo('Debugger', `Applied ${changeCount} property changes`);
413
+ this.showApplyFeedback(changeCount);
414
+ }
415
+
416
+ showApplyFeedback(changeCount) {
417
+ const applyBtn = this.querySelector('#apply-changes');
418
+ if (!applyBtn) return;
419
+
420
+ const originalText = applyBtn.textContent;
421
+
422
+ if (changeCount > 0) {
423
+ applyBtn.textContent = `✅ Applied ${changeCount} changes!`;
424
+ applyBtn.style.background = '#4CAF50';
404
425
  } else {
405
- this.propertyEditor.value = JSON.stringify(value, null, 2);
426
+ applyBtn.textContent = '✅ No changes to apply';
427
+ applyBtn.style.background = '#9E9E9E';
406
428
  }
407
-
408
- this.editorModal.classList.add('active');
409
- this.propertyEditor.focus();
410
- this.validateEditor();
429
+
430
+ setTimeout(() => {
431
+ applyBtn.textContent = originalText;
432
+ applyBtn.style.background = '';
433
+ }, 2000);
411
434
  }
412
435
 
413
- switchEditorType(type) {
436
+ openAdvancedEditor(prop, type) {
437
+ this.currentEditingProp = prop;
414
438
  this.currentEditingType = type;
415
439
 
440
+ const value = this.currentComponent[prop];
441
+
442
+ this.modalTitle.textContent = `Edit ${prop} (${type})`;
443
+
416
444
  this.querySelectorAll('.type-btn').forEach(btn => {
417
445
  btn.classList.toggle('active', btn.dataset.type === type);
418
446
  });
419
-
420
- const value = this.componentProps[this.currentEditingProp];
421
447
 
422
448
  if (type === 'function') {
423
- this.propertyEditor.value = typeof value === 'function' ?
424
- value.toString() : 'function() {\n // Your code here\n}';
449
+ if (typeof value === 'function') {
450
+ this.propertyEditor.value = value.toString();
451
+ } else {
452
+ this.propertyEditor.value = 'function() {\n // Your code here\n}';
453
+ }
425
454
  } else {
426
455
  this.propertyEditor.value = JSON.stringify(value, null, 2);
427
456
  }
428
457
 
429
- this.validateEditor();
458
+ this.editorModal.classList.add('active');
459
+ this.propertyEditor.focus();
430
460
  }
431
461
 
432
462
  validateEditor() {
433
- const content = this.propertyEditor.value;
434
- const saveBtn = this.querySelector('#modal-save');
463
+ const value = this.propertyEditor.value.trim();
464
+ const type = this.currentEditingType;
435
465
 
436
466
  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
- }
467
+ if (type === 'function') {
468
+ new Function('return ' + value)();
447
469
  } else {
448
- JSON.parse(content);
449
- this.validationMessage.textContent = '✅ Valid JSON';
450
- this.validationMessage.style.color = 'var(--success-color)';
451
- saveBtn.disabled = false;
470
+ JSON.parse(value);
452
471
  }
472
+
473
+ this.validationMessage.textContent = '✅ Valid syntax';
474
+ this.validationMessage.style.color = '#4CAF50';
475
+ this.querySelector('#modal-save').disabled = false;
453
476
  } catch (error) {
454
477
  this.validationMessage.textContent = `❌ ${error.message}`;
455
- this.validationMessage.style.color = 'var(--danger-color)';
456
- saveBtn.disabled = true;
478
+ this.validationMessage.style.color = '#F44336';
479
+ this.querySelector('#modal-save').disabled = true;
457
480
  }
458
481
  }
459
482
 
460
483
  savePropertyValue() {
461
- const content = this.propertyEditor.value;
484
+ const value = this.propertyEditor.value.trim();
485
+ const type = this.currentEditingType;
462
486
 
463
487
  try {
464
488
  let newValue;
465
489
 
466
- if (this.currentEditingType === 'function') {
467
- newValue = new Function('return ' + content)();
490
+ if (type === 'function') {
491
+ newValue = new Function('return ' + value)();
468
492
  } else {
469
- newValue = JSON.parse(content);
493
+ newValue = JSON.parse(value);
470
494
  }
471
-
472
- // Update component property
473
- this.currentComponent[this.currentEditingProp] = newValue;
474
- this.componentProps[this.currentEditingProp] = newValue;
475
495
 
476
- // CORREGIDO: Solo actualizar UI después de cerrar modal
496
+ this.currentComponent[this.currentEditingProp] = newValue;
477
497
  this.closeModal();
478
498
 
479
- // ✅ Recrear props solo después de editar objeto/función (necesario)
480
- setTimeout(() => {
481
- this.updatePropsTab();
482
- }, 50);
483
-
484
499
  slice.logger.logInfo('Debugger', `Updated ${this.currentEditingProp} via advanced editor`);
500
+
501
+ const input = this.querySelector(`[data-prop="${this.currentEditingProp}"]`);
502
+ if (input) {
503
+ input.value = this.serializeValue(newValue);
504
+ this.showVisualFeedback(input);
505
+ }
506
+
485
507
  } catch (error) {
486
508
  this.validationMessage.textContent = `❌ ${error.message}`;
487
- this.validationMessage.style.color = 'var(--danger-color)';
509
+ this.validationMessage.style.color = '#F44336';
488
510
  }
489
511
  }
490
512
 
@@ -495,121 +517,96 @@ export default class Debugger extends HTMLElement {
495
517
  this.validationMessage.textContent = '';
496
518
  }
497
519
 
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
520
  resetValues() {
579
521
  const ComponentClass = this.currentComponent.constructor;
580
- const staticProps = ComponentClass.props || {};
522
+ const configuredProps = ComponentClass.props || {};
581
523
  let resetCount = 0;
582
524
 
583
- Object.entries(staticProps).forEach(([prop, config]) => {
525
+ Object.entries(configuredProps).forEach(([prop, config]) => {
584
526
  if (config.default !== undefined) {
585
527
  this.currentComponent[prop] = config.default;
586
- resetCount++;
528
+
529
+ const input = this.querySelector(`[data-prop="${prop}"]`);
530
+ if (input && !input.readOnly) {
531
+ if (input.type === 'checkbox') {
532
+ input.checked = config.default;
533
+ const label = input.parentNode.querySelector('.checkbox-label');
534
+ if (label) {
535
+ label.textContent = config.default ? 'true' : 'false';
536
+ }
537
+ } else {
538
+ input.value = this.serializeValue(config.default);
539
+ }
540
+ resetCount++;
541
+ }
587
542
  }
588
543
  });
589
544
 
590
545
  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
- }
546
+ this.showResetFeedback(resetCount);
597
547
  }
598
548
 
599
- // ✅ NUEVO: Mostrar feedback visual para reset
600
549
  showResetFeedback(resetCount) {
601
550
  const resetBtn = this.querySelector('#reset-values');
551
+ if (!resetBtn) return;
552
+
602
553
  const originalText = resetBtn.textContent;
603
554
 
604
555
  resetBtn.textContent = `🔄 Reset ${resetCount} values!`;
605
- resetBtn.style.background = 'var(--warning-color)';
556
+ resetBtn.style.background = '#FF9800';
606
557
 
607
558
  setTimeout(() => {
608
559
  resetBtn.textContent = originalText;
609
- resetBtn.style.background = 'var(--secondary-color)';
560
+ resetBtn.style.background = '';
610
561
  }, 1500);
611
562
  }
612
563
 
564
+ updateInfoTab() {
565
+ const infoContainer = this.querySelector('.info-list');
566
+ if (!infoContainer) return;
567
+
568
+ const component = this.currentComponent;
569
+
570
+ const info = [
571
+ { label: 'Component Type', value: component.constructor.name },
572
+ { label: 'Slice ID', value: component.sliceId || 'Not assigned' },
573
+ { label: 'Tag Name', value: component.tagName },
574
+ { label: 'Connected', value: component.isConnected ? 'Yes' : 'No' },
575
+ { label: 'Props Count', value: Object.keys(this.componentProps).length },
576
+ { label: 'Children', value: component.children.length }
577
+ ];
578
+
579
+ infoContainer.innerHTML = info.map(item => `
580
+ <div class="info-item">
581
+ <span class="info-label">${item.label}</span>
582
+ <span class="info-value">${item.value}</span>
583
+ </div>
584
+ `).join('');
585
+ }
586
+
587
+ getValueType(value) {
588
+ if (value === null) return 'null';
589
+ if (value === undefined) return 'undefined';
590
+ if (Array.isArray(value)) return 'array';
591
+ return typeof value;
592
+ }
593
+
594
+ serializeValue(value) {
595
+ if (value === null || value === undefined) {
596
+ return '';
597
+ }
598
+
599
+ if (typeof value === 'object' || typeof value === 'function') {
600
+ try {
601
+ return JSON.stringify(value);
602
+ } catch {
603
+ return String(value);
604
+ }
605
+ }
606
+
607
+ return String(value);
608
+ }
609
+
613
610
  getComponentPropsForDebugger(component) {
614
611
  const ComponentClass = component.constructor;
615
612
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "slicejs-web-framework",
3
- "version": "1.0.31",
3
+ "version": "1.0.32",
4
4
  "description": "",
5
5
  "engines": {
6
6
  "node": ">=20"