canvasframework 0.3.6

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 (85) hide show
  1. package/README.md +554 -0
  2. package/components/Accordion.js +252 -0
  3. package/components/AndroidDatePickerDialog.js +398 -0
  4. package/components/AppBar.js +225 -0
  5. package/components/Avatar.js +202 -0
  6. package/components/BottomNavigationBar.js +205 -0
  7. package/components/BottomSheet.js +374 -0
  8. package/components/Button.js +225 -0
  9. package/components/Card.js +193 -0
  10. package/components/Checkbox.js +180 -0
  11. package/components/Chip.js +212 -0
  12. package/components/CircularProgress.js +143 -0
  13. package/components/ContextMenu.js +116 -0
  14. package/components/DatePicker.js +257 -0
  15. package/components/Dialog.js +367 -0
  16. package/components/Divider.js +125 -0
  17. package/components/Drawer.js +261 -0
  18. package/components/FAB.js +270 -0
  19. package/components/FileUpload.js +315 -0
  20. package/components/IOSDatePickerWheel.js +268 -0
  21. package/components/ImageCarousel.js +193 -0
  22. package/components/ImageComponent.js +223 -0
  23. package/components/Input.js +309 -0
  24. package/components/List.js +94 -0
  25. package/components/ListItem.js +223 -0
  26. package/components/Modal.js +364 -0
  27. package/components/MultiSelectDialog.js +206 -0
  28. package/components/NumberInput.js +271 -0
  29. package/components/ProgressBar.js +88 -0
  30. package/components/RadioButton.js +142 -0
  31. package/components/SearchInput.js +315 -0
  32. package/components/SegmentedControl.js +202 -0
  33. package/components/Select.js +199 -0
  34. package/components/SelectDialog.js +255 -0
  35. package/components/Slider.js +113 -0
  36. package/components/Snackbar.js +243 -0
  37. package/components/Stepper.js +281 -0
  38. package/components/SwipeableListItem.js +179 -0
  39. package/components/Switch.js +147 -0
  40. package/components/Table.js +492 -0
  41. package/components/Tabs.js +125 -0
  42. package/components/Text.js +141 -0
  43. package/components/TextField.js +331 -0
  44. package/components/Toast.js +236 -0
  45. package/components/TreeView.js +420 -0
  46. package/components/Video.js +397 -0
  47. package/components/View.js +140 -0
  48. package/components/VirtualList.js +120 -0
  49. package/core/CanvasFramework.js +1271 -0
  50. package/core/CanvasWork.js +32 -0
  51. package/core/Component.js +153 -0
  52. package/core/LogicWorker.js +25 -0
  53. package/core/WebGLCanvasAdapter.js +1369 -0
  54. package/features/Column.js +43 -0
  55. package/features/Grid.js +47 -0
  56. package/features/LayoutComponent.js +43 -0
  57. package/features/OpenStreetMap.js +310 -0
  58. package/features/Positioned.js +33 -0
  59. package/features/PullToRefresh.js +328 -0
  60. package/features/Row.js +40 -0
  61. package/features/SignaturePad.js +257 -0
  62. package/features/Skeleton.js +84 -0
  63. package/features/Stack.js +21 -0
  64. package/index.js +101 -0
  65. package/manager/AccessibilityManager.js +107 -0
  66. package/manager/ErrorHandler.js +59 -0
  67. package/manager/FeatureFlags.js +60 -0
  68. package/manager/MemoryManager.js +107 -0
  69. package/manager/PerformanceMonitor.js +84 -0
  70. package/manager/SecurityManager.js +54 -0
  71. package/package.json +28 -0
  72. package/utils/AnimationEngine.js +428 -0
  73. package/utils/DataStore.js +403 -0
  74. package/utils/EventBus.js +407 -0
  75. package/utils/FetchClient.js +74 -0
  76. package/utils/FormValidator.js +355 -0
  77. package/utils/GeoLocationService.js +62 -0
  78. package/utils/I18n.js +207 -0
  79. package/utils/IndexedDBManager.js +273 -0
  80. package/utils/OfflineSyncManager.js +342 -0
  81. package/utils/QueryBuilder.js +478 -0
  82. package/utils/SafeArea.js +64 -0
  83. package/utils/SecureStorage.js +289 -0
  84. package/utils/StateManager.js +207 -0
  85. package/utils/WebSocketClient.js +66 -0
