canvasframework 0.5.16 → 0.5.18

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 (112) hide show
  1. package/dist/canvasframework.js +2 -0
  2. package/dist/canvasframework.js.LICENSE.txt +1 -0
  3. package/package.json +18 -17
  4. package/components/Accordion.js +0 -265
  5. package/components/AndroidDatePickerDialog.js +0 -406
  6. package/components/AppBar.js +0 -398
  7. package/components/AudioPlayer.js +0 -611
  8. package/components/Avatar.js +0 -202
  9. package/components/Banner.js +0 -342
  10. package/components/BottomNavigationBar.js +0 -433
  11. package/components/BottomSheet.js +0 -234
  12. package/components/Button.js +0 -360
  13. package/components/Camera.js +0 -644
  14. package/components/Card.js +0 -193
  15. package/components/Chart.js +0 -700
  16. package/components/Checkbox.js +0 -166
  17. package/components/Chip.js +0 -212
  18. package/components/CircularProgress.js +0 -327
  19. package/components/ContextMenu.js +0 -116
  20. package/components/DatePicker.js +0 -298
  21. package/components/Dialog.js +0 -337
  22. package/components/Divider.js +0 -125
  23. package/components/Drawer.js +0 -276
  24. package/components/FAB.js +0 -270
  25. package/components/FileUpload.js +0 -315
  26. package/components/FloatedCamera.js +0 -644
  27. package/components/IOSDatePickerWheel.js +0 -430
  28. package/components/ImageCarousel.js +0 -219
  29. package/components/ImageComponent.js +0 -223
  30. package/components/Input.js +0 -831
  31. package/components/InputDatalist.js +0 -723
  32. package/components/InputTags.js +0 -624
  33. package/components/List.js +0 -95
  34. package/components/ListItem.js +0 -269
  35. package/components/Modal.js +0 -364
  36. package/components/MorphingFAB.js +0 -428
  37. package/components/MultiSelectDialog.js +0 -206
  38. package/components/NumberInput.js +0 -271
  39. package/components/PasswordInput.js +0 -462
  40. package/components/ProgressBar.js +0 -88
  41. package/components/QRCodeReader.js +0 -539
  42. package/components/RadioButton.js +0 -151
  43. package/components/SearchInput.js +0 -315
  44. package/components/SegmentedControl.js +0 -357
  45. package/components/Select.js +0 -199
  46. package/components/SelectDialog.js +0 -255
  47. package/components/Slider.js +0 -113
  48. package/components/SliverAppBar.js +0 -139
  49. package/components/Snackbar.js +0 -243
  50. package/components/SpeedDialFAB.js +0 -397
  51. package/components/Stepper.js +0 -281
  52. package/components/SwipeableListItem.js +0 -327
  53. package/components/Switch.js +0 -147
  54. package/components/Table.js +0 -492
  55. package/components/Tabs.js +0 -423
  56. package/components/Text.js +0 -141
  57. package/components/TextField.js +0 -151
  58. package/components/TimePicker.js +0 -934
  59. package/components/Toast.js +0 -236
  60. package/components/TreeView.js +0 -420
  61. package/components/Video.js +0 -397
  62. package/components/View.js +0 -140
  63. package/components/VirtualList.js +0 -120
  64. package/core/CanvasFramework.js +0 -3034
  65. package/core/Component.js +0 -243
  66. package/core/ThemeManager.js +0 -358
  67. package/core/UIBuilder.js +0 -267
  68. package/core/WebGLCanvasAdapter.js +0 -782
  69. package/features/Column.js +0 -43
  70. package/features/Grid.js +0 -47
  71. package/features/LayoutComponent.js +0 -43
  72. package/features/OpenStreetMap.js +0 -310
  73. package/features/Positioned.js +0 -33
  74. package/features/PullToRefresh.js +0 -328
  75. package/features/Row.js +0 -40
  76. package/features/SignaturePad.js +0 -257
  77. package/features/Skeleton.js +0 -193
  78. package/features/Stack.js +0 -21
  79. package/index.js +0 -119
  80. package/manager/AccessibilityManager.js +0 -107
  81. package/manager/ErrorHandler.js +0 -59
  82. package/manager/FeatureFlags.js +0 -60
  83. package/manager/MemoryManager.js +0 -107
  84. package/manager/PerformanceMonitor.js +0 -84
  85. package/manager/SecurityManager.js +0 -54
  86. package/utils/AnimationEngine.js +0 -734
  87. package/utils/CryptoManager.js +0 -303
  88. package/utils/DataStore.js +0 -403
  89. package/utils/DevTools.js +0 -1618
  90. package/utils/DevToolsConsole.js +0 -201
  91. package/utils/EventBus.js +0 -407
  92. package/utils/FetchClient.js +0 -74
  93. package/utils/FirebaseAuth.js +0 -653
  94. package/utils/FirebaseCore.js +0 -246
  95. package/utils/FirebaseFirestore.js +0 -581
  96. package/utils/FirebaseFunctions.js +0 -97
  97. package/utils/FirebaseRealtimeDB.js +0 -498
  98. package/utils/FirebaseStorage.js +0 -612
  99. package/utils/FormValidator.js +0 -355
  100. package/utils/GeoLocationService.js +0 -62
  101. package/utils/I18n.js +0 -207
  102. package/utils/IndexedDBManager.js +0 -273
  103. package/utils/InspectionOverlay.js +0 -308
  104. package/utils/NotificationManager.js +0 -60
  105. package/utils/OfflineSyncManager.js +0 -342
  106. package/utils/PayPalPayment.js +0 -678
  107. package/utils/QueryBuilder.js +0 -478
  108. package/utils/SafeArea.js +0 -64
  109. package/utils/SecureStorage.js +0 -289
  110. package/utils/StateManager.js +0 -207
  111. package/utils/StripePayment.js +0 -552
  112. package/utils/WebSocketClient.js +0 -66
