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
|
-
//
|
|
13
|
-
const
|
|
14
|
-
|
|
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('
|
|
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')
|
|
88
|
+
this.querySelector('#apply-changes')?.addEventListener('click', (e) => {
|
|
89
|
+
e.stopPropagation();
|
|
78
90
|
this.applyAllChanges();
|
|
79
91
|
});
|
|
80
92
|
|
|
81
|
-
this.querySelector('#reset-values')
|
|
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
|
-
// ✅
|
|
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
|
-
|
|
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
|
-
// ✅
|
|
147
|
+
// ✅ PROTECCIÓN GLOBAL: Prevenir que eventos externos interfieran
|
|
117
148
|
this.addEventListener('click', (event) => {
|
|
118
|
-
if (event.target
|
|
119
|
-
|
|
149
|
+
if (this.contains(event.target)) {
|
|
150
|
+
event.stopPropagation();
|
|
120
151
|
}
|
|
121
152
|
});
|
|
122
153
|
|
|
123
|
-
|
|
124
|
-
|
|
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
|
-
|
|
227
|
-
|
|
252
|
+
const propsContainer = this.querySelector('.props-container');
|
|
253
|
+
if (!propsContainer) {
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
228
256
|
|
|
229
|
-
|
|
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
|
-
|
|
237
|
-
|
|
238
|
-
|
|
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
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
263
|
+
realComponentProps.forEach(prop => {
|
|
264
|
+
const propElement = this.createPropElement(prop, configuredProps[prop]);
|
|
265
|
+
propsContainer.appendChild(propElement);
|
|
266
|
+
});
|
|
267
|
+
}
|
|
246
268
|
|
|
247
|
-
|
|
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
|
-
|
|
250
|
-
|
|
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
|
-
|
|
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-
|
|
283
|
-
|
|
284
|
-
<span class="prop-type">${
|
|
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"
|
|
289
|
-
|
|
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
|
-
|
|
301
|
+
${config.default !== undefined ? `<div class="default-value">Default: ${JSON.stringify(config.default)}</div>` : ''}
|
|
312
302
|
`;
|
|
313
303
|
|
|
314
|
-
return
|
|
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
|
-
|
|
326
|
-
const
|
|
327
|
-
const displayValue = this.formatValueForDisplay(value);
|
|
307
|
+
createInputForType(prop, value, type, config = {}) {
|
|
308
|
+
const serializedValue = this.serializeValue(value);
|
|
328
309
|
|
|
329
|
-
if (
|
|
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="
|
|
333
|
-
|
|
324
|
+
<input type="number"
|
|
325
|
+
class="prop-control debugger-input"
|
|
334
326
|
data-prop="${prop}"
|
|
335
|
-
|
|
336
|
-
|
|
327
|
+
value="${serializedValue}"
|
|
328
|
+
step="any"
|
|
329
|
+
placeholder="Enter number..."
|
|
330
|
+
data-debugger-input="true">
|
|
337
331
|
</div>
|
|
338
332
|
`;
|
|
339
|
-
} else if (
|
|
340
|
-
const checked = value ? 'checked' : '';
|
|
333
|
+
} else if (type === 'object' || type === 'array' || type === 'function') {
|
|
341
334
|
return `
|
|
342
|
-
<
|
|
343
|
-
<input type="
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
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
|
-
<
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
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
|
-
|
|
362
|
-
|
|
363
|
-
if (
|
|
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
|
-
|
|
369
|
-
const component = this.currentComponent;
|
|
364
|
+
let newValue;
|
|
370
365
|
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
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
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
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
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
+
showVisualFeedback(inputElement) {
|
|
392
|
+
const originalBorder = inputElement.style.borderColor;
|
|
393
|
+
const originalBoxShadow = inputElement.style.boxShadow;
|
|
391
394
|
|
|
392
|
-
|
|
393
|
-
|
|
395
|
+
inputElement.style.borderColor = '#4CAF50';
|
|
396
|
+
inputElement.style.boxShadow = '0 0 0 2px rgba(76, 175, 80, 0.3)';
|
|
394
397
|
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
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
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
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
|
-
|
|
429
|
+
applyBtn.textContent = '✅ No changes to apply';
|
|
430
|
+
applyBtn.style.background = '#9E9E9E';
|
|
406
431
|
}
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
432
|
+
|
|
433
|
+
setTimeout(() => {
|
|
434
|
+
applyBtn.textContent = originalText;
|
|
435
|
+
applyBtn.style.background = '';
|
|
436
|
+
}, 2000);
|
|
411
437
|
}
|
|
412
438
|
|
|
413
|
-
|
|
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
|
-
|
|
424
|
-
value.toString()
|
|
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.
|
|
461
|
+
this.editorModal.classList.add('active');
|
|
462
|
+
this.propertyEditor.focus();
|
|
430
463
|
}
|
|
431
464
|
|
|
432
465
|
validateEditor() {
|
|
433
|
-
const
|
|
434
|
-
const
|
|
466
|
+
const value = this.propertyEditor.value.trim();
|
|
467
|
+
const type = this.currentEditingType;
|
|
435
468
|
|
|
436
469
|
try {
|
|
437
|
-
if (
|
|
438
|
-
|
|
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(
|
|
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 = '
|
|
456
|
-
|
|
481
|
+
this.validationMessage.style.color = '#F44336';
|
|
482
|
+
this.querySelector('#modal-save').disabled = true;
|
|
457
483
|
}
|
|
458
484
|
}
|
|
459
485
|
|
|
460
486
|
savePropertyValue() {
|
|
461
|
-
const
|
|
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 (
|
|
467
|
-
newValue = new Function('return ' +
|
|
493
|
+
if (type === 'function') {
|
|
494
|
+
newValue = new Function('return ' + value)();
|
|
468
495
|
} else {
|
|
469
|
-
newValue = JSON.parse(
|
|
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
|
-
|
|
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 = '
|
|
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
|
|
525
|
+
const configuredProps = ComponentClass.props || {};
|
|
581
526
|
let resetCount = 0;
|
|
582
527
|
|
|
583
|
-
Object.entries(
|
|
528
|
+
Object.entries(configuredProps).forEach(([prop, config]) => {
|
|
584
529
|
if (config.default !== undefined) {
|
|
585
530
|
this.currentComponent[prop] = config.default;
|
|
586
|
-
|
|
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 = '
|
|
559
|
+
resetBtn.style.background = '#FF9800';
|
|
606
560
|
|
|
607
561
|
setTimeout(() => {
|
|
608
562
|
resetBtn.textContent = originalText;
|
|
609
|
-
resetBtn.style.background = '
|
|
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
|
+
}
|