@@ -0,0 +1,428 @@
1
+ /**
2
+ * Moteur d'animation pour composants Canvas
3
+ * Permet d'animer n'importe quelle propriété d'un composant sans le modifier
4
+ * @class
5
+ * @property {Map} animations - Liste des animations actives
6
+ * @property {boolean} isRunning - Indique si le moteur tourne
7
+ */
8
+ class AnimationEngine {
9
+ constructor() {
10
+ this.animations = new Map();
11
+ this.isRunning = false;
12
+ this.animationFrameId = null;
13
+ }
14
+
15
+ /**
16
+ * Anime une propriété d'un composant
17
+ * @param {Component} component - Composant à animer
18
+ * @param {Object} options - Options d'animation
19
+ * @param {Object} options.from - Valeurs de départ {x: 0, y: 0, ...}
20
+ * @param {Object} options.to - Valeurs d'arrivée {x: 100, y: 200, ...}
21
+ * @param {number} options.duration - Durée en ms (défaut: 300)
22
+ * @param {string} options.easing - Fonction d'easing (défaut: 'easeInOutQuad')
23
+ * @param {number} options.delay - Délai avant démarrage en ms (défaut: 0)
24
+ * @param {Function} options.onUpdate - Callback à chaque frame
25
+ * @param {Function} options.onComplete - Callback à la fin
26
+ * @param {boolean} options.loop - Boucler l'animation (défaut: false)
27
+ * @param {boolean} options.yoyo - Retour inverse (défaut: false)
28
+ * @returns {string} ID de l'animation
29
+ */
30
+ animate(component, options = {}) {
31
+ const animationId = this.generateId();
32
+
33
+ const animation = {
34
+ id: animationId,
35
+ component,
36
+ from: options.from || {},
37
+ to: options.to || {},
38
+ duration: options.duration || 300,
39
+ easing: options.easing || 'easeInOutQuad',
40
+ delay: options.delay || 0,
41
+ onUpdate: options.onUpdate,
42
+ onComplete: options.onComplete,
43
+ loop: options.loop || false,
44
+ yoyo: options.yoyo || false,
45
+
46
+ // État interne
47
+ startTime: null,
48
+ delayStartTime: null,
49
+ progress: 0,
50
+ isDelaying: options.delay > 0,
51
+ isReversed: false,
52
+ originalValues: {}
53
+ };
54
+
55
+ // Sauvegarder les valeurs originales
56
+ for (let prop in animation.to) {
57
+ if (animation.from[prop] === undefined) {
58
+ animation.from[prop] = component[prop];
59
+ }
60
+ animation.originalValues[prop] = component[prop];
61
+ }
62
+
63
+ this.animations.set(animationId, animation);
64
+
65
+ if (!this.isRunning) {
66
+ this.start();
67
+ }
68
+
69
+ return animationId;
70
+ }
71
+
72
+ /**
73
+ * Anime plusieurs propriétés en séquence
74
+ * @param {Component} component - Composant à animer
75
+ * @param {Array} sequence - Tableau d'options d'animation
76
+ * @returns {Promise} Promesse résolue à la fin de la séquence
77
+ */
78
+ async animateSequence(component, sequence) {
79
+ for (let options of sequence) {
80
+ await new Promise(resolve => {
81
+ this.animate(component, {
82
+ ...options,
83
+ onComplete: () => {
84
+ if (options.onComplete) options.onComplete();
85
+ resolve();
86
+ }
87
+ });
88
+ });
89
+ }
90
+ }
91
+
92
+ /**
93
+ * Anime plusieurs composants en parallèle
94
+ * @param {Array} animations - Tableau de {component, options}
95
+ * @returns {Promise} Promesse résolue quand toutes sont finies
96
+ */
97
+ async animateParallel(animations) {
98
+ const promises = animations.map(({component, options}) => {
99
+ return new Promise(resolve => {
100
+ this.animate(component, {
101
+ ...options,
102
+ onComplete: () => {
103
+ if (options.onComplete) options.onComplete();
104
+ resolve();
105
+ }
106
+ });
107
+ });
108
+ });
109
+
110
+ return Promise.all(promises);
111
+ }
112
+
113
+ /**
114
+ * Crée une animation de rebond
115
+ * @param {Component} component - Composant
116
+ * @param {Object} options - Options
117
+ */
118
+ bounce(component, options = {}) {
119
+ const originalY = component.y;
120
+ const height = options.height || 50;
121
+
122
+ return this.animate(component, {
123
+ from: { y: originalY },
124
+ to: { y: originalY - height },
125
+ duration: options.duration || 400,
126
+ easing: 'easeOutQuad',
127
+ yoyo: true,
128
+ onComplete: options.onComplete
129
+ });
130
+ }
131
+
132
+ /**
133
+ * Crée une animation de shake (tremblement)
134
+ * @param {Component} component - Composant
135
+ * @param {Object} options - Options
136
+ */
137
+ shake(component, options = {}) {
138
+ const originalX = component.x;
139
+ const intensity = options.intensity || 10;
140
+ const shakes = options.shakes || 4;
141
+ const duration = options.duration || 400;
142
+
143
+ const sequence = [];
144
+ for (let i = 0; i < shakes; i++) {
145
+ sequence.push({
146
+ to: { x: originalX + (i % 2 === 0 ? intensity : -intensity) },
147
+ duration: duration / (shakes * 2),
148
+ easing: 'linear'
149
+ });
150
+ }
151
+ sequence.push({
152
+ to: { x: originalX },
153
+ duration: duration / (shakes * 2),
154
+ easing: 'linear',
155
+ onComplete: options.onComplete
156
+ });
157
+
158
+ return this.animateSequence(component, sequence);
159
+ }
160
+
161
+ /**
162
+ * Crée une animation de pulsation (scale)
163
+ * @param {Component} component - Composant
164
+ * @param {Object} options - Options
165
+ */
166
+ pulse(component, options = {}) {
167
+ const originalWidth = component.width;
168
+ const originalHeight = component.height;
169
+ const scale = options.scale || 1.1;
170
+
171
+ return this.animate(component, {
172
+ from: {
173
+ width: originalWidth,
174
+ height: originalHeight
175
+ },
176
+ to: {
177
+ width: originalWidth * scale,
178
+ height: originalHeight * scale
179
+ },
180
+ duration: options.duration || 300,
181
+ easing: 'easeInOutQuad',
182
+ yoyo: true,
183
+ loop: options.loop || false,
184
+ onComplete: options.onComplete
185
+ });
186
+ }
187
+
188
+ /**
189
+ * Crée une animation de fade (opacité)
190
+ * @param {Component} component - Composant
191
+ * @param {Object} options - Options
192
+ */
193
+ fade(component, options = {}) {
194
+ // Ajouter une propriété opacity si elle n'existe pas
195
+ if (component.opacity === undefined) {
196
+ component.opacity = 1;
197
+ }
198
+
199
+ return this.animate(component, {
200
+ from: { opacity: options.from !== undefined ? options.from : component.opacity },
201
+ to: { opacity: options.to !== undefined ? options.to : 0 },
202
+ duration: options.duration || 300,
203
+ easing: options.easing || 'linear',
204
+ onComplete: options.onComplete
205
+ });
206
+ }
207
+
208
+ /**
209
+ * Crée une animation de slide (glissement)
210
+ * @param {Component} component - Composant
211
+ * @param {Object} options - Options
212
+ */
213
+ slide(component, options = {}) {
214
+ return this.animate(component, {
215
+ from: options.from || { x: component.x, y: component.y },
216
+ to: options.to || { x: component.x + 100, y: component.y },
217
+ duration: options.duration || 400,
218
+ easing: options.easing || 'easeOutQuad',
219
+ onComplete: options.onComplete
220
+ });
221
+ }
222
+
223
+ /**
224
+ * Crée une animation de rotation
225
+ * @param {Component} component - Composant
226
+ * @param {Object} options - Options
227
+ */
228
+ rotate(component, options = {}) {
229
+ if (component.rotation === undefined) {
230
+ component.rotation = 0;
231
+ }
232
+
233
+ return this.animate(component, {
234
+ from: { rotation: options.from !== undefined ? options.from : component.rotation },
235
+ to: { rotation: options.to !== undefined ? options.to : 360 },
236
+ duration: options.duration || 1000,
237
+ easing: options.easing || 'linear',
238
+ loop: options.loop || false,
239
+ onComplete: options.onComplete
240
+ });
241
+ }
242
+
243
+ /**
244
+ * Arrête une animation
245
+ * @param {string} animationId - ID de l'animation
246
+ */
247
+ stop(animationId) {
248
+ this.animations.delete(animationId);
249
+
250
+ if (this.animations.size === 0) {
251
+ this.isRunning = false;
252
+ if (this.animationFrameId) {
253
+ cancelAnimationFrame(this.animationFrameId);
254
+ this.animationFrameId = null;
255
+ }
256
+ }
257
+ }
258
+
259
+ /**
260
+ * Arrête toutes les animations d'un composant
261
+ * @param {Component} component - Composant
262
+ */
263
+ stopAll(component) {
264
+ const toDelete = [];
265
+
266
+ for (let [id, anim] of this.animations) {
267
+ if (anim.component === component) {
268
+ toDelete.push(id);
269
+ }
270
+ }
271
+
272
+ toDelete.forEach(id => this.stop(id));
273
+ }
274
+
275
+ /**
276
+ * Démarre le moteur d'animation
277
+ * @private
278
+ */
279
+ start() {
280
+ this.isRunning = true;
281
+ this.lastTime = performance.now();
282
+ this.update();
283
+ }
284
+
285
+ /**
286
+ * Met à jour toutes les animations
287
+ * @private
288
+ */
289
+ update() {
290
+ const currentTime = performance.now();
291
+ const toDelete = [];
292
+
293
+ for (let [id, anim] of this.animations) {
294
+ // Gérer le délai
295
+ if (anim.isDelaying) {
296
+ if (!anim.delayStartTime) {
297
+ anim.delayStartTime = currentTime;
298
+ }
299
+
300
+ if (currentTime - anim.delayStartTime >= anim.delay) {
301
+ anim.isDelaying = false;
302
+ anim.startTime = currentTime;
303
+ }
304
+ continue;
305
+ }
306
+
307
+ // Initialiser le temps de départ
308
+ if (!anim.startTime) {
309
+ anim.startTime = currentTime;
310
+ }
311
+
312
+ // Calculer la progression
313
+ const elapsed = currentTime - anim.startTime;
314
+ let progress = Math.min(elapsed / anim.duration, 1);
315
+
316
+ // Appliquer l'easing
317
+ const easedProgress = this.applyEasing(progress, anim.easing);
318
+
319
+ // Inverser si yoyo
320
+ const actualProgress = anim.isReversed ? 1 - easedProgress : easedProgress;
321
+
322
+ // Mettre à jour les propriétés du composant
323
+ for (let prop in anim.to) {
324
+ const from = anim.from[prop];
325
+ const to = anim.to[prop];
326
+ const value = from + (to - from) * actualProgress;
327
+ anim.component[prop] = value;
328
+ }
329
+
330
+ // Callback onUpdate
331
+ if (anim.onUpdate) {
332
+ anim.onUpdate(actualProgress);
333
+ }
334
+
335
+ // Animation terminée
336
+ if (progress >= 1) {
337
+ if (anim.yoyo && !anim.isReversed) {
338
+ // Inverser pour le yoyo
339
+ anim.isReversed = true;
340
+ anim.startTime = currentTime;
341
+ } else if (anim.loop) {
342
+ // Recommencer
343
+ anim.startTime = currentTime;
344
+ anim.isReversed = false;
345
+ } else {
346
+ // Terminer
347
+ if (anim.onComplete) {
348
+ anim.onComplete();
349
+ }
350
+ toDelete.push(id);
351
+ }
352
+ }
353
+ }
354
+
355
+ // Nettoyer les animations terminées
356
+ toDelete.forEach(id => this.stop(id));
357
+
358
+ // Continuer l'animation
359
+ if (this.animations.size > 0) {
360
+ this.animationFrameId = requestAnimationFrame(() => this.update());
361
+ } else {
362
+ this.isRunning = false;
363
+ }
364
+ }
365
+
366
+ /**
367
+ * Applique une fonction d'easing
368
+ * @param {number} t - Progression (0-1)
369
+ * @param {string} easingName - Nom de l'easing
370
+ * @returns {number} Valeur easée
371
+ * @private
372
+ */
373
+ applyEasing(t, easingName) {
374
+ const easings = {
375
+ linear: t => t,
376
+ easeInQuad: t => t * t,
377
+ easeOutQuad: t => t * (2 - t),
378
+ easeInOutQuad: t => t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t,
379
+ easeInCubic: t => t * t * t,
380
+ easeOutCubic: t => (--t) * t * t + 1,
381
+ easeInOutCubic: t => t < 0.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1,
382
+ easeInQuart: t => t * t * t * t,
383
+ easeOutQuart: t => 1 - (--t) * t * t * t,
384
+ easeInOutQuart: t => t < 0.5 ? 8 * t * t * t * t : 1 - 8 * (--t) * t * t * t,
385
+ easeInElastic: t => {
386
+ const c4 = (2 * Math.PI) / 3;
387
+ return t === 0 ? 0 : t === 1 ? 1 : -Math.pow(2, 10 * t - 10) * Math.sin((t * 10 - 10.75) * c4);
388
+ },
389
+ easeOutElastic: t => {
390
+ const c4 = (2 * Math.PI) / 3;
391
+ return t === 0 ? 0 : t === 1 ? 1 : Math.pow(2, -10 * t) * Math.sin((t * 10 - 0.75) * c4) + 1;
392
+ },
393
+ easeOutBounce: t => {
394
+ const n1 = 7.5625;
395
+ const d1 = 2.75;
396
+ if (t < 1 / d1) return n1 * t * t;
397
+ else if (t < 2 / d1) return n1 * (t -= 1.5 / d1) * t + 0.75;
398
+ else if (t < 2.5 / d1) return n1 * (t -= 2.25 / d1) * t + 0.9375;
399
+ else return n1 * (t -= 2.625 / d1) * t + 0.984375;
400
+ }
401
+ };
402
+
403
+ return (easings[easingName] || easings.linear)(t);
404
+ }
405
+
406
+ /**
407
+ * Génère un ID unique
408
+ * @returns {string} ID unique
409
+ * @private
410
+ */
411
+ generateId() {
412
+ return `anim_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
413
+ }
414
+
415
+ /**
416
+ * Nettoie toutes les animations
417
+ */
418
+ clear() {
419
+ this.animations.clear();
420
+ this.isRunning = false;
421
+ if (this.animationFrameId) {
422
+ cancelAnimationFrame(this.animationFrameId);
423
+ this.animationFrameId = null;
424
+ }
425
+ }
426
+ }
427
+
428
+ export default AnimationEngine;