canvasframework 0.5.41 → 0.5.42
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.
- package/components/AppBar.js +107 -249
- package/components/BottomNavigationBar.js +143 -378
- package/components/FileUpload.js +225 -248
- package/package.json +1 -1
package/components/FileUpload.js
CHANGED
|
@@ -1,315 +1,292 @@
|
|
|
1
1
|
import Component from '../core/Component.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* Zone de téléchargement de fichiers
|
|
4
|
+
* Zone de téléchargement de fichiers (Material & Cupertino) - Bouton visuel seulement
|
|
5
5
|
* @class
|
|
6
6
|
* @extends Component
|
|
7
|
-
* @property {string} label - Texte affiché
|
|
8
|
-
* @property {string} sublabel - Sous-texte
|
|
9
|
-
* @property {string} accept - Types de fichiers acceptés
|
|
10
|
-
* @property {boolean} multiple - Accepter plusieurs fichiers
|
|
11
|
-
* @property {number} maxSize - Taille max en bytes
|
|
12
|
-
* @property {Array} files - Fichiers sélectionnés
|
|
13
|
-
* @property {boolean} isDragOver - État de survol
|
|
14
|
-
* @property {string} borderColor - Couleur de bordure
|
|
15
|
-
* @property {string} bgColor - Couleur de fond
|
|
16
|
-
* @property {string} iconColor - Couleur de l'icône
|
|
17
|
-
* @property {Function} onFilesSelected - Callback
|
|
18
|
-
* @property {Function} onError - Callback d'erreur
|
|
19
7
|
*/
|
|
20
8
|
class FileUpload extends Component {
|
|
21
|
-
/**
|
|
22
|
-
* Crée une instance de FileUpload
|
|
23
|
-
* @param {CanvasFramework} framework - Framework parent
|
|
24
|
-
* @param {Object} [options={}] - Options de configuration
|
|
25
|
-
* @param {string} [options.label='Drag & drop files here'] - Label
|
|
26
|
-
* @param {string} [options.sublabel='or click to browse'] - Sublabel
|
|
27
|
-
* @param {string} [options.accept='*'] - Types acceptés
|
|
28
|
-
* @param {boolean} [options.multiple=true] - Multiple fichiers
|
|
29
|
-
* @param {number} [options.maxSize=10485760] - Taille max (10MB)
|
|
30
|
-
* @param {Function} [options.onFilesSelected] - Callback
|
|
31
|
-
* @param {Function} [options.onError] - Callback erreur
|
|
32
|
-
*/
|
|
33
9
|
constructor(framework, options = {}) {
|
|
34
10
|
super(framework, options);
|
|
35
|
-
|
|
36
|
-
this.label = options.label || '
|
|
37
|
-
this.sublabel = options.sublabel || 'or click to browse';
|
|
11
|
+
|
|
12
|
+
this.label = options.label || 'Cliquez pour choisir un fichier';
|
|
38
13
|
this.accept = options.accept || '*';
|
|
39
14
|
this.multiple = options.multiple !== false;
|
|
40
|
-
this.
|
|
41
|
-
this.
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
const platform = framework.platform;
|
|
45
|
-
|
|
15
|
+
this.files = options.files || [];
|
|
16
|
+
this.platform = framework.platform;
|
|
17
|
+
|
|
46
18
|
// Styles selon la plateforme
|
|
47
|
-
if (platform === 'material') {
|
|
48
|
-
|
|
49
|
-
this.bgColor = 'rgba(98, 0, 238, 0.
|
|
50
|
-
this.
|
|
51
|
-
this.
|
|
52
|
-
this.
|
|
19
|
+
if (this.platform === 'material') {
|
|
20
|
+
// DESIGN MATERIAL AVEC RIPPLE PRONONCÉ
|
|
21
|
+
this.bgColor = options.bgColor || 'rgba(98, 0, 238, 0.04)';
|
|
22
|
+
this.borderColor = options.borderColor || '#6200EE';
|
|
23
|
+
this.iconColor = options.iconColor || '#6200EE';
|
|
24
|
+
this.borderRadius = options.borderRadius || 8;
|
|
25
|
+
this.borderWidth = options.borderWidth || 1.5;
|
|
26
|
+
this.borderStyle = 'dashed';
|
|
27
|
+
this.height = options.height || 90;
|
|
28
|
+
this.rippleColor = 'rgba(98, 0, 238, 0.3)'; // Ripple plus visible
|
|
29
|
+
this.elevation = 1;
|
|
53
30
|
} else {
|
|
54
|
-
|
|
55
|
-
this.bgColor =
|
|
56
|
-
this.
|
|
57
|
-
this.
|
|
58
|
-
this.
|
|
31
|
+
// DESIGN CUPERTINO
|
|
32
|
+
this.bgColor = options.bgColor || '#F2F2F7';
|
|
33
|
+
this.borderColor = options.borderColor || '#C6C6C8';
|
|
34
|
+
this.iconColor = options.iconColor || '#007AFF';
|
|
35
|
+
this.borderRadius = 14;
|
|
36
|
+
this.borderWidth = 0;
|
|
37
|
+
this.height = options.height || 80;
|
|
38
|
+
this.borderStyle = 'solid';
|
|
59
39
|
}
|
|
60
40
|
|
|
41
|
+
this.width = options.width || 300;
|
|
42
|
+
|
|
43
|
+
// Ripple effect Material - variables d'animation
|
|
44
|
+
this.ripples = [];
|
|
45
|
+
|
|
46
|
+
this.onClickCallback = options.onClick || null;
|
|
61
47
|
this.onFilesSelected = options.onFilesSelected || null;
|
|
62
|
-
|
|
48
|
+
|
|
49
|
+
if (options.onFilesSelected && !options.onClickCallback) {
|
|
50
|
+
this.onClickCallback = options.onFilesSelected;
|
|
51
|
+
}
|
|
63
52
|
|
|
64
|
-
//
|
|
65
|
-
this.
|
|
53
|
+
// Bind
|
|
54
|
+
this.onPress = this.handlePress.bind(this);
|
|
66
55
|
}
|
|
67
56
|
|
|
68
57
|
/**
|
|
69
|
-
*
|
|
70
|
-
* @private
|
|
58
|
+
* Gère la pression sur le bouton
|
|
71
59
|
*/
|
|
72
|
-
|
|
73
|
-
this.
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
60
|
+
handlePress(x, y) {
|
|
61
|
+
if (this.platform === 'material') {
|
|
62
|
+
const adjustedY = y - (this.framework.scrollOffset || 0);
|
|
63
|
+
this.ripples.push({
|
|
64
|
+
x: x - this.x,
|
|
65
|
+
y: adjustedY - this.y,
|
|
66
|
+
radius: 0,
|
|
67
|
+
maxRadius: Math.max(this.width, this.height) * 1.5,
|
|
68
|
+
opacity: 1
|
|
69
|
+
});
|
|
70
|
+
this.animateRipple();
|
|
71
|
+
}
|
|
83
72
|
}
|
|
84
73
|
|
|
85
74
|
/**
|
|
86
|
-
*
|
|
87
|
-
* @param {Array} fileList - Liste des fichiers
|
|
88
|
-
* @private
|
|
75
|
+
* Anime les effets ripple
|
|
89
76
|
*/
|
|
90
|
-
|
|
91
|
-
const
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
if (file.size > this.maxSize) {
|
|
96
|
-
if (this.onError) {
|
|
97
|
-
this.onError({
|
|
98
|
-
type: 'size',
|
|
99
|
-
message: `${file.name} exceeds max size of ${this.formatBytes(this.maxSize)}`,
|
|
100
|
-
file: file
|
|
101
|
-
});
|
|
102
|
-
}
|
|
103
|
-
continue;
|
|
77
|
+
animateRipple() {
|
|
78
|
+
const animate = () => {
|
|
79
|
+
for (let ripple of this.ripples) {
|
|
80
|
+
ripple.radius += ripple.maxRadius / 15;
|
|
81
|
+
ripple.opacity -= 0.05;
|
|
104
82
|
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
const fileExt = '.' + file.name.split('.').pop();
|
|
111
|
-
|
|
112
|
-
const isAccepted = acceptedTypes.some(type => {
|
|
113
|
-
if (type.startsWith('.')) {
|
|
114
|
-
return fileExt === type;
|
|
115
|
-
} else if (type.endsWith('/*')) {
|
|
116
|
-
return fileType.startsWith(type.replace('/*', ''));
|
|
117
|
-
} else {
|
|
118
|
-
return fileType === type;
|
|
119
|
-
}
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
if (!isAccepted) {
|
|
123
|
-
if (this.onError) {
|
|
124
|
-
this.onError({
|
|
125
|
-
type: 'type',
|
|
126
|
-
message: `${file.name} is not an accepted file type`,
|
|
127
|
-
file: file
|
|
128
|
-
});
|
|
129
|
-
}
|
|
130
|
-
continue;
|
|
131
|
-
}
|
|
83
|
+
|
|
84
|
+
this.ripples = this.ripples.filter(r => r.opacity > 0);
|
|
85
|
+
|
|
86
|
+
if (this.framework && this.framework.redraw) {
|
|
87
|
+
this.framework.redraw();
|
|
132
88
|
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
if (validFiles.length > 0) {
|
|
138
|
-
this.files = validFiles;
|
|
139
|
-
if (this.onFilesSelected) {
|
|
140
|
-
this.onFilesSelected(validFiles);
|
|
89
|
+
|
|
90
|
+
if (this.ripples.length > 0) {
|
|
91
|
+
requestAnimationFrame(animate);
|
|
141
92
|
}
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
animate();
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
handleRelease() {
|
|
99
|
+
this.pressed = false;
|
|
100
|
+
|
|
101
|
+
if (this.onClickCallback) {
|
|
102
|
+
this.onClickCallback(this.files);
|
|
142
103
|
}
|
|
143
104
|
|
|
144
|
-
|
|
145
|
-
|
|
105
|
+
if (this.framework && this.framework.redraw) {
|
|
106
|
+
this.framework.redraw();
|
|
107
|
+
}
|
|
146
108
|
}
|
|
147
109
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
110
|
+
setFiles(files) {
|
|
111
|
+
this.files = files;
|
|
112
|
+
if (this.framework && this.framework.redraw) {
|
|
113
|
+
this.framework.redraw();
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
addFile(file) {
|
|
118
|
+
this.files.push(file);
|
|
119
|
+
if (this.framework && this.framework.redraw) {
|
|
120
|
+
this.framework.redraw();
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
clearFiles() {
|
|
125
|
+
this.files = [];
|
|
126
|
+
if (this.framework && this.framework.redraw) {
|
|
127
|
+
this.framework.redraw();
|
|
128
|
+
}
|
|
160
129
|
}
|
|
161
130
|
|
|
162
|
-
/**
|
|
163
|
-
* Dessine le composant
|
|
164
|
-
* @param {CanvasRenderingContext2D} ctx - Contexte de dessin
|
|
165
|
-
*/
|
|
166
131
|
draw(ctx) {
|
|
167
132
|
ctx.save();
|
|
133
|
+
|
|
134
|
+
const radius = this.borderRadius;
|
|
168
135
|
|
|
169
|
-
//
|
|
170
|
-
|
|
171
|
-
|
|
136
|
+
// OMBRE POUR MATERIAL
|
|
137
|
+
if (this.platform === 'material' && this.elevation > 0 && !this.pressed) {
|
|
138
|
+
ctx.shadowColor = 'rgba(0, 0, 0, 0.08)';
|
|
139
|
+
ctx.shadowBlur = this.elevation * 4;
|
|
140
|
+
ctx.shadowOffsetY = this.elevation;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Background
|
|
144
|
+
let currentBgColor = this.bgColor;
|
|
145
|
+
if (this.pressed && this.platform === 'cupertino') {
|
|
146
|
+
currentBgColor = '#E5E5EA';
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
ctx.fillStyle = currentBgColor;
|
|
172
150
|
ctx.beginPath();
|
|
173
|
-
this.roundRect(ctx, this.x, this.y, this.width, this.height,
|
|
151
|
+
this.roundRect(ctx, this.x, this.y, this.width, this.height, radius);
|
|
174
152
|
ctx.fill();
|
|
175
|
-
|
|
176
|
-
//
|
|
177
|
-
ctx.
|
|
178
|
-
ctx.
|
|
179
|
-
ctx.
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
153
|
+
|
|
154
|
+
// Reset shadow
|
|
155
|
+
ctx.shadowColor = 'transparent';
|
|
156
|
+
ctx.shadowBlur = 0;
|
|
157
|
+
ctx.shadowOffsetY = 0;
|
|
158
|
+
|
|
159
|
+
// BORDURE
|
|
160
|
+
if (this.borderWidth > 0) {
|
|
161
|
+
ctx.strokeStyle = this.borderColor;
|
|
162
|
+
ctx.lineWidth = this.borderWidth;
|
|
163
|
+
|
|
164
|
+
if (this.platform === 'material' && this.borderStyle === 'dashed') {
|
|
165
|
+
ctx.setLineDash([6, 4]);
|
|
166
|
+
} else {
|
|
167
|
+
ctx.setLineDash([]);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
ctx.beginPath();
|
|
171
|
+
this.roundRect(ctx, this.x, this.y, this.width, this.height, radius);
|
|
172
|
+
ctx.stroke();
|
|
173
|
+
ctx.setLineDash([]);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// RIPPLE EFFECT (Material)
|
|
177
|
+
if (this.platform === 'material') {
|
|
178
|
+
ctx.save();
|
|
179
|
+
ctx.beginPath();
|
|
180
|
+
this.roundRect(ctx, this.x, this.y, this.width, this.height, radius);
|
|
181
|
+
ctx.clip();
|
|
182
|
+
|
|
183
|
+
for (let ripple of this.ripples) {
|
|
184
|
+
ctx.globalAlpha = ripple.opacity;
|
|
185
|
+
ctx.fillStyle = this.rippleColor;
|
|
186
|
+
ctx.beginPath();
|
|
187
|
+
ctx.arc(this.x + ripple.x, this.y + ripple.y, ripple.radius, 0, Math.PI * 2);
|
|
188
|
+
ctx.fill();
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
ctx.restore();
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// ICÔNE
|
|
195
|
+
const iconSize = this.platform === 'material' ? 32 : 28;
|
|
196
|
+
const iconX = this.x + this.width / 2;
|
|
197
|
+
const iconY = this.y + this.height / 2 - (this.files.length > 0 ? 15 : 8);
|
|
198
|
+
|
|
190
199
|
ctx.strokeStyle = this.iconColor;
|
|
191
|
-
ctx.lineWidth =
|
|
192
|
-
|
|
193
|
-
// Document
|
|
194
|
-
ctx.beginPath();
|
|
195
|
-
ctx.moveTo(iconX, iconY);
|
|
196
|
-
ctx.lineTo(iconX + iconSize * 0.7, iconY);
|
|
197
|
-
ctx.lineTo(iconX + iconSize, iconY + iconSize * 0.3);
|
|
198
|
-
ctx.lineTo(iconX + iconSize, iconY + iconSize);
|
|
199
|
-
ctx.lineTo(iconX, iconY + iconSize);
|
|
200
|
-
ctx.closePath();
|
|
201
|
-
ctx.stroke();
|
|
202
|
-
|
|
203
|
-
// Coin plié
|
|
204
|
-
ctx.beginPath();
|
|
205
|
-
ctx.moveTo(iconX + iconSize * 0.7, iconY);
|
|
206
|
-
ctx.lineTo(iconX + iconSize * 0.7, iconY + iconSize * 0.3);
|
|
207
|
-
ctx.lineTo(iconX + iconSize, iconY + iconSize * 0.3);
|
|
208
|
-
ctx.stroke();
|
|
209
|
-
|
|
210
|
-
// Flèche montante
|
|
211
|
-
const arrowX = iconX + iconSize / 2;
|
|
212
|
-
const arrowY = iconY + iconSize * 0.5;
|
|
213
|
-
const arrowSize = 12;
|
|
200
|
+
ctx.lineWidth = this.platform === 'material' ? 1.8 : 2;
|
|
201
|
+
ctx.lineCap = 'round';
|
|
214
202
|
|
|
203
|
+
// Ligne horizontale
|
|
215
204
|
ctx.beginPath();
|
|
216
|
-
ctx.moveTo(
|
|
217
|
-
ctx.lineTo(
|
|
205
|
+
ctx.moveTo(iconX - iconSize / 3, iconY);
|
|
206
|
+
ctx.lineTo(iconX + iconSize / 3, iconY);
|
|
218
207
|
ctx.stroke();
|
|
219
208
|
|
|
209
|
+
// Ligne verticale
|
|
220
210
|
ctx.beginPath();
|
|
221
|
-
ctx.moveTo(
|
|
222
|
-
ctx.lineTo(
|
|
223
|
-
ctx.lineTo(arrowX + arrowSize / 2, arrowY - arrowSize / 2);
|
|
211
|
+
ctx.moveTo(iconX, iconY - iconSize / 3);
|
|
212
|
+
ctx.lineTo(iconX, iconY + iconSize / 3);
|
|
224
213
|
ctx.stroke();
|
|
225
|
-
|
|
226
|
-
//
|
|
227
|
-
ctx.fillStyle = '#
|
|
228
|
-
ctx.font =
|
|
214
|
+
|
|
215
|
+
// LABEL
|
|
216
|
+
ctx.fillStyle = this.platform === 'material' ? '#5F6368' : '#3C3C43';
|
|
217
|
+
ctx.font = this.platform === 'material'
|
|
218
|
+
? '500 13px Roboto, sans-serif'
|
|
219
|
+
: '15px -apple-system, sans-serif';
|
|
229
220
|
ctx.textAlign = 'center';
|
|
230
221
|
ctx.textBaseline = 'middle';
|
|
231
|
-
ctx.fillText(this.label, this.x + this.width / 2, this.y + this.height / 2 + 30);
|
|
232
|
-
|
|
233
|
-
ctx.fillStyle = '#666666';
|
|
234
|
-
ctx.font = '14px -apple-system, BlinkMacSystemFont, Roboto, sans-serif';
|
|
235
|
-
ctx.fillText(this.sublabel, this.x + this.width / 2, this.y + this.height / 2 + 52);
|
|
236
222
|
|
|
237
|
-
|
|
223
|
+
const labelY = iconY + iconSize / 2 + 12;
|
|
224
|
+
ctx.fillText(this.label, this.x + this.width / 2, labelY);
|
|
225
|
+
|
|
226
|
+
// FICHIERS SÉLECTIONNÉS
|
|
238
227
|
if (this.files.length > 0) {
|
|
239
|
-
ctx.fillStyle = this.
|
|
240
|
-
ctx.font =
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
228
|
+
ctx.fillStyle = this.platform === 'material' ? '#6200EE' : '#007AFF';
|
|
229
|
+
ctx.font = this.platform === 'material'
|
|
230
|
+
? '400 11px Roboto, sans-serif'
|
|
231
|
+
: '13px -apple-system, sans-serif';
|
|
232
|
+
|
|
233
|
+
let fileText = '';
|
|
234
|
+
if (this.files.length === 1) {
|
|
235
|
+
fileText = this.truncateText(this.files[0].name, 25);
|
|
236
|
+
} else {
|
|
237
|
+
fileText = `${this.files.length} fichier${this.files.length > 1 ? 's' : ''}`;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
const fileIconY = this.y + this.height - 18;
|
|
241
|
+
|
|
242
|
+
if (this.platform === 'material') {
|
|
243
|
+
ctx.fillStyle = '#6200EE';
|
|
244
|
+
ctx.beginPath();
|
|
245
|
+
ctx.roundRect(this.x + this.width / 2 - 40, fileIconY - 2, 8, 10, 1);
|
|
246
|
+
ctx.fill();
|
|
247
|
+
ctx.beginPath();
|
|
248
|
+
ctx.moveTo(this.x + this.width / 2 - 32, fileIconY - 2);
|
|
249
|
+
ctx.lineTo(this.x + this.width / 2 - 32, fileIconY + 8);
|
|
250
|
+
ctx.lineTo(this.x + this.width / 2 - 40, fileIconY + 8);
|
|
251
|
+
ctx.closePath();
|
|
252
|
+
ctx.fill();
|
|
253
|
+
|
|
254
|
+
ctx.fillText(fileText, this.x + this.width / 2 + 5, fileIconY + 3);
|
|
255
|
+
} else {
|
|
256
|
+
ctx.fillText(`📎 ${fileText}`, this.x + this.width / 2, fileIconY);
|
|
257
|
+
}
|
|
245
258
|
}
|
|
246
|
-
|
|
259
|
+
|
|
247
260
|
ctx.restore();
|
|
248
261
|
}
|
|
249
262
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
ctx.lineTo(x + width, y + height - radius);
|
|
265
|
-
ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
|
|
266
|
-
ctx.lineTo(x + radius, y + height);
|
|
267
|
-
ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
|
|
268
|
-
ctx.lineTo(x, y + radius);
|
|
269
|
-
ctx.quadraticCurveTo(x, y, x + radius, y);
|
|
263
|
+
roundRect(ctx, x, y, w, h, r) {
|
|
264
|
+
if (r > 0) {
|
|
265
|
+
ctx.moveTo(x + r, y);
|
|
266
|
+
ctx.lineTo(x + w - r, y);
|
|
267
|
+
ctx.quadraticCurveTo(x + w, y, x + w, y + r);
|
|
268
|
+
ctx.lineTo(x + w, y + h - r);
|
|
269
|
+
ctx.quadraticCurveTo(x + w, y + h, x + w - r, y + h);
|
|
270
|
+
ctx.lineTo(x + r, y + h);
|
|
271
|
+
ctx.quadraticCurveTo(x, y + h, x, y + h - r);
|
|
272
|
+
ctx.lineTo(x, y + r);
|
|
273
|
+
ctx.quadraticCurveTo(x, y, x + r, y);
|
|
274
|
+
} else {
|
|
275
|
+
ctx.rect(x, y, w, h);
|
|
276
|
+
}
|
|
270
277
|
}
|
|
271
278
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
* @returns {string} Couleur éclaircie
|
|
276
|
-
* @private
|
|
277
|
-
*/
|
|
278
|
-
lightenColor(color) {
|
|
279
|
-
if (color.startsWith('rgba')) {
|
|
280
|
-
return color.replace(/[\d.]+\)$/g, '0.15)');
|
|
281
|
-
}
|
|
282
|
-
return color;
|
|
279
|
+
truncateText(text, maxLength) {
|
|
280
|
+
if (text.length <= maxLength) return text;
|
|
281
|
+
return text.substring(0, maxLength - 3) + '...';
|
|
283
282
|
}
|
|
284
283
|
|
|
285
|
-
/**
|
|
286
|
-
* Vérifie si un point est dans les limites
|
|
287
|
-
* @param {number} x - Coordonnée X
|
|
288
|
-
* @param {number} y - Coordonnée Y
|
|
289
|
-
* @returns {boolean} True si le point est dans le composant
|
|
290
|
-
*/
|
|
291
284
|
isPointInside(x, y) {
|
|
292
285
|
return x >= this.x &&
|
|
293
286
|
x <= this.x + this.width &&
|
|
294
287
|
y >= this.y &&
|
|
295
288
|
y <= this.y + this.height;
|
|
296
289
|
}
|
|
297
|
-
|
|
298
|
-
/**
|
|
299
|
-
* Override du onClick pour ouvrir le file picker
|
|
300
|
-
*/
|
|
301
|
-
onClick() {
|
|
302
|
-
this.fileInput.click();
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
/**
|
|
306
|
-
* Nettoie le composant
|
|
307
|
-
*/
|
|
308
|
-
destroy() {
|
|
309
|
-
if (this.fileInput && this.fileInput.parentNode) {
|
|
310
|
-
this.fileInput.parentNode.removeChild(this.fileInput);
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
290
|
}
|
|
314
291
|
|
|
315
292
|
export default FileUpload;
|