canvasframework 0.5.18 → 0.5.19
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/Accordion.js +265 -0
- package/components/AndroidDatePickerDialog.js +406 -0
- package/components/AppBar.js +398 -0
- package/components/AudioPlayer.js +611 -0
- package/components/Avatar.js +202 -0
- package/components/Banner.js +342 -0
- package/components/BottomNavigationBar.js +433 -0
- package/components/BottomSheet.js +234 -0
- package/components/Button.js +358 -0
- package/components/Camera.js +644 -0
- package/components/Card.js +193 -0
- package/components/Chart.js +700 -0
- package/components/Checkbox.js +166 -0
- package/components/Chip.js +212 -0
- package/components/CircularProgress.js +327 -0
- package/components/ContextMenu.js +116 -0
- package/components/DatePicker.js +298 -0
- package/components/Dialog.js +337 -0
- package/components/Divider.js +125 -0
- package/components/Drawer.js +276 -0
- package/components/FAB.js +270 -0
- package/components/FileUpload.js +315 -0
- package/components/FloatedCamera.js +644 -0
- package/components/IOSDatePickerWheel.js +430 -0
- package/components/ImageCarousel.js +219 -0
- package/components/ImageComponent.js +223 -0
- package/components/Input.js +831 -0
- package/components/InputDatalist.js +723 -0
- package/components/InputTags.js +624 -0
- package/components/List.js +95 -0
- package/components/ListItem.js +269 -0
- package/components/Modal.js +364 -0
- package/components/MorphingFAB.js +428 -0
- package/components/MultiSelectDialog.js +206 -0
- package/components/NumberInput.js +271 -0
- package/components/PasswordInput.js +462 -0
- package/components/ProgressBar.js +88 -0
- package/components/QRCodeReader.js +539 -0
- package/components/RadioButton.js +151 -0
- package/components/SearchInput.js +315 -0
- package/components/SegmentedControl.js +357 -0
- package/components/Select.js +199 -0
- package/components/SelectDialog.js +255 -0
- package/components/Slider.js +113 -0
- package/components/SliverAppBar.js +139 -0
- package/components/Snackbar.js +243 -0
- package/components/SpeedDialFAB.js +397 -0
- package/components/Stepper.js +281 -0
- package/components/SwipeableListItem.js +327 -0
- package/components/Switch.js +147 -0
- package/components/Table.js +492 -0
- package/components/Tabs.js +423 -0
- package/components/Text.js +141 -0
- package/components/TextField.js +151 -0
- package/components/TimePicker.js +934 -0
- package/components/Toast.js +236 -0
- package/components/TreeView.js +420 -0
- package/components/Video.js +397 -0
- package/components/View.js +140 -0
- package/components/VirtualList.js +120 -0
- package/core/CanvasFramework.js +3045 -0
- package/core/Component.js +243 -0
- package/core/ThemeManager.js +358 -0
- package/core/UIBuilder.js +267 -0
- package/core/WebGLCanvasAdapter.js +782 -0
- package/features/Column.js +43 -0
- package/features/Grid.js +47 -0
- package/features/LayoutComponent.js +43 -0
- package/features/OpenStreetMap.js +310 -0
- package/features/Positioned.js +33 -0
- package/features/PullToRefresh.js +328 -0
- package/features/Row.js +40 -0
- package/features/SignaturePad.js +257 -0
- package/features/Skeleton.js +193 -0
- package/features/Stack.js +21 -0
- package/index.js +119 -0
- package/manager/AccessibilityManager.js +107 -0
- package/manager/ErrorHandler.js +59 -0
- package/manager/FeatureFlags.js +60 -0
- package/manager/MemoryManager.js +107 -0
- package/manager/PerformanceMonitor.js +84 -0
- package/manager/SecurityManager.js +54 -0
- package/package.json +22 -16
- package/utils/AnimationEngine.js +734 -0
- package/utils/CryptoManager.js +303 -0
- package/utils/DataStore.js +403 -0
- package/utils/DevTools.js +1618 -0
- package/utils/DevToolsConsole.js +201 -0
- package/utils/EventBus.js +407 -0
- package/utils/FetchClient.js +74 -0
- package/utils/FirebaseAuth.js +653 -0
- package/utils/FirebaseCore.js +246 -0
- package/utils/FirebaseFirestore.js +581 -0
- package/utils/FirebaseFunctions.js +97 -0
- package/utils/FirebaseRealtimeDB.js +498 -0
- package/utils/FirebaseStorage.js +612 -0
- package/utils/FormValidator.js +355 -0
- package/utils/GeoLocationService.js +62 -0
- package/utils/I18n.js +207 -0
- package/utils/IndexedDBManager.js +273 -0
- package/utils/InspectionOverlay.js +308 -0
- package/utils/NotificationManager.js +60 -0
- package/utils/OfflineSyncManager.js +342 -0
- package/utils/PayPalPayment.js +678 -0
- package/utils/QueryBuilder.js +478 -0
- package/utils/SafeArea.js +64 -0
- package/utils/SecureStorage.js +289 -0
- package/utils/StateManager.js +207 -0
- package/utils/StripePayment.js +552 -0
- package/utils/WebSocketClient.js +66 -0
- package/dist/canvasframework.js +0 -2
- package/dist/canvasframework.js.LICENSE.txt +0 -1
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
import Component from '../core/Component.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Zone de téléchargement de fichiers avec drag & drop
|
|
5
|
+
* @class
|
|
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
|
+
*/
|
|
20
|
+
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
|
+
constructor(framework, options = {}) {
|
|
34
|
+
super(framework, options);
|
|
35
|
+
|
|
36
|
+
this.label = options.label || 'Drag & drop files here';
|
|
37
|
+
this.sublabel = options.sublabel || 'or click to browse';
|
|
38
|
+
this.accept = options.accept || '*';
|
|
39
|
+
this.multiple = options.multiple !== false;
|
|
40
|
+
this.maxSize = options.maxSize || 10485760; // 10MB
|
|
41
|
+
this.files = [];
|
|
42
|
+
this.isDragOver = false;
|
|
43
|
+
|
|
44
|
+
const platform = framework.platform;
|
|
45
|
+
|
|
46
|
+
// Styles selon la plateforme
|
|
47
|
+
if (platform === 'material') {
|
|
48
|
+
this.borderColor = '#6200EE';
|
|
49
|
+
this.bgColor = 'rgba(98, 0, 238, 0.05)';
|
|
50
|
+
this.iconColor = '#6200EE';
|
|
51
|
+
this.borderRadius = 4;
|
|
52
|
+
this.borderWidth = 2;
|
|
53
|
+
} else {
|
|
54
|
+
this.borderColor = '#007AFF';
|
|
55
|
+
this.bgColor = 'rgba(0, 122, 255, 0.05)';
|
|
56
|
+
this.iconColor = '#007AFF';
|
|
57
|
+
this.borderRadius = 12;
|
|
58
|
+
this.borderWidth = 2;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
this.onFilesSelected = options.onFilesSelected || null;
|
|
62
|
+
this.onError = options.onError || null;
|
|
63
|
+
|
|
64
|
+
// Créer un input file caché
|
|
65
|
+
this.createFileInput();
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Crée l'input file HTML caché
|
|
70
|
+
* @private
|
|
71
|
+
*/
|
|
72
|
+
createFileInput() {
|
|
73
|
+
this.fileInput = document.createElement('input');
|
|
74
|
+
this.fileInput.type = 'file';
|
|
75
|
+
this.fileInput.accept = this.accept;
|
|
76
|
+
this.fileInput.multiple = this.multiple;
|
|
77
|
+
this.fileInput.style.display = 'none';
|
|
78
|
+
document.body.appendChild(this.fileInput);
|
|
79
|
+
|
|
80
|
+
this.fileInput.addEventListener('change', (e) => {
|
|
81
|
+
this.handleFiles(Array.from(e.target.files));
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Gère les fichiers sélectionnés
|
|
87
|
+
* @param {Array} fileList - Liste des fichiers
|
|
88
|
+
* @private
|
|
89
|
+
*/
|
|
90
|
+
handleFiles(fileList) {
|
|
91
|
+
const validFiles = [];
|
|
92
|
+
|
|
93
|
+
for (let file of fileList) {
|
|
94
|
+
// Vérifier la taille
|
|
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;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Vérifier le type si spécifié
|
|
107
|
+
if (this.accept !== '*') {
|
|
108
|
+
const acceptedTypes = this.accept.split(',').map(t => t.trim());
|
|
109
|
+
const fileType = file.type;
|
|
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
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
validFiles.push(file);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (validFiles.length > 0) {
|
|
138
|
+
this.files = validFiles;
|
|
139
|
+
if (this.onFilesSelected) {
|
|
140
|
+
this.onFilesSelected(validFiles);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Reset input
|
|
145
|
+
this.fileInput.value = '';
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Formate les bytes en format lisible
|
|
150
|
+
* @param {number} bytes - Nombre de bytes
|
|
151
|
+
* @returns {string} Taille formatée
|
|
152
|
+
* @private
|
|
153
|
+
*/
|
|
154
|
+
formatBytes(bytes) {
|
|
155
|
+
if (bytes === 0) return '0 Bytes';
|
|
156
|
+
const k = 1024;
|
|
157
|
+
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
|
|
158
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
159
|
+
return Math.round(bytes / Math.pow(k, i) * 100) / 100 + ' ' + sizes[i];
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Dessine le composant
|
|
164
|
+
* @param {CanvasRenderingContext2D} ctx - Contexte de dessin
|
|
165
|
+
*/
|
|
166
|
+
draw(ctx) {
|
|
167
|
+
ctx.save();
|
|
168
|
+
|
|
169
|
+
// Fond
|
|
170
|
+
ctx.fillStyle = this.isDragOver || this.pressed ?
|
|
171
|
+
this.lightenColor(this.bgColor) : this.bgColor;
|
|
172
|
+
ctx.beginPath();
|
|
173
|
+
this.roundRect(ctx, this.x, this.y, this.width, this.height, this.borderRadius);
|
|
174
|
+
ctx.fill();
|
|
175
|
+
|
|
176
|
+
// Bordure en pointillés
|
|
177
|
+
ctx.strokeStyle = this.borderColor;
|
|
178
|
+
ctx.lineWidth = this.borderWidth;
|
|
179
|
+
ctx.setLineDash([8, 8]);
|
|
180
|
+
ctx.beginPath();
|
|
181
|
+
this.roundRect(ctx, this.x, this.y, this.width, this.height, this.borderRadius);
|
|
182
|
+
ctx.stroke();
|
|
183
|
+
ctx.setLineDash([]);
|
|
184
|
+
|
|
185
|
+
// Icône de fichier (simple)
|
|
186
|
+
const iconSize = 40;
|
|
187
|
+
const iconX = this.x + this.width / 2 - iconSize / 2;
|
|
188
|
+
const iconY = this.y + this.height / 2 - 40;
|
|
189
|
+
|
|
190
|
+
ctx.strokeStyle = this.iconColor;
|
|
191
|
+
ctx.lineWidth = 3;
|
|
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;
|
|
214
|
+
|
|
215
|
+
ctx.beginPath();
|
|
216
|
+
ctx.moveTo(arrowX, arrowY - arrowSize);
|
|
217
|
+
ctx.lineTo(arrowX, arrowY + arrowSize);
|
|
218
|
+
ctx.stroke();
|
|
219
|
+
|
|
220
|
+
ctx.beginPath();
|
|
221
|
+
ctx.moveTo(arrowX - arrowSize / 2, arrowY - arrowSize / 2);
|
|
222
|
+
ctx.lineTo(arrowX, arrowY - arrowSize);
|
|
223
|
+
ctx.lineTo(arrowX + arrowSize / 2, arrowY - arrowSize / 2);
|
|
224
|
+
ctx.stroke();
|
|
225
|
+
|
|
226
|
+
// Texte
|
|
227
|
+
ctx.fillStyle = '#000000';
|
|
228
|
+
ctx.font = '16px -apple-system, BlinkMacSystemFont, Roboto, sans-serif';
|
|
229
|
+
ctx.textAlign = 'center';
|
|
230
|
+
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
|
+
|
|
237
|
+
// Afficher les fichiers sélectionnés
|
|
238
|
+
if (this.files.length > 0) {
|
|
239
|
+
ctx.fillStyle = this.borderColor;
|
|
240
|
+
ctx.font = '12px -apple-system, BlinkMacSystemFont, Roboto, sans-serif';
|
|
241
|
+
const fileText = this.files.length === 1 ?
|
|
242
|
+
this.files[0].name :
|
|
243
|
+
`${this.files.length} files selected`;
|
|
244
|
+
ctx.fillText(fileText, this.x + this.width / 2, this.y + this.height - 20);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
ctx.restore();
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Dessine un rectangle avec coins arrondis
|
|
252
|
+
* @param {CanvasRenderingContext2D} ctx - Contexte de dessin
|
|
253
|
+
* @param {number} x - Position X
|
|
254
|
+
* @param {number} y - Position Y
|
|
255
|
+
* @param {number} width - Largeur
|
|
256
|
+
* @param {number} height - Hauteur
|
|
257
|
+
* @param {number} radius - Rayon des coins
|
|
258
|
+
* @private
|
|
259
|
+
*/
|
|
260
|
+
roundRect(ctx, x, y, width, height, radius) {
|
|
261
|
+
ctx.moveTo(x + radius, y);
|
|
262
|
+
ctx.lineTo(x + width - radius, y);
|
|
263
|
+
ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
|
|
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);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Éclaircit une couleur
|
|
274
|
+
* @param {string} color - Couleur
|
|
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;
|
|
283
|
+
}
|
|
284
|
+
|
|
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
|
+
isPointInside(x, y) {
|
|
292
|
+
return x >= this.x &&
|
|
293
|
+
x <= this.x + this.width &&
|
|
294
|
+
y >= this.y &&
|
|
295
|
+
y <= this.y + this.height;
|
|
296
|
+
}
|
|
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
|
+
}
|
|
314
|
+
|
|
315
|
+
export default FileUpload;
|