@@ -1,624 +0,0 @@
1
- import Component from '../core/Component.js';
2
-
3
- /**
4
- * Champ de saisie de tags avec gestion de tags multiples
5
- * @class
6
- * @extends Component
7
- * @property {string} placeholder - Texte d'indication
8
- * @property {string} value - Valeur en cours de saisie
9
- * @property {Array} tags - Liste des tags
10
- * @property {number} fontSize - Taille de police
11
- * @property {boolean} focused - Focus actif
12
- * @property {string} platform - Plateforme
13
- * @property {boolean} cursorVisible - Curseur visible
14
- * @property {number} cursorPosition - Position du curseur
15
- * @property {HTMLInputElement} hiddenInput - Input HTML caché
16
- * @property {number} tagPadding - Padding interne des tags
17
- * @property {number} tagSpacing - Espacement entre les tags
18
- * @property {string} tagColor - Couleur des tags
19
- * @property {string} tagTextColor - Couleur du texte des tags
20
- * @property {string} deleteButtonColor - Couleur du bouton de suppression
21
- */
22
- class InputTags extends Component {
23
- static activeInput = null;
24
- static allInputs = new Set();
25
- static globalClickHandler = null;
26
-
27
- /**
28
- * Crée une instance de InputTags
29
- * @param {CanvasFramework} framework - Framework parent
30
- * @param {Object} [options={}] - Options de configuration
31
- * @param {string} [options.placeholder=''] - Texte d'indication
32
- * @param {Array} [options.tags=[]] - Tags initiaux
33
- * @param {string} [options.value=''] - Valeur initiale
34
- * @param {number} [options.fontSize=16] - Taille de police
35
- * @param {Function} [options.onFocus] - Callback au focus
36
- * @param {Function} [options.onBlur] - Callback au blur
37
- * @param {Function} [options.onTagAdd] - Callback quand un tag est ajouté
38
- * @param {Function} [options.onTagRemove] - Callback quand un tag est supprimé
39
- * @param {number} [options.tagPadding=8] - Padding interne des tags
40
- * @param {number} [options.tagSpacing=6] - Espacement entre les tags
41
- * @param {string} [options.tagColor='#E0E0E0'] - Couleur des tags
42
- * @param {string} [options.tagTextColor='#333333'] - Couleur du texte des tags
43
- * @param {string} [options.deleteButtonColor='#666666'] - Couleur du bouton de suppression
44
- */
45
- constructor(framework, options = {}) {
46
- super(framework, options);
47
- this.placeholder = options.placeholder || 'Ajouter des tags...';
48
- this.value = options.value || '';
49
- this.tags = Array.isArray(options.tags) ? [...options.tags] : [];
50
- this.fontSize = options.fontSize || 16;
51
- this.focused = false;
52
- this.platform = framework.platform;
53
- this.cursorVisible = true;
54
- this.cursorPosition = this.value.length;
55
-
56
- // Configuration des tags
57
- this.tagPadding = options.tagPadding || 8;
58
- this.tagSpacing = options.tagSpacing || 6;
59
- this.tagColor = options.tagColor || '#E0E0E0';
60
- this.tagTextColor = options.tagTextColor || '#333333';
61
- this.deleteButtonColor = options.deleteButtonColor || '#666666';
62
-
63
- // Callbacks
64
- this.onTagAdd = options.onTagAdd || (() => {});
65
- this.onTagRemove = options.onTagRemove || (() => {});
66
-
67
- // Calculs de layout
68
- this.tagHeight = this.fontSize + this.tagPadding * 2;
69
- this.deleteButtonSize = this.fontSize * 0.8;
70
-
71
- // Gestion du focus
72
- this.onFocus = this.onFocus.bind(this);
73
- this.onBlur = this.onBlur.bind(this);
74
-
75
- // Enregistrer cet input
76
- InputTags.allInputs.add(this);
77
-
78
- // Animation du curseur
79
- this.cursorInterval = setInterval(() => {
80
- if (this.focused) this.cursorVisible = !this.cursorVisible;
81
- }, 500);
82
-
83
- // Écouter les clics partout pour détecter quand on clique ailleurs
84
- this.setupGlobalClickHandler();
85
- }
86
-
87
- /**
88
- * Écoute les clics globaux pour détecter les clics hors input
89
- */
90
- setupGlobalClickHandler() {
91
- if (!InputTags.globalClickHandler) {
92
- InputTags.globalClickHandler = (e) => {
93
- let clickedOnInput = false;
94
-
95
- for (let input of InputTags.allInputs) {
96
- if (input.hiddenInput && e.target === input.hiddenInput) {
97
- clickedOnInput = true;
98
- break;
99
- }
100
- }
101
-
102
- if (!clickedOnInput) {
103
- InputTags.removeAllHiddenInputs();
104
- }
105
- };
106
-
107
- document.addEventListener('click', InputTags.globalClickHandler, true);
108
- document.addEventListener('touchstart', InputTags.globalClickHandler, true);
109
- }
110
- }
111
-
112
- /**
113
- * Configure l'input HTML caché
114
- * @private
115
- */
116
- setupHiddenInput() {
117
- if (this.hiddenInput) return;
118
-
119
- this.hiddenInput = document.createElement('input');
120
- this.hiddenInput.style.position = 'fixed';
121
- this.hiddenInput.style.opacity = '0';
122
- this.hiddenInput.style.pointerEvents = 'none';
123
- this.hiddenInput.style.top = '-100px';
124
- this.hiddenInput.style.zIndex = '9999';
125
- document.body.appendChild(this.hiddenInput);
126
-
127
- this.hiddenInput.addEventListener('input', (e) => {
128
- if (this.focused) {
129
- this.value = e.target.value;
130
- this.cursorPosition = this.value.length;
131
- }
132
- });
133
-
134
- this.hiddenInput.addEventListener('keydown', (e) => {
135
- if (e.key === 'Enter' || e.key === ',') {
136
- e.preventDefault();
137
- this.addCurrentTag();
138
- } else if (e.key === 'Backspace' && this.value === '' && this.tags.length > 0) {
139
- this.removeLastTag();
140
- }
141
- });
142
-
143
- this.hiddenInput.addEventListener('blur', () => {
144
- // Ajouter le tag en cours si non vide
145
- if (this.value.trim() !== '') {
146
- this.addCurrentTag();
147
- }
148
-
149
- this.focused = false;
150
- this.cursorVisible = false;
151
-
152
- setTimeout(() => {
153
- this.destroyHiddenInput();
154
- }, 100);
155
- });
156
- }
157
-
158
- /**
159
- * Ajoute le tag en cours de saisie
160
- */
161
- addCurrentTag() {
162
- const tag = this.value.trim();
163
- if (tag !== '' && !this.tags.includes(tag)) {
164
- this.tags.push(tag);
165
- this.value = '';
166
- this.cursorPosition = 0;
167
-
168
- if (this.hiddenInput) {
169
- this.hiddenInput.value = '';
170
- }
171
-
172
- this.onTagAdd(tag, this.tags);
173
- }
174
- }
175
-
176
- /**
177
- * Ajoute un tag spécifique
178
- * @param {string} tag - Tag à ajouter
179
- */
180
- addTag(tag) {
181
- const trimmedTag = tag.trim();
182
- if (trimmedTag !== '' && !this.tags.includes(trimmedTag)) {
183
- this.tags.push(trimmedTag);
184
- this.onTagAdd(trimmedTag, this.tags);
185
- }
186
- }
187
-
188
- /**
189
- * Supprime un tag par son index
190
- * @param {number} index - Index du tag à supprimer
191
- */
192
- removeTag(index) {
193
- if (index >= 0 && index < this.tags.length) {
194
- const removedTag = this.tags[index];
195
- this.tags.splice(index, 1);
196
- this.onTagRemove(removedTag, this.tags);
197
- }
198
- }
199
-
200
- /**
201
- * Supprime le dernier tag
202
- */
203
- removeLastTag() {
204
- if (this.tags.length > 0) {
205
- this.removeTag(this.tags.length - 1);
206
- }
207
- }
208
-
209
- /**
210
- * Supprime tous les tags
211
- */
212
- clearTags() {
213
- const oldTags = [...this.tags];
214
- this.tags = [];
215
- oldTags.forEach(tag => this.onTagRemove(tag, this.tags));
216
- }
217
-
218
- /**
219
- * Vérifie si un point est sur le bouton de suppression d'un tag
220
- * @param {number} x - Coordonnée X
221
- * @param {number} y - Coordonnée Y
222
- * @returns {number|null} Index du tag ou null
223
- */
224
- getTagIndexAtPoint(x, y) {
225
- let currentX = this.x + 10;
226
- const tagY = this.y + 10;
227
-
228
- for (let i = 0; i < this.tags.length; i++) {
229
- const tag = this.tags[i];
230
- const tagWidth = this.measureTagWidth(tag);
231
-
232
- // Vérifier si le point est dans le tag
233
- if (x >= currentX && x <= currentX + tagWidth &&
234
- y >= tagY && y <= tagY + this.tagHeight) {
235
- return i;
236
- }
237
-
238
- currentX += tagWidth + this.tagSpacing;
239
- }
240
-
241
- return null;
242
- }
243
-
244
- /**
245
- * Vérifie si un point est sur le bouton de suppression d'un tag
246
- * @param {number} x - Coordonnée X
247
- * @param {number} y - Coordonnée Y
248
- * @returns {number|null} Index du tag ou null
249
- */
250
- getDeleteButtonIndexAtPoint(x, y) {
251
- let currentX = this.x + 10;
252
- const tagY = this.y + 10;
253
-
254
- for (let i = 0; i < this.tags.length; i++) {
255
- const tag = this.tags[i];
256
- const tagWidth = this.measureTagWidth(tag);
257
- const deleteButtonX = currentX + tagWidth - this.deleteButtonSize - this.tagPadding / 2;
258
- const deleteButtonY = tagY + (this.tagHeight - this.deleteButtonSize) / 2;
259
-
260
- // Vérifier si le point est sur le bouton de suppression
261
- if (x >= deleteButtonX && x <= deleteButtonX + this.deleteButtonSize &&
262
- y >= deleteButtonY && y <= deleteButtonY + this.deleteButtonSize) {
263
- return i;
264
- }
265
-
266
- currentX += tagWidth + this.tagSpacing;
267
- }
268
-
269
- return null;
270
- }
271
-
272
- /**
273
- * Mesure la largeur d'un tag
274
- * @param {string} tag - Tag à mesurer
275
- * @returns {number} Largeur du tag
276
- */
277
- measureTagWidth(tag) {
278
- // Approximation de la largeur du texte
279
- const textWidth = tag.length * (this.fontSize * 0.6);
280
- return textWidth + this.tagPadding * 2 + this.deleteButtonSize + this.tagPadding / 2;
281
- }
282
-
283
- /**
284
- * Gère le focus
285
- */
286
- onFocus() {
287
- if (InputTags.activeInput === this) {
288
- return;
289
- }
290
-
291
- InputTags.removeAllHiddenInputs();
292
-
293
- for (let input of InputTags.allInputs) {
294
- if (input !== this) {
295
- input.focused = false;
296
- input.cursorVisible = false;
297
- }
298
- }
299
-
300
- this.focused = true;
301
- this.cursorVisible = true;
302
- InputTags.activeInput = this;
303
-
304
- this.setupHiddenInput();
305
-
306
- if (this.hiddenInput) {
307
- this.hiddenInput.value = this.value;
308
-
309
- const adjustedY = this.y + this.framework.scrollOffset;
310
- this.hiddenInput.style.top = `${adjustedY}px`;
311
-
312
- setTimeout(() => {
313
- if (this.hiddenInput && this.focused) {
314
- this.hiddenInput.focus();
315
- this.hiddenInput.setSelectionRange(this.value.length, this.value.length);
316
- }
317
- }, 50);
318
- }
319
- }
320
-
321
- /**
322
- * Gère le blur
323
- */
324
- onBlur() {
325
- this.focused = false;
326
- this.cursorVisible = false;
327
- }
328
-
329
- /**
330
- * Détruit l'input HTML
331
- */
332
- destroyHiddenInput() {
333
- if (this.hiddenInput && this.hiddenInput.parentNode) {
334
- this.hiddenInput.parentNode.removeChild(this.hiddenInput);
335
- this.hiddenInput = null;
336
- }
337
- }
338
-
339
- /**
340
- * Gère le clic
341
- * @param {number} x - Coordonnée X du clic
342
- * @param {number} y - Coordonnée Y du clic
343
- * @returns {boolean} True si le clic a été géré
344
- */
345
- onClick(x, y) {
346
- // Vérifier si on clique sur un bouton de suppression
347
- const deleteIndex = this.getDeleteButtonIndexAtPoint(x, y);
348
- if (deleteIndex !== null) {
349
- this.removeTag(deleteIndex);
350
- return true;
351
- }
352
-
353
- // Vérifier si on clique sur un tag (pour focus l'input)
354
- const tagIndex = this.getTagIndexAtPoint(x, y);
355
- if (tagIndex !== null) {
356
- this.onFocus();
357
- return true;
358
- }
359
-
360
- // Vérifier si on clique dans la zone d'input
361
- if (this.isPointInside(x, y)) {
362
- this.onFocus();
363
- return true;
364
- }
365
-
366
- return false;
367
- }
368
-
369
- /**
370
- * Méthode statique pour détruire tous les inputs HTML
371
- */
372
- static removeAllHiddenInputs() {
373
- for (let input of InputTags.allInputs) {
374
- input.focused = false;
375
- input.cursorVisible = false;
376
-
377
- if (input.hiddenInput && input.hiddenInput.parentNode) {
378
- input.hiddenInput.parentNode.removeChild(input.hiddenInput);
379
- input.hiddenInput = null;
380
- }
381
- }
382
-
383
- InputTags.activeInput = null;
384
- }
385
-
386
- /**
387
- * Vérifie si un point est dans les limites
388
- * @param {number} x - Coordonnée X
389
- * @param {number} y - Coordonnée Y
390
- * @returns {boolean} True si le point est dans l'input
391
- */
392
- isPointInside(x, y) {
393
- return x >= this.x &&
394
- x <= this.x + this.width &&
395
- y >= this.y &&
396
- y <= this.y + this.height;
397
- }
398
-
399
- /**
400
- * Calcule la position X du curseur
401
- * @returns {number} Position X du curseur
402
- */
403
- getCursorXPosition() {
404
- let cursorX = this.x + 10;
405
-
406
- // Ajouter la largeur de tous les tags
407
- for (let tag of this.tags) {
408
- cursorX += this.measureTagWidth(tag) + this.tagSpacing;
409
- }
410
-
411
- // Ajouter la largeur du texte en cours
412
- const textWidth = this.value.length * (this.fontSize * 0.6);
413
- cursorX += textWidth;
414
-
415
- return cursorX;
416
- }
417
-
418
- updateHeight() {
419
- const maxX = this.x + this.width - 10; // marge droite
420
- let currentX = this.x + 10;
421
- let currentY = this.y + 10;
422
- let lines = 1;
423
-
424
- for (let i = 0; i < this.tags.length; i++) {
425
- const tagWidth = this.measureTagWidth(this.tags[i]);
426
-
427
- if (currentX + tagWidth > maxX) {
428
- currentX = this.x + 10;
429
- currentY += this.tagHeight + this.tagSpacing;
430
- lines++;
431
- }
432
-
433
- currentX += tagWidth + this.tagSpacing;
434
- }
435
-
436
- // Ajouter la largeur du texte en cours
437
- const textWidth = this.value.length * (this.fontSize * 0.6);
438
- if (currentX + textWidth > maxX) {
439
- lines++;
440
- }
441
-
442
- // Mettre à jour la hauteur dynamique
443
- this.height = Math.max(lines * (this.tagHeight + this.tagSpacing) + 10, 40); // 40 = minHeight
444
- }
445
-
446
- /**
447
- * Dessine l'input
448
- * @param {CanvasRenderingContext2D} ctx - Contexte de dessin
449
- */
450
- draw(ctx) {
451
- this.updateHeight();
452
- ctx.save();
453
-
454
- // Dessin du contour
455
- if (this.platform === 'material') {
456
- ctx.strokeStyle = this.focused ? '#6200EE' : '#CCCCCC';
457
- ctx.lineWidth = this.focused ? 2 : 1;
458
- ctx.beginPath();
459
- ctx.moveTo(this.x, this.y + this.height);
460
- ctx.lineTo(this.x + this.width, this.y + this.height);
461
- ctx.stroke();
462
- } else {
463
- ctx.strokeStyle = this.focused ? '#007AFF' : '#C7C7CC';
464
- ctx.lineWidth = 1;
465
- ctx.beginPath();
466
- this.roundRect(ctx, this.x, this.y, this.width, this.height, 8);
467
- ctx.stroke();
468
- }
469
-
470
- // Position de départ pour dessiner les tags
471
- let currentX = this.x + 10;
472
- let currentY = this.y + 10;
473
- const maxX = this.x + this.width - 10;
474
-
475
- // Dessiner les tags
476
- for (let i = 0; i < this.tags.length; i++) {
477
- const tagWidth = this.measureTagWidth(this.tags[i]);
478
-
479
- // Retour à la ligne si dépassement
480
- if (currentX + tagWidth > maxX) {
481
- currentX = this.x + 10;
482
- currentY += this.tagHeight + this.tagSpacing;
483
- }
484
-
485
- this.drawTag(ctx, this.tags[i], currentX, currentY);
486
- currentX += tagWidth + this.tagSpacing;
487
- }
488
-
489
- // Dessiner le texte en cours ou placeholder
490
- if (this.value || (this.focused && this.tags.length === 0)) {
491
- ctx.fillStyle = this.value ? '#000000' : '#999999';
492
- ctx.font = `${this.fontSize}px -apple-system, BlinkMacSystemFont, 'Roboto', sans-serif`;
493
- ctx.textAlign = 'left';
494
- ctx.textBaseline = 'middle';
495
-
496
- const displayText = this.value || this.placeholder;
497
- const textY = currentY + this.tagHeight / 2;
498
-
499
- ctx.fillText(displayText, currentX, textY);
500
-
501
- // Curseur
502
- if (this.focused && this.cursorVisible) {
503
- const textWidth = ctx.measureText(this.value).width;
504
- ctx.fillStyle = '#000000';
505
- ctx.fillRect(currentX + textWidth, textY - this.fontSize / 2, 2, this.fontSize);
506
- }
507
- }
508
-
509
- ctx.restore();
510
- }
511
-
512
- /**
513
- * Dessine un tag
514
- * @param {CanvasRenderingContext2D} ctx - Contexte de dessin
515
- * @param {string} tag - Texte du tag
516
- * @param {number} x - Position X
517
- * @param {number} y - Position Y
518
- */
519
- drawTag(ctx, tag, x, y) {
520
- const tagWidth = this.measureTagWidth(tag);
521
-
522
- // Fond du tag
523
- ctx.fillStyle = this.tagColor;
524
- this.roundRect(ctx, x, y, tagWidth, this.tagHeight, this.tagHeight / 2);
525
- ctx.fill();
526
-
527
- // Texte du tag
528
- ctx.fillStyle = this.tagTextColor;
529
- ctx.font = `${this.fontSize}px -apple-system, BlinkMacSystemFont, 'Roboto', sans-serif`;
530
- ctx.textAlign = 'left';
531
- ctx.textBaseline = 'middle';
532
-
533
- const textX = x + this.tagPadding;
534
- const textY = y + this.tagHeight / 2;
535
-
536
- // Tronquer le texte si trop long
537
- const maxTextWidth = tagWidth - this.tagPadding * 2 - this.deleteButtonSize - this.tagPadding / 2;
538
- let displayTag = tag;
539
- let textWidth = ctx.measureText(tag).width;
540
-
541
- if (textWidth > maxTextWidth) {
542
- // Tronquer le texte avec "..."
543
- for (let i = tag.length; i > 0; i--) {
544
- const truncated = tag.substring(0, i) + '...';
545
- if (ctx.measureText(truncated).width <= maxTextWidth) {
546
- displayTag = truncated;
547
- break;
548
- }
549
- }
550
- }
551
-
552
- ctx.fillText(displayTag, textX, textY);
553
-
554
- // Bouton de suppression (×)
555
- const deleteButtonX = x + tagWidth - this.deleteButtonSize - this.tagPadding / 2;
556
- const deleteButtonY = y + (this.tagHeight - this.deleteButtonSize) / 2;
557
-
558
- ctx.strokeStyle = this.deleteButtonColor;
559
- ctx.lineWidth = 2;
560
- ctx.beginPath();
561
-
562
- // Croix
563
- const centerX = deleteButtonX + this.deleteButtonSize / 2;
564
- const centerY = deleteButtonY + this.deleteButtonSize / 2;
565
- const crossSize = this.deleteButtonSize / 3;
566
-
567
- ctx.moveTo(centerX - crossSize, centerY - crossSize);
568
- ctx.lineTo(centerX + crossSize, centerY + crossSize);
569
- ctx.moveTo(centerX + crossSize, centerY - crossSize);
570
- ctx.lineTo(centerX - crossSize, centerY + crossSize);
571
- ctx.stroke();
572
- }
573
-
574
- /**
575
- * Dessine un rectangle avec coins arrondis
576
- * @param {CanvasRenderingContext2D} ctx - Contexte de dessin
577
- * @param {number} x - Position X
578
- * @param {number} y - Position Y
579
- * @param {number} width - Largeur
580
- * @param {number} height - Hauteur
581
- * @param {number} radius - Rayon des coins
582
- * @private
583
- */
584
- roundRect(ctx, x, y, width, height, radius) {
585
- if (ctx.roundRect) {
586
- ctx.roundRect(x, y, width, height, radius);
587
- } else {
588
- ctx.beginPath();
589
- ctx.moveTo(x + radius, y);
590
- ctx.lineTo(x + width - radius, y);
591
- ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
592
- ctx.lineTo(x + width, y + height - radius);
593
- ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
594
- ctx.lineTo(x + radius, y + height);
595
- ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
596
- ctx.lineTo(x, y + radius);
597
- ctx.quadraticCurveTo(x, y, x + radius, y);
598
- ctx.closePath();
599
- }
600
- }
601
-
602
- /**
603
- * Nettoie les ressources
604
- */
605
- destroy() {
606
- this.destroyHiddenInput();
607
-
608
- if (this.cursorInterval) {
609
- clearInterval(this.cursorInterval);
610
- }
611
-
612
- InputTags.allInputs.delete(this);
613
-
614
- if (InputTags.allInputs.size === 0 && InputTags.globalClickHandler) {
615
- document.removeEventListener('click', InputTags.globalClickHandler, true);
616
- document.removeEventListener('touchstart', InputTags.globalClickHandler, true);
617
- InputTags.globalClickHandler = null;
618
- }
619
-
620
- super.destroy && super.destroy();
621
- }
622
- }
623
-
624
- export default InputTags;
@@ -1,95 +0,0 @@
1
- import Component from '../core/Component.js';
2
- import ListItem from '../components/ListItem.js';
3
-
4
- /**
5
- * Conteneur pour les éléments de liste (ListItems) avec défilement automatique
6
- * @class
7
- * @extends Component
8
- */
9
- class List extends Component {
10
- constructor(framework, options = {}) {
11
- super(framework, options);
12
- /** @type {ListItem[]} */
13
- this.items = [];
14
- /** @type {number} */
15
- this.itemHeight = options.itemHeight || 56;
16
- /** @type {Function|undefined} */
17
- this.onItemClick = options.onItemClick;
18
- /** @type {number} */
19
- this.y = options.y || 0;
20
- }
21
-
22
- /**
23
- * Ajoute un item à la liste
24
- * @param {Object|Component} itemOptions - Options pour l'item OU instance de Component (ex: SwipeableListItem)
25
- * @returns {ListItem|Component} L'item créé ou passé
26
- */
27
- addItem(itemOptions) {
28
- let item;
29
-
30
- // 🔹 Vérifier si c'est déjà un composant instancié (SwipeableListItem)
31
- if (itemOptions instanceof Component) {
32
- item = itemOptions;
33
-
34
- // 🔹 CRITIQUE : Définir la position et taille de l'item
35
- item.x = this.x;
36
- item.y = this.y + (this.items.length * this.itemHeight);
37
- item.width = this.width;
38
- item.height = this.itemHeight;
39
-
40
- console.log(`📦 SwipeableListItem positionné à y=${item.y}`);
41
- } else {
42
- // Créer un ListItem standard
43
- item = new ListItem(this.framework, {
44
- ...itemOptions,
45
- x: this.x,
46
- y: this.y + (this.items.length * this.itemHeight),
47
- width: this.width,
48
- height: this.itemHeight,
49
- onClick: () => {
50
- if (this.onItemClick) {
51
- this.onItemClick(this.items.length, itemOptions);
52
- }
53
- if (itemOptions.onClick) {
54
- itemOptions.onClick();
55
- }
56
- }
57
- });
58
- }
59
-
60
- this.items.push(item);
61
- this.framework.add(item);
62
- this.height = this.items.length * this.itemHeight;
63
-
64
- return item;
65
- }
66
-
67
- /**
68
- * Vide la liste et supprime tous les items du framework
69
- */
70
- clear() {
71
- for (let item of this.items) {
72
- this.framework.remove(item);
73
- }
74
- this.items = [];
75
- this.height = 0;
76
- }
77
-
78
- /**
79
- * Dessine le composant (les items se dessinent eux-mêmes)
80
- * @param {CanvasRenderingContext2D} ctx - Contexte de dessin
81
- */
82
- draw(ctx) {
83
- // Les items se dessinent eux-mêmes
84
- }
85
-
86
- /**
87
- * Vérifie si un point est à l'intérieur du composant
88
- * @returns {boolean} Toujours false (les ListItems gèrent leurs propres clics)
89
- */
90
- isPointInside() {
91
- return false; // Les ListItems gèrent leurs propres clics
92
- }
93
- }
94
-
95
- export default List;