canvasframework 0.5.26 → 0.5.28

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.
Files changed (2) hide show
  1. package/components/Card.js +195 -94
  2. package/package.json +1 -1
@@ -8,11 +8,12 @@ import Component from '../core/Component.js';
8
8
  * @property {number} padding - Padding interne
9
9
  * @property {number} gap - Espacement constant entre enfants
10
10
  * @property {string} direction - Direction ('column' ou 'row')
11
- * @property {string} align - Alignement ('start', 'center', 'end', 'stretch')
11
+ * @property {string} align - Alignement ('start', 'center', 'end')
12
12
  * @property {string} bgColor - Couleur de fond
13
13
  * @property {number} borderRadius - Rayon des coins
14
14
  * @property {number} elevation - Niveau d'élévation (ombres)
15
- * @property {boolean} autoHeight - Ajuste automatiquement la hauteur selon le contenu
15
+ * @property {boolean} autoLayout - Active le layout automatique
16
+ * @property {Map} childPositions - Positions relatives des enfants
16
17
  */
17
18
  class Card extends Component {
18
19
  /**
@@ -26,19 +27,22 @@ class Card extends Component {
26
27
  * @param {string} [options.bgColor='transparent'] - Couleur de fond
27
28
  * @param {number} [options.borderRadius=0] - Rayon des coins
28
29
  * @param {number} [options.elevation=0] - Niveau d'élévation (0-5)
29
- * @param {boolean} [options.autoHeight=false] - Ajuste automatiquement la hauteur
30
+ * @param {boolean} [options.autoLayout=true] - Active le layout automatique
30
31
  */
31
32
  constructor(framework, options = {}) {
32
33
  super(framework, options);
33
34
  this.children = [];
34
35
  this.padding = options.padding || 0;
35
- this.gap = options.gap || 0; // Espacement constant entre chaque enfant
36
+ this.gap = options.gap || 0;
36
37
  this.direction = options.direction || 'column';
37
38
  this.align = options.align || 'start';
38
39
  this.bgColor = options.bgColor || 'transparent';
39
40
  this.borderRadius = options.borderRadius || 0;
40
41
  this.elevation = options.elevation || 0;
41
- this.autoHeight = options.autoHeight || false;
42
+ this.autoLayout = options.autoLayout !== undefined ? options.autoLayout : true;
43
+
44
+ // Stocker les positions relatives des enfants
45
+ this.childPositions = new Map();
42
46
  }
43
47
 
44
48
  /**
@@ -48,7 +52,17 @@ class Card extends Component {
48
52
  */
49
53
  add(child) {
50
54
  this.children.push(child);
51
- this.layout();
55
+
56
+ // Si autoLayout est activé, organiser automatiquement
57
+ if (this.autoLayout) {
58
+ this.layout();
59
+ } else {
60
+ // En mode manuel, calculer et stocker la position relative
61
+ const relativeX = child.x - this.x;
62
+ const relativeY = child.y - this.y;
63
+ this.childPositions.set(child, { x: relativeX, y: relativeY });
64
+ }
65
+
52
66
  return child;
53
67
  }
54
68
 
@@ -61,7 +75,8 @@ class Card extends Component {
61
75
  const index = this.children.indexOf(child);
62
76
  if (index > -1) {
63
77
  this.children.splice(index, 1);
64
- this.layout();
78
+ this.childPositions.delete(child);
79
+ if (this.autoLayout) this.layout();
65
80
  return true;
66
81
  }
67
82
  return false;
@@ -72,91 +87,127 @@ class Card extends Component {
72
87
  */
73
88
  clear() {
74
89
  this.children = [];
75
- this.layout();
90
+ this.childPositions.clear();
91
+ if (this.autoLayout) this.layout();
76
92
  }
77
93
 
78
94
  /**
79
- * Organise les enfants selon le layout avec espacement constant
95
+ * Organise les enfants selon le layout
80
96
  * @private
81
97
  */
82
98
  layout() {
83
- if (this.children.length === 0) return;
99
+ if (this.children.length === 0 || !this.autoLayout) return;
84
100
 
85
- let currentX = this.x + this.padding;
86
- let currentY = this.y + this.padding;
87
-
88
101
  if (this.direction === 'column') {
102
+ let currentY = this.padding;
103
+
89
104
  for (let i = 0; i < this.children.length; i++) {
90
105
  const child = this.children[i];
91
106
 
92
- // Positionner l'enfant
93
- child.x = currentX;
94
- child.y = currentY;
95
-
96
- // Gérer l'alignement horizontal
107
+ // Calculer la position X selon l'alignement
108
+ let childX = this.padding;
97
109
  if (this.align === 'center') {
98
- child.x = this.x + (this.width - child.width) / 2;
110
+ childX = (this.width - child.width) / 2;
99
111
  } else if (this.align === 'end') {
100
- child.x = this.x + this.width - child.width - this.padding;
101
- } else if (this.align === 'stretch') {
102
- child.x = this.x + this.padding;
103
- child.width = this.width - (this.padding * 2);
112
+ childX = this.width - child.width - this.padding;
104
113
  }
105
114
 
115
+ // Positionner l'enfant RELATIVEMENT à la Card
116
+ child.x = this.x + childX;
117
+ child.y = this.y + currentY;
118
+
119
+ // Stocker la position relative
120
+ this.childPositions.set(child, { x: childX, y: currentY });
121
+
106
122
  // Mettre à jour la position Y pour l'enfant suivant
107
- // Toujours le même espacement (gap) entre chaque enfant
108
- currentY += child.height + this.gap;
109
- }
110
-
111
- // Ajuster la hauteur automatiquement si autoHeight est activé
112
- if (this.autoHeight) {
113
- const totalChildrenHeight = this.children.reduce((sum, child) => sum + child.height, 0);
114
- const totalGapHeight = this.gap * Math.max(0, this.children.length - 1);
115
- const neededHeight = totalChildrenHeight + totalGapHeight + (this.padding * 2);
123
+ currentY += child.height;
116
124
 
117
- if (neededHeight !== this.height) {
118
- this.height = neededHeight;
119
- // Notifier un changement de dimensions
120
- if (this.onResize) this.onResize(this.width, this.height);
125
+ // Ajouter le gap seulement si ce n'est pas le dernier enfant
126
+ if (i < this.children.length - 1) {
127
+ currentY += this.gap;
121
128
  }
122
129
  }
123
130
  } else {
124
- // Direction 'row' (logique similaire pour l'alignement horizontal)
131
+ // Direction 'row'
132
+ let currentX = this.padding;
133
+
125
134
  for (let i = 0; i < this.children.length; i++) {
126
135
  const child = this.children[i];
127
136
 
128
- child.x = currentX;
129
- child.y = currentY;
130
-
131
- // Gérer l'alignement vertical
137
+ // Calculer la position Y selon l'alignement
138
+ let childY = this.padding;
132
139
  if (this.align === 'center') {
133
- child.y = this.y + (this.height - child.height) / 2;
140
+ childY = (this.height - child.height) / 2;
134
141
  } else if (this.align === 'end') {
135
- child.y = this.y + this.height - child.height - this.padding;
136
- } else if (this.align === 'stretch') {
137
- child.y = this.y + this.padding;
138
- child.height = this.height - (this.padding * 2);
142
+ childY = this.height - child.height - this.padding;
139
143
  }
140
144
 
141
- // Espacement constant entre chaque enfant
142
- currentX += child.width + this.gap;
143
- }
144
-
145
- // Ajuster la largeur automatiquement si autoHeight est activé (pour row)
146
- if (this.autoHeight) {
147
- const totalChildrenWidth = this.children.reduce((sum, child) => sum + child.width, 0);
148
- const totalGapWidth = this.gap * Math.max(0, this.children.length - 1);
149
- const neededWidth = totalChildrenWidth + totalGapWidth + (this.padding * 2);
145
+ // Positionner l'enfant RELATIVEMENT à la Card
146
+ child.x = this.x + currentX;
147
+ child.y = this.y + childY;
150
148
 
151
- if (neededWidth !== this.width) {
152
- this.width = neededWidth;
153
- // Notifier un changement de dimensions
154
- if (this.onResize) this.onResize(this.width, this.height);
149
+ // Stocker la position relative
150
+ this.childPositions.set(child, { x: currentX, y: childY });
151
+
152
+ // Mettre à jour la position X pour l'enfant suivant
153
+ currentX += child.width;
154
+
155
+ // Ajouter le gap seulement si ce n'est pas le dernier enfant
156
+ if (i < this.children.length - 1) {
157
+ currentX += this.gap;
155
158
  }
156
159
  }
157
160
  }
158
161
  }
159
162
 
163
+ /**
164
+ * Met à jour la position de la carte et ajuste les enfants
165
+ * @param {number} x - Nouvelle position X
166
+ * @param {number} y - Nouvelle position Y
167
+ */
168
+ setPosition(x, y) {
169
+ const deltaX = x - this.x;
170
+ const deltaY = y - this.y;
171
+
172
+ super.setPosition(x, y);
173
+
174
+ // Déplacer tous les enfants avec la carte
175
+ for (let child of this.children) {
176
+ child.x += deltaX;
177
+ child.y += deltaY;
178
+ }
179
+ }
180
+
181
+ /**
182
+ * Définit la position d'un enfant dans le système de coordonnées de la Card
183
+ * @param {Component} child - L'enfant à positionner
184
+ * @param {number} relativeX - Position X relative à la Card
185
+ * @param {number} relativeY - Position Y relative à la Card
186
+ */
187
+ setChildPosition(child, relativeX, relativeY) {
188
+ if (this.children.includes(child)) {
189
+ child.x = this.x + relativeX;
190
+ child.y = this.y + relativeY;
191
+ this.childPositions.set(child, { x: relativeX, y: relativeY });
192
+ }
193
+ }
194
+
195
+ /**
196
+ * Active/désactive le layout automatique
197
+ * @param {boolean} enabled - True pour activer le layout automatique
198
+ */
199
+ setAutoLayout(enabled) {
200
+ this.autoLayout = enabled;
201
+ if (enabled) this.layout();
202
+ }
203
+
204
+ /**
205
+ * Force un recalcul du layout
206
+ */
207
+ updateLayout() {
208
+ this.layout();
209
+ }
210
+
160
211
  /**
161
212
  * Génère les paramètres d'ombre selon le niveau d'élévation
162
213
  * @param {number} elevation - Niveau d'élévation (0-5)
@@ -230,7 +281,7 @@ class Card extends Component {
230
281
  }
231
282
  }
232
283
 
233
- // Appliquer le clipping pour le borderRadius (empêche les débordements)
284
+ // Appliquer le clipping si borderRadius > 0
234
285
  if (this.borderRadius > 0) {
235
286
  ctx.beginPath();
236
287
  this.roundRect(ctx, this.x, this.y, this.width, this.height, this.borderRadius);
@@ -309,41 +360,13 @@ class Card extends Component {
309
360
  this.setElevation(this.elevation - 1);
310
361
  }
311
362
 
312
- /**
313
- * Met à jour la position de la carte (surcharge pour recalculer le layout)
314
- * @param {number} x - Nouvelle position X
315
- * @param {number} y - Nouvelle position Y
316
- */
317
- setPosition(x, y) {
318
- const deltaX = x - this.x;
319
- const deltaY = y - this.y;
320
-
321
- super.setPosition(x, y);
322
-
323
- // Déplacer tous les enfants avec la carte
324
- for (let child of this.children) {
325
- child.x += deltaX;
326
- child.y += deltaY;
327
- }
328
- }
329
-
330
- /**
331
- * Met à jour les dimensions (surcharge pour recalculer le layout)
332
- * @param {number} width - Nouvelle largeur
333
- * @param {number} height - Nouvelle hauteur
334
- */
335
- setSize(width, height) {
336
- super.setSize(width, height);
337
- this.layout();
338
- }
339
-
340
363
  /**
341
364
  * Définit l'espacement entre enfants
342
365
  * @param {number} gap - Nouvel espacement
343
366
  */
344
367
  setGap(gap) {
345
368
  this.gap = Math.max(0, gap);
346
- this.layout();
369
+ if (this.autoLayout) this.layout();
347
370
  }
348
371
 
349
372
  /**
@@ -352,7 +375,7 @@ class Card extends Component {
352
375
  */
353
376
  setPadding(padding) {
354
377
  this.padding = Math.max(0, padding);
355
- this.layout();
378
+ if (this.autoLayout) this.layout();
356
379
  }
357
380
 
358
381
  /**
@@ -362,20 +385,98 @@ class Card extends Component {
362
385
  setDirection(direction) {
363
386
  if (direction === 'column' || direction === 'row') {
364
387
  this.direction = direction;
365
- this.layout();
388
+ if (this.autoLayout) this.layout();
366
389
  }
367
390
  }
368
391
 
369
392
  /**
370
393
  * Définit l'alignement
371
- * @param {string} align - 'start', 'center', 'end' ou 'stretch'
394
+ * @param {string} align - 'start', 'center', 'end'
372
395
  */
373
396
  setAlign(align) {
374
- if (['start', 'center', 'end', 'stretch'].includes(align)) {
397
+ if (['start', 'center', 'end'].includes(align)) {
375
398
  this.align = align;
376
- this.layout();
399
+ if (this.autoLayout) this.layout();
400
+ }
401
+ }
402
+
403
+ /**
404
+ * Calcule la hauteur totale nécessaire pour contenir tous les enfants
405
+ * @returns {number} Hauteur totale nécessaire
406
+ */
407
+ getTotalHeight() {
408
+ if (this.children.length === 0) return 0;
409
+
410
+ if (this.direction === 'column') {
411
+ const totalChildrenHeight = this.children.reduce((sum, child) => sum + child.height, 0);
412
+ const totalGapHeight = this.gap * Math.max(0, this.children.length - 1);
413
+ return totalChildrenHeight + totalGapHeight + (this.padding * 2);
414
+ }
415
+ return this.height;
416
+ }
417
+
418
+ /**
419
+ * Calcule la largeur totale nécessaire pour contenir tous les enfants
420
+ * @returns {number} Largeur totale nécessaire
421
+ */
422
+ getTotalWidth() {
423
+ if (this.children.length === 0) return 0;
424
+
425
+ if (this.direction === 'row') {
426
+ const totalChildrenWidth = this.children.reduce((sum, child) => sum + child.width, 0);
427
+ const totalGapWidth = this.gap * Math.max(0, this.children.length - 1);
428
+ return totalChildrenWidth + totalGapWidth + (this.padding * 2);
429
+ }
430
+ return this.width;
431
+ }
432
+
433
+ /**
434
+ * Ajuste automatiquement la hauteur de la carte pour contenir tous les enfants
435
+ */
436
+ fitHeight() {
437
+ if (this.direction === 'column') {
438
+ this.height = this.getTotalHeight();
377
439
  }
378
440
  }
441
+
442
+ /**
443
+ * Ajuste automatiquement la largeur de la carte pour contenir tous les enfants
444
+ */
445
+ fitWidth() {
446
+ if (this.direction === 'row') {
447
+ this.width = this.getTotalWidth();
448
+ }
449
+ }
450
+
451
+ /**
452
+ * Ajuste automatiquement les dimensions de la carte pour contenir tous les enfants
453
+ */
454
+ fitSize() {
455
+ if (this.direction === 'column') {
456
+ this.height = this.getTotalHeight();
457
+ } else if (this.direction === 'row') {
458
+ this.width = this.getTotalWidth();
459
+ }
460
+ }
461
+
462
+ /**
463
+ * Met à jour les dimensions et relayout si autoLayout est activé
464
+ * @param {number} width - Nouvelle largeur
465
+ * @param {number} height - Nouvelle hauteur
466
+ */
467
+ setSize(width, height) {
468
+ super.setSize(width, height);
469
+ if (this.autoLayout) this.layout();
470
+ }
471
+
472
+ /**
473
+ * Obtient la position relative d'un enfant
474
+ * @param {Component} child - L'enfant
475
+ * @returns {Object|null} Position relative {x, y} ou null si non trouvé
476
+ */
477
+ getChildPosition(child) {
478
+ return this.childPositions.get(child) || null;
479
+ }
379
480
  }
380
481
 
381
482
  export default Card;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "canvasframework",
3
- "version": "0.5.26",
3
+ "version": "0.5.28",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/beyons/CanvasFramework.git"