canvasframework 0.3.21 → 0.3.23

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.
@@ -0,0 +1,139 @@
1
+ import AppBar from './AppBar.js';
2
+ /**
3
+ * SliverAppBar - CanvasFramework
4
+ * Collapse / Stretch / Parallax
5
+ * Compatible Material & Cupertino
6
+ * ⚠️ Ne modifie PAS AppBar
7
+ */
8
+ class SliverAppBar extends AppBar {
9
+ constructor(framework, options = {}) {
10
+ super(framework, {
11
+ ...options,
12
+ y: 0
13
+ });
14
+ // Heights
15
+ this.expandedHeight = options.expandedHeight || 240;
16
+ this.collapsedHeight = options.collapsedHeight ?? 56;
17
+ // Effects
18
+ this.stretch = options.stretch ?? true;
19
+ this.parallax = options.parallax ?? true;
20
+ this.parallaxFactor = options.parallaxFactor ?? 0.4;
21
+ // Background
22
+ this.backgroundImage = options.backgroundImage || null;
23
+ this.backgroundColor = options.backgroundColor || this.bgColor || '#FFFFFF';
24
+ this.backgroundOpacity = this._extractOpacity(this.backgroundColor);
25
+ // Overlay (au-dessus de l'image)
26
+ this.overlayColor = options.overlayColor || '#000000';
27
+ this.overlayOpacity = options.overlayOpacity ?? 0;
28
+ // Foreground (titre + icônes)
29
+ this.foregroundColor = options.foregroundColor || options.textColor || this.textColor || '#FFFFFF';
30
+ // SliverAppBar participe au scroll
31
+ this.fixed = false;
32
+ }
33
+
34
+ /**
35
+ * Extrait l'opacité d'une couleur rgba() ou retourne 1
36
+ */
37
+ _extractOpacity(color) {
38
+ if (typeof color === 'string' && color.startsWith('rgba')) {
39
+ const match = color.match(/rgba?\([^,]+,[^,]+,[^,]+,\s*([\d.]+)\)/);
40
+ return match ? parseFloat(match[1]) : 1;
41
+ }
42
+ return 1;
43
+ }
44
+
45
+ /**
46
+ * Mise à jour dynamique selon le scroll
47
+ */
48
+ updateWithScroll(scrollOffset) {
49
+ const scrollY = -scrollOffset;
50
+ const collapseRange = this.expandedHeight - this.collapsedHeight;
51
+ const collapse = Math.min(scrollY, collapseRange);
52
+ let newHeight = this.expandedHeight - collapse;
53
+ // Stretch (overscroll)
54
+ if (scrollY < 0 && this.stretch) {
55
+ newHeight = this.expandedHeight - scrollY;
56
+ }
57
+ this.height = Math.max(newHeight, this.collapsedHeight);
58
+ }
59
+
60
+ draw(ctx) {
61
+ const scrollOffset = this.framework.scrollOffset || 0;
62
+ this.updateWithScroll(scrollOffset);
63
+ ctx.save();
64
+ // ===== Collapse progress (0 → 1)
65
+ const collapseProgress = Math.min(
66
+ 1,
67
+ Math.max(
68
+ 0,
69
+ (this.expandedHeight - this.height) /
70
+ (this.expandedHeight - this.collapsedHeight)
71
+ )
72
+ );
73
+ // ===== BACKGROUND IMAGE (en premier) =====
74
+ if (this.backgroundImage && this.backgroundImage.complete) {
75
+ let bgOffset = 0;
76
+ if (this.parallax) {
77
+ bgOffset = Math.max(0, -scrollOffset * this.parallaxFactor);
78
+ }
79
+ ctx.drawImage(
80
+ this.backgroundImage,
81
+ this.x,
82
+ this.y - bgOffset,
83
+ this.width,
84
+ this.height + bgOffset
85
+ );
86
+ }
87
+
88
+ // ===== BACKGROUND COLOR (overlay coloré au-dessus de l'image) =====
89
+ ctx.globalAlpha = this.backgroundOpacity;
90
+ ctx.fillStyle = this.backgroundColor;
91
+ ctx.fillRect(this.x, this.y, this.width, this.height);
92
+ ctx.globalAlpha = 1;
93
+
94
+ // ===== OVERLAY SUPPLÉMENTAIRE (si besoin) =====
95
+ if (this.overlayOpacity > 0) {
96
+ ctx.globalAlpha = this.overlayOpacity;
97
+ ctx.fillStyle = this.overlayColor;
98
+ ctx.fillRect(this.x, this.y, this.width, this.height);
99
+ ctx.globalAlpha = 1;
100
+ }
101
+ // ===== TITLE (fade with collapse) =====
102
+ ctx.globalAlpha = 1 - collapseProgress;
103
+ ctx.fillStyle = this.foregroundColor;
104
+ ctx.font = `bold 20px -apple-system, Roboto, sans-serif`;
105
+ ctx.textAlign = 'left';
106
+ ctx.textBaseline = 'bottom';
107
+ ctx.fillText(
108
+ this.title,
109
+ this.x + 16,
110
+ this.y + this.height - 16
111
+ );
112
+ ctx.globalAlpha = 1;
113
+
114
+ // ===== PREVENT APPBAR BACKGROUND OVERWRITE =====
115
+ const originalBg = this.bgColor;
116
+ const originalTextColor = this.textColor;
117
+ const originalIconColor = this.iconColor;
118
+ const originalPlatform = this.platform;
119
+
120
+ // Force transparent pour éviter que super.draw() dessine un fond
121
+ this.bgColor = 'rgba(0,0,0,0)';
122
+ // Force la couleur du texte et des icônes
123
+ this.textColor = this.foregroundColor;
124
+ this.iconColor = this.foregroundColor;
125
+ // Force Material pour uniformiser le comportement des couleurs
126
+ this.platform = 'material';
127
+
128
+ // Icons, ripple, elevation, etc.
129
+ super.draw(ctx);
130
+
131
+ // Restore
132
+ this.bgColor = originalBg;
133
+ this.textColor = originalTextColor;
134
+ this.iconColor = originalIconColor;
135
+ this.platform = originalPlatform;
136
+ ctx.restore();
137
+ }
138
+ }
139
+ export default SliverAppBar;
@@ -52,6 +52,7 @@ import InputTags from '../components/InputTags.js';
52
52
  import InputDatalist from '../components/InputDatalist.js';
