canvasframework 0.3.28 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -170,7 +170,7 @@ class AndroidDatePickerDialog extends Component {
170
170
  ctx.shadowColor = 'transparent';
171
171
 
172
172
  // Header coloré
173
- ctx.fillStyle = '#6200EE';
173
+ ctx.fillStyle = this.headerBgColor;
174
174
  ctx.beginPath();
175
175
  this.roundRect(ctx, dialogX, dialogY, this.dialogWidth, this.headerHeight, 4);
176
176
  ctx.rect(dialogX, dialogY + this.headerHeight - 4, this.dialogWidth, 4);
@@ -191,7 +191,7 @@ class AndroidDatePickerDialog extends Component {
191
191
  const selectedMonth = monthNames[this.selectedDate.getMonth()];
192
192
  const selectedDayNum = this.selectedDate.getDate();
193
193
 
194
- ctx.fillStyle = '#000000';
194
+ ctx.fillStyle = '#ffffff';
195
195
  ctx.font = 'bold 32px Roboto, sans-serif';
196
196
  ctx.textBaseline = 'middle';
197
197
  ctx.fillText(`${selectedDay}, ${selectedMonth} ${selectedDayNum}`,
@@ -27,6 +27,7 @@ class RadioButton extends Component {
27
27
  this.group = options.group || 'default';
28
28
  this.checked = options.checked || false;
29
29
  this.label = options.label || '';
30
+ this.labelColor = options.labelColor || '#000000'; // Nouvelle propriété
30
31
  this.platform = framework.platform;
31
32
  this.circleSize = 24; // Taille du cercle
32
33
  this.circleRadius = 10; // Rayon du cercle
@@ -123,7 +124,7 @@ class RadioButton extends Component {
123
124
 
124
125
  // Label
125
126
  if (this.label) {
126
- ctx.fillStyle = '#000000';
127
+ ctx.fillStyle = this.labelColor; // Au lieu de '#000000'
127
128
  ctx.font = '16px -apple-system, sans-serif';
128
129
  ctx.textAlign = 'left';
129
130
  ctx.textBaseline = 'middle';
@@ -180,7 +180,6 @@ class CanvasFramework {
180
180
  // Thèmes
181
181
  this.lightTheme = lightTheme;
182
182
  this.darkTheme = darkTheme;
183
- this.theme = lightTheme; // thème par défaut
184
183
  // État actuel + préférence
185
184
  this.themeMode = options.themeMode || 'system'; // 'light', 'dark', 'system'
186
185
  this.userThemeOverride = null; // null = suit system, sinon 'light' ou 'dark'
@@ -196,7 +195,13 @@ class CanvasFramework {
196
195
  }
197
196
 
198
197
  this.components = [];
199
- this.applyThemeFromSystem();
198
+ this.theme = lightTheme; // thème par défaut
199
+ // ✅ AJOUTER ICI :
200
+ this._cachedMaxScroll = 0;
201
+ this._maxScrollDirty = true;
202
+ this.resizeTimeout = null;
203
+
204
+ //this.applyThemeFromSystem();
200
205
  this.state = {};
201
206
  // NOUVELLE OPTION: choisir entre Canvas 2D et WebGL
202
207
  this.useWebGL = options.useWebGL !== false; // true par défaut
@@ -286,17 +291,23 @@ class CanvasFramework {
286
291
  * Détecte le thème système et applique si mode = 'system'
287
292
  */
288
293
  applyThemeFromSystem() {
289
- if (this.themeMode === 'system') {
290
- const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
291
- const newTheme = prefersDark ? this.darkTheme : this.lightTheme;
292
- this.setTheme(newTheme);
293
- } else {
294
- // Mode forcé
295
- this.setTheme(
296
- this.themeMode === 'dark' ? this.darkTheme : this.lightTheme
297
- );
298
- }
299
- }
294
+ // Vérifier que tout est initialisé
295
+ if (!this.lightTheme || !this.darkTheme) {
296
+ console.warn('Thèmes non initialisés');
297
+ return;
298
+ }
299
+
300
+ if (this.themeMode === 'system') {
301
+ const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
302
+ const newTheme = prefersDark ? this.darkTheme : this.lightTheme;
303
+ this.setTheme(newTheme);
304
+ } else {
305
+ // Mode forcé
306
+ this.setTheme(
307
+ this.themeMode === 'dark' ? this.darkTheme : this.lightTheme
308
+ );
309
+ }
310
+ }
300
311
 
301
312
  /**
302
313
  * Écoute les changements système (ex: utilisateur bascule dark mode)
@@ -431,7 +442,7 @@ class CanvasFramework {
431
442
  set: (value) => {
432
443
  // Si value est blanc/noir ou une couleur “neutre”, tu remplaces par theme
433
444
  if (value === '#FFFFFF' || value === '#000000') {
434
- originalFillStyle.set.call(ctx, theme.text);
445
+ originalFillStyle.set.call(ctx, value);
435
446
  } else {
436
447
  originalFillStyle.set.call(ctx, value);
437
448
  }
@@ -1225,13 +1236,18 @@ class CanvasFramework {
1225
1236
  }
1226
1237
 
1227
1238
  getMaxScroll() {
1239
+ if (!this._maxScrollDirty) return this._cachedMaxScroll;
1240
+
1228
1241
  let maxY = 0;
1229
1242
  for (const comp of this.components) {
1230
1243
  if (this.isFixedComponent(comp) || !comp.visible) continue;
1231
1244
  const bottom = comp.y + comp.height;
1232
1245
  if (bottom > maxY) maxY = bottom;
1233
1246
  }
1234
- return Math.max(0, maxY - this.height + 50);
1247
+
1248
+ this._cachedMaxScroll = Math.max(0, maxY - this.height + 50);
1249
+ this._maxScrollDirty = false;
1250
+ return this._cachedMaxScroll;
1235
1251
  }
1236
1252
 
1237
1253
  /*getMaxScroll() {
@@ -1245,32 +1261,38 @@ class CanvasFramework {
1245
1261
  }*/
1246
1262
 
1247
1263
  handleResize() {
1248
- // Pour WebGL, NE PAS redimensionner automatiquement
1249
- if (!this.useWebGL) {
1250
- this.width = window.innerWidth;
1251
- this.height = window.innerHeight;
1252
- this.setupCanvas();
1264
+ if (this.resizeTimeout) clearTimeout(this.resizeTimeout); // AJOUTER
1265
+
1266
+ this.resizeTimeout = setTimeout(() => { // ✅ AJOUTER
1267
+ if (!this.useWebGL) {
1268
+ this.width = window.innerWidth;
1269
+ this.height = window.innerHeight;
1270
+ this.setupCanvas();
1253
1271
 
1254
- for (const comp of this.components) {
1255
- if (comp._resize) {
1256
- comp._resize(this.width, this.height);
1272
+ for (const comp of this.components) {
1273
+ if (comp._resize) {
1274
+ comp._resize(this.width, this.height);
1275
+ }
1257
1276
  }
1277
+ this._maxScrollDirty = true; // ✅ AJOUTER
1258
1278
  }
1259
- }
1279
+ }, 150); // ✅ AJOUTER (throttle 150ms)
1260
1280
  }
1261
1281
 
1262
1282
  add(component) {
1263
1283
  this.components.push(component);
1264
- component._mount();
1284
+ component._mount();
1285
+ this._maxScrollDirty = true; // ✅ AJOUTER CETTE LIGNE
1265
1286
  return component;
1266
1287
  }
1267
1288
 
1268
1289
  remove(component) {
1269
1290
  const index = this.components.indexOf(component);
1270
1291
  if (index > -1) {
1271
- component._unmount();
1272
- this.components.splice(index, 1);
1273
- }
1292
+ component._unmount();
1293
+ this.components.splice(index, 1);
1294
+ this._maxScrollDirty = true; // ✅ AJOUTER CETTE LIGNE
1295
+ }
1274
1296
  }
1275
1297
 
1276
1298
  markComponentDirty(component) {
@@ -1491,14 +1513,20 @@ class CanvasFramework {
1491
1513
  }
1492
1514
 
1493
1515
  // Scrollable
1494
- this.ctx.save();
1495
- this.ctx.translate(0, this.scrollOffset);
1496
- for (let comp of scrollableComponents) {
1497
- if (comp.visible) {
1498
- comp.draw(this.ctx);
1499
- }
1500
- }
1501
- this.ctx.restore();
1516
+ this.ctx.save();
1517
+ this.ctx.translate(0, this.scrollOffset);
1518
+ for (let comp of scrollableComponents) {
1519
+ if (comp.visible) {
1520
+ // ✅ Viewport culling : ne dessiner que ce qui est visible
1521
+ const screenY = comp.y + this.scrollOffset;
1522
+ const isInViewport = screenY + comp.height >= -100 && screenY <= this.height + 100;
1523
+
1524
+ if (isInViewport) {
1525
+ comp.draw(this.ctx);
1526
+ }
1527
+ }
1528
+ }
1529
+ this.ctx.restore();
1502
1530
 
1503
1531
  // Fixed
1504
1532
  for (let comp of fixedComponents) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "canvasframework",
3
- "version": "0.3.28",
3
+ "version": "0.4.0",
4
4
  "description": "Canvas-based cross-platform UI framework (Material & Cupertino)",
5
5
  "type": "module",
6
6
  "main": "./index.js",
package/utils/DevTools.js CHANGED
@@ -19,6 +19,16 @@ class DevTools {
19
19
  memory: [],
20
20
  drawCalls: []
21
21
  };
22
+ // Dans le constructeur, ajoutez :
23
+ this.consoleLogs = [];
24
+ this.maxConsoleLogs = 100;
25
+ this.consoleFilters = {
26
+ log: true,
27
+ warn: true,
28
+ error: true,
29
+ debug: true,
30
+ info: true
31
+ };
22
32
  this.setupUI();
23
33
  }
24
34
 
@@ -79,20 +89,50 @@ class DevTools {
79
89
 
80
90
  // Tabs
81
91
  this.tabs = document.createElement('div');
82
- this.tabs.style.cssText = `
83
- display: flex;
84
- background: #2d2d2d;
85
- border-bottom: 1px solid #333;
86
- `;
87
-
88
- const tabConfigs = [
89
- { id: 'components', label: 'Composants' },
90
- { id: 'performance', label: 'Performance' },
91
- { id: 'hierarchy', label: 'Hiérarchie' },
92
- { id: 'properties', label: 'Propriétés' },
93
- { id: 'events', label: 'Événements' },
94
- { id: 'routing', label: 'Routing' }
95
- ];
92
+ this.tabs.style.cssText = `
93
+ display: flex;
94
+ background: #2d2d2d;
95
+ border-bottom: 1px solid #333;
96
+ overflow-x: auto;
97
+ overflow-y: hidden;
98
+ scrollbar-width: thin;
99
+ scrollbar-color: #555 #2d2d2d;
100
+ `;
101
+
102
+ // Ajouter un style pour la scrollbar webkit (Chrome, Safari, Edge)
103
+ const style = document.createElement('style');
104
+ style.textContent = `
105
+ #devtools-tabs::-webkit-scrollbar {
106
+ height: 6px;
107
+ }
108
+
109
+ #devtools-tabs::-webkit-scrollbar-track {
110
+ background: #2d2d2d;
111
+ }
112
+
113
+ #devtools-tabs::-webkit-scrollbar-thumb {
114
+ background: #555;
115
+ border-radius: 3px;
116
+ }
117
+
118
+ #devtools-tabs::-webkit-scrollbar-thumb:hover {
119
+ background: #666;
120
+ }
121
+ `;
122
+ document.head.appendChild(style);
123
+
124
+ // Ajouter un ID pour cibler avec le CSS
125
+ this.tabs.id = 'devtools-tabs';
126
+
127
+ const tabConfigs = [
128
+ { id: 'components', label: 'Composants' },
129
+ { id: 'performance', label: 'Performance' },
130
+ { id: 'hierarchy', label: 'Hiérarchie' },
131
+ { id: 'properties', label: 'Propriétés' },
132
+ { id: 'events', label: 'Événements' },
133
+ { id: 'routing', label: 'Routing' },
134
+ { id: 'console', label: 'Console' } // <-- NOUVEAU
135
+ ];
96
136
 
97
137
  tabConfigs.forEach(config => {
98
138
  const tab = document.createElement('button');
@@ -126,6 +166,8 @@ class DevTools {
126
166
  this.createPropertiesPanel();
127
167
  this.createEventsPanel();
128
168
  this.createRoutingPanel();
169
+ // Ajoutez après createRoutingPanel() :
170
+ this.createConsolePanel();
129
171
 
130
172
  // Assembler le conteneur
131
173
  this.container.appendChild(this.header);
@@ -447,7 +489,330 @@ class DevTools {
447
489
  this.content.appendChild(panel);
448
490
  this.panels.routing = panel;
449
491
  }
492
+
493
+ /**
494
+ * Crée le panneau de console
495
+ */
496
+ createConsolePanel() {
497
+ const panel = document.createElement('div');
498
+ panel.id = 'console-panel';
499
+ panel.style.display = 'none';
500
+
501
+ // Filtres
502
+ const filters = document.createElement('div');
503
+ filters.style.cssText = `
504
+ display: flex;
505
+ gap: 10px;
506
+ padding: 8px;
507
+ background: #252526;
508
+ border-radius: 4px;
509
+ margin-bottom: 10px;
510
+ flex-wrap: wrap;
511
+ `;
512
+
513
+ const filterTypes = [
514
+ { type: 'log', label: 'Log', color: '#d4d4d4' },
515
+ { type: 'info', label: 'Info', color: '#4ec9b0' },
516
+ { type: 'warn', label: 'Warn', color: '#dcdcaa' },
517
+ { type: 'error', label: 'Error', color: '#f48771' },
518
+ { type: 'debug', label: 'Debug', color: '#569cd6' }
519
+ ];
520
+
521
+ filterTypes.forEach(({ type, label, color }) => {
522
+ const filterBtn = document.createElement('button');
523
+ filterBtn.textContent = label;
524
+ filterBtn.dataset.type = type;
525
+ filterBtn.style.cssText = `
526
+ padding: 4px 12px;
527
+ background: ${this.consoleFilters[type] ? color : '#555'};
528
+ color: ${this.consoleFilters[type] ? '#000' : '#aaa'};
529
+ border: none;
530
+ border-radius: 3px;
531
+ cursor: pointer;
532
+ font-size: 11px;
533
+ font-weight: bold;
534
+ transition: all 0.2s;
535
+ `;
536
+
537
+ filterBtn.onclick = () => {
538
+ this.consoleFilters[type] = !this.consoleFilters[type];
539
+ filterBtn.style.background = this.consoleFilters[type] ? color : '#555';
540
+ filterBtn.style.color = this.consoleFilters[type] ? '#000' : '#aaa';
541
+ this.updateConsolePanel();
542
+ };
543
+
544
+ filters.appendChild(filterBtn);
545
+ });
546
+
547
+ // Liste des logs
548
+ const consoleList = document.createElement('div');
549
+ consoleList.id = 'console-list';
550
+ consoleList.style.cssText = `
551
+ max-height: 400px;
552
+ overflow-y: auto;
553
+ border: 1px solid #333;
554
+ border-radius: 4px;
555
+ background: #1e1e1e;
556
+ font-family: 'Consolas', 'Monaco', monospace;
557
+ font-size: 11px;
558
+ `;
559
+
560
+ // Contrôles
561
+ const controls = document.createElement('div');
562
+ controls.style.cssText = `
563
+ display: flex;
564
+ gap: 8px;
565
+ margin-top: 10px;
566
+ `;
567
+
568
+ const clearBtn = document.createElement('button');
569
+ clearBtn.textContent = 'Clear Console';
570
+ clearBtn.style.cssText = `
571
+ flex: 1;
572
+ padding: 6px;
573
+ background: #555;
574
+ color: #fff;
575
+ border: none;
576
+ border-radius: 4px;
577
+ cursor: pointer;
578
+ `;
579
+ clearBtn.onclick = () => this.clearConsole();
580
+
581
+ const preserveLogCheckbox = document.createElement('label');
582
+ preserveLogCheckbox.style.cssText = `
583
+ display: flex;
584
+ align-items: center;
585
+ gap: 5px;
586
+ color: #ccc;
587
+ cursor: pointer;
588
+ `;
589
+ preserveLogCheckbox.innerHTML = `
590
+ <input type="checkbox" id="preserve-log">
591
+ <span>Preserve log</span>
592
+ `;
593
+
594
+ controls.appendChild(clearBtn);
595
+ controls.appendChild(preserveLogCheckbox);
596
+
597
+ panel.appendChild(filters);
598
+ panel.appendChild(consoleList);
599
+ panel.appendChild(controls);
600
+
601
+ this.content.appendChild(panel);
602
+ this.panels.console = panel;
603
+ this.consoleList = consoleList;
604
+ }
605
+
606
+ /**
607
+ * Met à jour le panneau console
608
+ */
609
+ updateConsolePanel() {
610
+ if (!this.isOpen || this.currentTab !== 'console') return;
611
+
612
+ this.consoleList.innerHTML = '';
613
+
614
+ this.consoleLogs
615
+ .filter(log => this.consoleFilters[log.type])
616
+ .forEach(log => {
617
+ const logItem = document.createElement('div');
618
+ logItem.style.cssText = `
619
+ padding: 6px 10px;
620
+ border-bottom: 1px solid #2d2d2d;
621
+ display: flex;
622
+ align-items: flex-start;
623
+ gap: 8px;
624
+ `;
625
+
626
+ const colors = {
627
+ log: '#d4d4d4',
628
+ info: '#4ec9b0',
629
+ warn: '#dcdcaa',
630
+ error: '#f48771',
631
+ debug: '#569cd6'
632
+ };
633
+
634
+ const icons = {
635
+ log: '○',
636
+ info: 'ℹ',
637
+ warn: '⚠',
638
+ error: '✖',
639
+ debug: '⚙'
640
+ };
450
641
 
642
+ const timestamp = document.createElement('span');
643
+ timestamp.textContent = log.timestamp;
644
+ timestamp.style.cssText = `
645
+ color: #888;
646
+ font-size: 10px;
647
+ min-width: 80px;
648
+ `;
649
+
650
+ const icon = document.createElement('span');
651
+ icon.textContent = icons[log.type];
652
+ icon.style.cssText = `
653
+ color: ${colors[log.type]};
654
+ min-width: 20px;
655
+ font-weight: bold;
656
+ `;
657
+
658
+ const message = document.createElement('div');
659
+ message.style.cssText = `
660
+ flex: 1;
661
+ color: ${colors[log.type]};
662
+ word-break: break-word;
663
+ `;
664
+
665
+ // Formater le message
666
+ if (typeof log.args[0] === 'object') {
667
+ // Fonction pour gérer les références circulaires
668
+ const safeStringify = (obj, indent = 2) => {
669
+ const seen = new WeakSet();
670
+ return JSON.stringify(obj, (key, value) => {
671
+ // Ignorer les propriétés framework pour éviter les cycles
672
+ if (key === 'framework') return '[CanvasFramework]';
673
+
674
+ if (typeof value === 'object' && value !== null) {
675
+ // Détection de cycle
676
+ if (seen.has(value)) {
677
+ return '[Circular]';
678
+ }
679
+ seen.add(value);
680
+
681
+ // Limiter la profondeur pour les gros objets
682
+ if (key === 'components' && Array.isArray(value)) {
683
+ return `[Array(${value.length})]`;
684
+ }
685
+ }
686
+ return value;
687
+ }, indent);
688
+ };
689
+
690
+ try {
691
+ message.innerHTML = `<pre style="margin: 0;">${safeStringify(log.args[0])}</pre>`;
692
+ } catch (e) {
693
+ message.textContent = '[Objet complexe non affichable]';
694
+ }
695
+ } else {
696
+ message.textContent = log.args.map(arg => {
697
+ if (typeof arg === 'object' && arg !== null) {
698
+ // Pour les objets dans les arguments
699
+ const seen = new WeakSet();
700
+ try {
701
+ return JSON.stringify(arg, (key, value) => {
702
+ if (key === 'framework') return '[Framework]';
703
+ if (typeof value === 'object' && value !== null) {
704
+ if (seen.has(value)) return '[Circular]';
705
+ seen.add(value);
706
+ }
707
+ return value;
708
+ });
709
+ } catch (e) {
710
+ return '[Object]';
711
+ }
712
+ }
713
+ return String(arg);
714
+ }).join(' ');
715
+ }
716
+
717
+ // Stack trace pour les erreurs
718
+ if (log.type === 'error' && log.stack) {
719
+ const stackTrace = document.createElement('div');
720
+ stackTrace.style.cssText = `
721
+ margin-top: 5px;
722
+ padding: 5px;
723
+ background: #2d2d2d;
724
+ border-radius: 3px;
725
+ font-size: 10px;
726
+ color: #888;
727
+ max-height: 100px;
728
+ overflow-y: auto;
729
+ `;
730
+ stackTrace.textContent = log.stack;
731
+ message.appendChild(stackTrace);
732
+ }
733
+
734
+ logItem.appendChild(timestamp);
735
+ logItem.appendChild(icon);
736
+ logItem.appendChild(message);
737
+
738
+ this.consoleList.appendChild(logItem);
739
+ });
740
+
741
+ // Auto-scroll vers le bas
742
+ this.consoleList.scrollTop = this.consoleList.scrollHeight;
743
+ }
744
+
745
+ /**
746
+ * Ajoute un log à la console
747
+ */
748
+ addConsoleLog(type, args, stack = null) {
749
+ const timestamp = new Date().toLocaleTimeString();
750
+
751
+ this.consoleLogs.push({
752
+ type,
753
+ args,
754
+ timestamp,
755
+ stack
756
+ });
757
+
758
+ // Limiter le nombre de logs
759
+ if (this.consoleLogs.length > this.maxConsoleLogs) {
760
+ this.consoleLogs.shift();
761
+ }
762
+
763
+ if (this.isOpen && this.currentTab === 'console') {
764
+ this.updateConsolePanel();
765
+ }
766
+ }
767
+
768
+ /**
769
+ * Vide la console
770
+ */
771
+ clearConsole() {
772
+ const preserveLog = document.getElementById('preserve-log')?.checked;
773
+
774
+ if (!preserveLog) {
775
+ this.consoleLogs = [];
776
+ this.updateConsolePanel();
777
+ }
778
+ }
779
+
780
+ /**
781
+ * Intercepte les méthodes console natives
782
+ */
783
+ interceptConsole() {
784
+ const originalConsole = {
785
+ log: console.log,
786
+ info: console.info,
787
+ warn: console.warn,
788
+ error: console.error,
789
+ debug: console.debug
790
+ };
791
+
792
+ ['log', 'info', 'warn', 'error', 'debug'].forEach(method => {
793
+ console[method] = (...args) => {
794
+ // Appeler la méthode originale
795
+ originalConsole[method].apply(console, args);
796
+
797
+ // Ajouter au DevTools
798
+ const stack = method === 'error' ? new Error().stack : null;
799
+ this.addConsoleLog(method, args, stack);
800
+ };
801
+ });
802
+
803
+ // Sauvegarder pour restauration
804
+ this.originalConsole = originalConsole;
805
+ }
806
+
807
+ /**
808
+ * Restaure les méthodes console natives
809
+ */
810
+ restoreConsole() {
811
+ if (this.originalConsole) {
812
+ Object.assign(console, this.originalConsole);
813
+ }
814
+ }
815
+
451
816
  /**
452
817
  * Configure les raccourcis clavier
453
818
  */
@@ -504,14 +869,16 @@ class DevTools {
504
869
  });
505
870
 
506
871
  if (tabId === 'performance') {
507
- this.updatePerformancePanel();
508
- } else if (tabId === 'hierarchy') {
509
- this.updateHierarchyPanel();
510
- } else if (tabId === 'components') {
511
- this.updateComponentsPanel();
512
- } else if (tabId === 'routing') {
513
- this.updateRoutingPanel();
514
- }
872
+ this.updatePerformancePanel();
873
+ } else if (tabId === 'hierarchy') {
874
+ this.updateHierarchyPanel();
875
+ } else if (tabId === 'components') {
876
+ this.updateComponentsPanel();
877
+ } else if (tabId === 'routing') {
878
+ this.updateRoutingPanel();
879
+ } else if (tabId === 'console') { // <-- NOUVEAU
880
+ this.updateConsolePanel();
881
+ }
515
882
  }
516
883
 
517
884
  /**
@@ -1143,6 +1510,8 @@ class DevTools {
1143
1510
  * Nettoie les références et restaure le framework
1144
1511
  */
1145
1512
  cleanup() {
1513
+ this.restoreConsole();
1514
+
1146
1515
  // Restaurer les méthodes originales si elles existent
1147
1516
  if (this.framework) {
1148
1517
  if (this.originalNavigate) {
@@ -1190,6 +1559,8 @@ class DevTools {
1190
1559
  */
1191
1560
  attachToFramework() {
1192
1561
  window.devTools = this;
1562
+ // Intercepter la console
1563
+ this.interceptConsole();
1193
1564
 
1194
1565
  // Sauvegarder les références originales
1195
1566
  this.originalNavigate = this.framework.navigate;