53
53
  import Banner from '../components/Banner.js';
54
54
  import Chart from '../components/Chart.js';
55
+ import SliverAppBar from '../components/SliverAppBar.js';
55
56
 
56
57
  // Utils
57
58
  import SafeArea from '../utils/SafeArea.js';
@@ -71,6 +72,12 @@ import AnimationEngine from '../utils/AnimationEngine.js';
71
72
  import CryptoManager from '../utils/CryptoManager.js';
72
73
  import NotificationManager from '../utils/NotificationManager.js';
73
74
 
75
+ // DevTools
76
+ import DevTools from '../utils/DevTools.js';
77
+ import InspectionOverlay from '../utils/InspectionOverlay.js';
78
+ import DevToolsConsole from '../utils/DevToolsConsole.js';
79
+
80
+
74
81
  // Features
75
82
  import PullToRefresh from '../features/PullToRefresh.js';
76
83
  import Skeleton from '../features/Skeleton.js';
@@ -126,6 +133,7 @@ const FIXED_COMPONENT_TYPES = new Set([
126
133
  FAB,
127
134
  Toast,
128
135
  Banner,
136
+ SliverAppBar,
129
137
  BottomSheet,
130
138
  ContextMenu,
131
139
  OpenStreetMap,
@@ -243,6 +251,96 @@ class CanvasFramework {
243
251
  this.setupEventListeners();
244
252
  this.setupHistoryListener();
245
253
  this.startRenderLoop();
254
+
255
+ this.devTools = new DevTools(this);
256
+ this.inspectionOverlay = new InspectionOverlay(this);
257
+
258
+ // MODIFICATION: Vérifier explicitement l'option enableDevTools
259
+ const shouldEnableDevTools = options.enableDevTools === true;
260
+
261
+ if (shouldEnableDevTools) {
262
+ this.enableDevTools();
263
+ console.log('DevTools enabled. Press Ctrl+Shift+D to toggle.');
264
+ }
265
+ }
266
+
267
+ /**
268
+ * Active ou désactive les DevTools
269
+ * @param {boolean} enabled - true pour activer, false pour désactiver
270
+ */
271
+ enableDevTools(enabled = true) {
272
+ if (enabled) {
273
+ // Créer le DevTools s'il n'existe pas
274
+ if (!this.devTools) {
275
+ this.devTools = new DevTools(this);
276
+ }
277
+
278
+ // Attacher seulement si pas déjà fait
279
+ if (!this.devTools._isAttached) {
280
+ this.devTools.attachToFramework();
281
+ this.devTools._isAttached = true;
282
+ }
283
+
284
+ // Afficher le bouton
285
+ if (this.devTools.toggleBtn) {
286
+ this.devTools.toggleBtn.style.display = 'block';
287
+ }
288
+ } else {
289
+ // Désactiver complètement
290
+ if (this.devTools) {
291
+ // Détacher du framework
292
+ if (this.devTools.detachFromFramework) {
293
+ this.devTools.detachFromFramework();
294
+ } else if (this.devTools.cleanup) {
295
+ this.devTools.cleanup();
296
+ }
297
+
298
+ // Supprimer de la page DOM
299
+ if (this.devTools.container && this.devTools.container.parentNode) {
300
+ this.devTools.container.parentNode.removeChild(this.devTools.container);
301
+ }
302
+
303
+ if (this.devTools.toggleBtn && this.devTools.toggleBtn.parentNode) {
304
+ this.devTools.toggleBtn.parentNode.removeChild(this.devTools.toggleBtn);
305
+ }
306
+
307
+ this.devTools._isAttached = false;
308
+ }
309
+ }
310
+ }
311
+
312
+ /**
313
+ * Bascule l'overlay d'inspection
314
+ */
315
+ toggleInspection() {
316
+ this.inspectionOverlay.toggle();
317
+ }
318
+
319
+ /**
320
+ * Exécute une commande DevTools
321
+ */
322
+ devToolsCommand(command, ...args) {
323
+ switch (command) {
324
+ case 'inspect':
325
+ this.inspectionOverlay.enable();
326
+ break;
327
+ case 'performance':
328
+ this.devTools.switchTab('performance');
329
+ this.devTools.toggle();
330
+ break;
331
+ case 'components':
332
+ this.devTools.switchTab('components');
333
+ this.devTools.toggle();
334
+ break;
335
+ case 'highlight':
336
+ if (args[0]) {
337
+ this.devTools.highlightComponent(args[0]);
338
+ }
339
+ break;
340
+ case 'reflow':
341
+ this.components.forEach(comp => comp.markDirty());
342
+ break;
343
+ }
246
344
  }
247
345
 
248
346
  wrapContext(ctx, theme) {
package/core/UIBuilder.js CHANGED
@@ -53,6 +53,7 @@ import InputTags from '../components/InputTags.js';
53
53
  import InputDatalist from '../components/InputDatalist.js';
54
54
  import Banner from '../components/Banner.js';
55
55
  import Chart from '../components/Chart.js';
56
+ import SliverAppBar from '../components/SliverAppBar.js';
56
57
 
57
58
  // Features
58
59
  import PullToRefresh from '../features/PullToRefresh.js';
@@ -92,6 +93,7 @@ const Components = {
92
93
  Modal,
93
94
  Drawer,
94
95
  AppBar,
96
+ SliverAppBar,
95
97
  Chip,
96
98
  Stepper,
97
99
  Accordion,
@@ -133,7 +135,6 @@ const Components = {
133
135
  Positioned,
134
136
  Banner,
135
137
  Chart,
136
- QRCode,
137
138
  Stack
138
139
  };
139
140
 
package/index.js CHANGED
@@ -60,6 +60,7 @@ export { default as InputTags } from './components/InputTags.js';
60
60
  export { default as InputDatalist } from './components/InputDatalist.js';
61
61
  export { default as Banner } from './components/Banner.js';
62
62
  export { default as Chart } from './components/Chart.js';
63
+ export { default as SliverAppBar } from './components/SliverAppBar.js';
63
64
 
64
65
  // Utils
65
66
  export { default as SafeArea } from './utils/SafeArea.js';
@@ -78,6 +79,7 @@ export { default as WebSocketClient } from './utils/WebSocketClient.js';
78
79
  export { default as AnimationEngine } from './utils/AnimationEngine.js';
79
80
  export { default as CryptoManager } from './utils/CryptoManager.js';
80
81
  export { default as NotificationManager } from './utils/NotificationManager.js';
82
+ export { default as DevTools } from './utils/DevTools.js';
81
83
 
82
84
  // Features
83
85
  export { default as PullToRefresh } from './features/PullToRefresh.js';
@@ -101,7 +103,7 @@ export { default as FeatureFlags } from './manager/FeatureFlags.js';
101
103
 
102
104
  // Version du framework
103
105
 
104
- export const VERSION = '0.3.21';
106
+ export const VERSION = '0.3.23';
105
107
 
106
108
 
107
109
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "canvasframework",
3
- "version": "0.3.21",
3
+ "version": "0.3.23",
4
4
  "description": "Canvas-based cross-platform UI framework (Material & Cupertino)",
5
5
  "type": "module",
6
6
  "main": "./index.js",