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,199 +0,0 @@
1
- import Component from '../core/Component.js';
2
- import SelectDialog from '../components/SelectDialog.js';
3
-
4
- /**
5
- * Composant de sélection déroulante (dropdown)
6
- * @class
7
- * @extends Component
8
- * @param {Framework} framework - Instance du framework
9
- * @param {Object} [options={}] - Options de configuration
10
- * @param {string[]} [options.options=[]] - Liste des options
11
- * @param {number} [options.selectedIndex=0] - Index de l'option sélectionnée
12
- * @param {string} [options.placeholder='Select...'] - Texte par défaut
13
- * @param {number} [options.fontSize=16] - Taille de police
14
- * @param {Function} [options.onChange] - Callback lors du changement de sélection
15
- * @example
16
- * const select = new Select(framework, {
17
- * options: ['Option 1', 'Option 2', 'Option 3'],
18
- * placeholder: 'Choisissez une option',
19
- * onChange: (value, index) => console.log('Selected:', value)
20
- * });
21
- */
22
- class Select extends Component {
23
- /**
24
- * @constructs Select
25
- */
26
- constructor(framework, options = {}) {
27
- super(framework, options);
28
- /** @type {string[]} */
29
- this.options = options.options || [];
30
- /** @type {number} */
31
- this.selectedIndex = options.selectedIndex || 0;
32
- /** @type {string} */
33
- this.placeholder = options.placeholder || 'Select...';
34
- /** @type {string} */
35
- this.platform = framework.platform;
36
- /** @type {number} */
37
- this.fontSize = options.fontSize || 16;
38
- /** @type {Function|undefined} */
39
- this.onChange = options.onChange;
40
- /** @type {boolean} */
41
- this.isOpen = false;
42
- /** @type {SelectDialog|null} */
43
- this.dialog = null;
44
-
45
- // Définir onClick pour le Select
46
- this.onClick = this.toggleMenu.bind(this);
47
- }
48
-
49
- /**
50
- * Ouvre ou ferme le menu de sélection
51
- */
52
- toggleMenu() {
53
- if (this.isOpen && this.dialog) {
54
- this.closeMenu();
55
- return;
56
- }
57
-
58
- this.openMenu();
59
- }
60
-
61
- /**
62
- * Ouvre le menu de sélection (affiche le modal)
63
- */
64
- openMenu() {
65
- if (this.isOpen) return;
66
-
67
- this.dialog = new SelectDialog(this.framework, {
68
- title: this.placeholder,
69
- options: this.options,
70
- selectedIndex: this.selectedIndex,
71
- onSelect: (index, value) => {
72
- this.selectedIndex = index;
73
- if (this.onChange) {
74
- this.onChange(value, index);
75
- }
76
- this.closeMenu();
77
- }
78
- });
79
-
80
- this.framework.add(this.dialog);
81
- this.isOpen = true;
82
- }
83
-
84
- /**
85
- * Ferme le menu de sélection
86
- */
87
- closeMenu() {
88
- if (this.dialog) {
89
- this.dialog.hide();
90
- this.dialog = null;
91
- }
92
- this.isOpen = false;
93
- }
94
-
95
- /**
96
- * Dessine le composant Select
97
- * @param {CanvasRenderingContext2D} ctx - Contexte de dessin
98
- */
99
- draw(ctx) {
100
- ctx.save();
101
-
102
- const selectedValue = this.options[this.selectedIndex] || this.placeholder;
103
-
104
- if (this.platform === 'material') {
105
- // Material Design Select
106
- ctx.fillStyle = this.pressed ? '#F5F5F5' : '#FFFFFF';
107
- ctx.fillRect(this.x, this.y, this.width, this.height);
108
-
109
- ctx.strokeStyle = this.isOpen ? '#6200EE' : '#CCCCCC';
110
- ctx.lineWidth = this.isOpen ? 2 : 1;
111
- ctx.strokeRect(this.x, this.y, this.width, this.height);
112
-
113
- // Texte
114
- ctx.fillStyle = selectedValue === this.placeholder ? '#999999' : '#000000';
115
- ctx.font = `${this.fontSize}px Roboto, sans-serif`;
116
- ctx.textAlign = 'left';
117
- ctx.textBaseline = 'middle';
118
- ctx.fillText(selectedValue, this.x + 15, this.y + this.height / 2);
119
-
120
- // Flèche
121
- ctx.fillStyle = '#666666';
122
- const arrowX = this.x + this.width - 20;
123
- const arrowY = this.y + this.height / 2;
124
- ctx.beginPath();
125
- ctx.moveTo(arrowX - 5, arrowY - 3);
126
- ctx.lineTo(arrowX + 5, arrowY - 3);
127
- ctx.lineTo(arrowX, arrowY + 3);
128
- ctx.closePath();
129
- ctx.fill();
130
- } else {
131
- // Cupertino Select
132
- ctx.fillStyle = '#FFFFFF';
133
- ctx.beginPath();
134
- this.roundRect(ctx, this.x, this.y, this.width, this.height, 8);
135
- ctx.fill();
136
-
137
- ctx.strokeStyle = this.isOpen ? '#007AFF' : '#C7C7CC';
138
- ctx.lineWidth = 1;
139
- ctx.stroke();
140
-
141
- // Texte
142
- ctx.fillStyle = selectedValue === this.placeholder ? '#999999' : '#000000';
143
- ctx.font = `${this.fontSize}px -apple-system, sans-serif`;
144
- ctx.textAlign = 'left';
145
- ctx.textBaseline = 'middle';
146
- ctx.fillText(selectedValue, this.x + 15, this.y + this.height / 2);
147
-
148
- // Chevron
149
- ctx.strokeStyle = '#007AFF';
150
- ctx.lineWidth = 2;
151
- const chevronX = this.x + this.width - 20;
152
- const chevronY = this.y + this.height / 2;
153
- ctx.beginPath();
154
- ctx.moveTo(chevronX - 5, chevronY - 3);
155
- ctx.lineTo(chevronX, chevronY + 2);
156
- ctx.lineTo(chevronX + 5, chevronY - 3);
157
- ctx.stroke();
158
- }
159
-
160
- ctx.restore();
161
- }
162
-
163
- /**
164
- * Dessine un rectangle avec des coins arrondis
165
- * @param {CanvasRenderingContext2D} ctx - Contexte de dessin
166
- * @param {number} x - Position X
167
- * @param {number} y - Position Y
168
- * @param {number} width - Largeur
169
- * @param {number} height - Hauteur
170
- * @param {number} radius - Rayon des coins
171
- * @private
172
- */
173
- roundRect(ctx, x, y, width, height, radius) {
174
- ctx.moveTo(x + radius, y);
175
- ctx.lineTo(x + width - radius, y);
176
- ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
177
- ctx.lineTo(x + width, y + height - radius);
178
- ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
179
- ctx.lineTo(x + radius, y + height);
180
- ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
181
- ctx.lineTo(x, y + radius);
182
- ctx.quadraticCurveTo(x, y, x + radius, y);
183
- }
184
-
185
- /**
186
- * Vérifie si un point est à l'intérieur du composant
187
- * @param {number} x - Position X
188
- * @param {number} y - Position Y
189
- * @returns {boolean} True si le point est à l'intérieur
190
- */
191
- isPointInside(x, y) {
192
- return x >= this.x &&
193
- x <= this.x + this.width &&
194
- y >= this.y &&
195
- y <= this.y + this.height;
196
- }
197
- }
198
-
199
- export default Select;
@@ -1,255 +0,0 @@
1
- import Modal from '../components/Modal.js';
2
- /**
3
- * Modal pour la sélection d'une option parmi une liste
4
- * @class
5
- * @extends Modal
6
- * @param {Framework} framework - Instance du framework
7
- * @param {Object} [options={}] - Options de configuration
8
- * @param {string} [options.title='Sélectionner une option'] - Titre du modal
9
- * @param {string[]} [options.options=[]] - Liste des options
10
- * @param {number} [options.selectedIndex=0] - Index de l'option sélectionnée par défaut
11
- * @param {Function} [options.onSelect] - Callback lors de la sélection
12
- * @example
13
- * const dialog = new SelectDialog(framework, {
14
- * title: 'Choisir une couleur',
15
- * options: ['Rouge', 'Vert', 'Bleu'],
16
- * selectedIndex: 1,
17
- * onSelect: (index, value) => console.log('Selected:', value)
18
- * });
19
- */
20
- class SelectDialog extends Modal {
21
- /**
22
- * @constructs SelectDialog
23
- */
24
- constructor(framework, options = {}) {
25
- // Calculer la hauteur en fonction du nombre d'options
26
- const optionsCount = options.options?.length || 0;
27
- const itemHeight = 50;
28
- const dialogHeight = Math.min(
29
- 400, // Hauteur max
30
- Math.max(200, optionsCount * itemHeight + 100) // Hauteur min + espace pour titre
31
- );
32
-
33
- // Appeler le constructeur parent
34
- super(framework, {
35
- title: options.title || 'Sélectionner une option',
36
- width: Math.min(350, framework.width - 40),
37
- height: dialogHeight,
38
- showCloseButton: true,
39
- closeOnOverlayClick: true,
40
- padding: 0, // Pas de padding, on gère nous-même
41
- ...options
42
- });
43
-
44
- /** @type {string[]} */
45
- this.options = options.options || [];
46
- /** @type {number} */
47
- this.selectedIndex = options.selectedIndex || 0;
48
- /** @type {Function|undefined} */
49
- this.onSelect = options.onSelect;
50
- /** @type {number} */
51
- this.itemHeight = itemHeight;
52
- /** @type {number} */
53
- this.hoveredIndex = -1;
54
-
55
- // Désactiver les animations
56
- this.opacity = 1;
57
- this.scale = 1;
58
- this.isVisible = true;
59
- this.visible = true;
60
-
61
- // AJOUTER: Définir onPress et onMove pour que le framework les appelle
62
- this.onPress = this.handlePress.bind(this);
63
- this.onMove = this.handleMove.bind(this);
64
- }
65
-
66
- /**
67
- * Dessine le modal de sélection
68
- * @param {CanvasRenderingContext2D} ctx - Contexte de dessin
69
- */
70
- draw(ctx) {
71
- if (!this.isVisible) return;
72
-
73
- ctx.save();
74
- ctx.globalAlpha = this.opacity;
75
-
76
- // Overlay sombre
77
- ctx.fillStyle = 'rgba(0, 0, 0, 0.5)';
78
- ctx.fillRect(0, 0, this.framework.width, this.framework.height);
79
-
80
- // Calculer la position du modal (centré)
81
- const modalX = (this.framework.width - this.modalWidth) / 2;
82
- const modalY = (this.framework.height - this.modalHeight) / 2;
83
-
84
- // Fond du modal
85
- ctx.fillStyle = '#FFFFFF';
86
- ctx.shadowColor = 'rgba(0, 0, 0, 0.3)';
87
- ctx.shadowBlur = 20;
88
- ctx.shadowOffsetY = 10;
89
-
90
- ctx.beginPath();
91
- this.roundRect(ctx, modalX, modalY, this.modalWidth, this.modalHeight, 12);
92
- ctx.fill();
93
-
94
- ctx.shadowColor = 'transparent';
95
-
96
- // Titre
97
- if (this.title) {
98
- ctx.fillStyle = '#000000';
99
- ctx.font = 'bold 18px -apple-system, sans-serif';
100
- ctx.textAlign = 'center';
101
- ctx.textBaseline = 'middle';
102
- ctx.fillText(this.title, modalX + this.modalWidth / 2, modalY + 30);
103
-
104
- // Ligne de séparation sous le titre
105
- ctx.strokeStyle = '#E0E0E0';
106
- ctx.lineWidth = 1;
107
- ctx.beginPath();
108
- ctx.moveTo(modalX, modalY + 50);
109
- ctx.lineTo(modalX + this.modalWidth, modalY + 50);
110
- ctx.stroke();
111
- }
112
-
113
- // Zone de contenu (avec scroll si nécessaire)
114
- const contentX = modalX;
115
- const contentY = modalY + 55; // Après le titre et la ligne
116
- const contentHeight = this.modalHeight - 55;
117
-
118
- ctx.save();
119
- ctx.beginPath();
120
- ctx.rect(contentX, contentY, this.modalWidth, contentHeight);
121
- ctx.clip();
122
-
123
- // Options
124
- for (let i = 0; i < this.options.length; i++) {
125
- const optionY = contentY + i * this.itemHeight;
126
-
127
- // Si l'option est en dehors de la zone visible, passer à la suivante
128
- if (optionY + this.itemHeight < contentY || optionY > contentY + contentHeight) {
129
- continue;
130
- }
131
-
132
- // Option sélectionnée
133
- if (i === this.selectedIndex) {
134
- ctx.fillStyle = this.framework.platform === 'material' ? 'rgba(98, 0, 238, 0.1)' : 'rgba(0, 122, 255, 0.1)';
135
- ctx.fillRect(contentX, optionY, this.modalWidth, this.itemHeight);
136
- }
137
-
138
- // Effet hover
139
- if (this.hoveredIndex === i) {
140
- ctx.fillStyle = '#F5F5F5';
141
- ctx.fillRect(contentX, optionY, this.modalWidth, this.itemHeight);
142
- }
143
-
144
- // Texte de l'option
145
- ctx.fillStyle = i === this.selectedIndex ?
146
- (this.framework.platform === 'material' ? '#6200EE' : '#007AFF') :
147
- '#000000';
148
- ctx.font = i === this.selectedIndex ? 'bold 16px -apple-system, sans-serif' : '16px -apple-system, sans-serif';
149
- ctx.textAlign = 'left';
150
- ctx.textBaseline = 'middle';
151
- ctx.fillText(this.options[i], contentX + 20, optionY + this.itemHeight / 2);
152
-
153
- // Divider entre les options
154
- if (i < this.options.length - 1) {
155
- ctx.strokeStyle = '#E0E0E0';
156
- ctx.lineWidth = 1;
157
- ctx.beginPath();
158
- ctx.moveTo(contentX + 20, optionY + this.itemHeight);
159
- ctx.lineTo(contentX + this.modalWidth - 20, optionY + this.itemHeight);
160
- ctx.stroke();
161
- }
162
- }
163
-
164
- ctx.restore();
165
- ctx.restore();
166
- }
167
-
168
- /**
169
- * Gère le clic dans le modal
170
- * @param {number} x - Position X du clic
171
- * @param {number} y - Position Y du clic
172
- */
173
- handlePress(x, y) {
174
- // POUR LES MODALS: utiliser les coordonnées brutes car le modal est un composant FIXE
175
- // Les modals ne sont pas affectés par le scroll
176
-
177
- const modalX = (this.framework.width - this.modalWidth) / 2;
178
- const modalY = (this.framework.height - this.modalHeight) / 2;
179
- const contentY = modalY + 55;
180
-
181
- // Vérifier si une option a été cliquée
182
- for (let i = 0; i < this.options.length; i++) {
183
- const optionY = contentY + i * this.itemHeight;
184
-
185
- // IMPORTANT: Pas d'ajustement de scroll pour les modals
186
- if (y >= optionY && y <= optionY + this.itemHeight &&
187
- x >= modalX && x <= modalX + this.modalWidth) {
188
-
189
- this.selectedIndex = i;
190
- if (this.onSelect) {
191
- this.onSelect(i, this.options[i]);
192
- }
193
- this.hide();
194
- return;
195
- }
196
- }
197
-
198
- // Sinon, laisser le parent gérer (bouton de fermeture, overlay)
199
- super.handlePress(x, y);
200
- }
201
-
202
- /**
203
- * Gère le survol dans le modal
204
- * @param {number} x - Position X actuelle
205
- * @param {number} y - Position Y actuelle
206
- */
207
- handleMove(x, y) {
208
- const modalX = (this.framework.width - this.modalWidth) / 2;
209
- const modalY = (this.framework.height - this.modalHeight) / 2;
210
- const contentY = modalY + 55;
211
-
212
- this.hoveredIndex = -1;
213
-
214
- // Vérifier si on survole une option
215
- for (let i = 0; i < this.options.length; i++) {
216
- const optionY = contentY + i * this.itemHeight;
217
-
218
- // IMPORTANT: Pas d'ajustement de scroll pour les modals
219
- if (y >= optionY && y <= optionY + this.itemHeight &&
220
- x >= modalX && x <= modalX + this.modalWidth) {
221
- this.hoveredIndex = i;
222
- break;
223
- }
224
- }
225
- }
226
-
227
- /**
228
- * Vérifie si un point est à l'intérieur du modal
229
- * @param {number} x - Position X
230
- * @param {number} y - Position Y
231
- * @returns {boolean} True si le point est à l'intérieur du modal
232
- */
233
- isPointInside(x, y) {
234
- const modalX = (this.framework.width - this.modalWidth) / 2;
235
- const modalY = (this.framework.height - this.modalHeight) / 2;
236
-
237
- // Les modals sont des composants fixes, donc pas d'ajustement de scroll
238
- return x >= modalX &&
239
- x <= modalX + this.modalWidth &&
240
- y >= modalY &&
241
- y <= modalY + this.modalHeight;
242
- }
243
-
244
- /**
245
- * Affiche le modal
246
- */
247
- show() {
248
- this.isVisible = true;
249
- this.visible = true;
250
- this.opacity = 1;
251
- this.scale = 1;
252
- }
253
- }
254
-
255
- export default SelectDialog;
@@ -1,113 +0,0 @@
1
- import Component from '../core/Component.js';
2
-
3
- class Slider extends Component {
4
- constructor(framework, options = {}) {
5
- super(framework, options);
6
- this.min = options.min || 0;
7
- this.max = options.max || 100;
8
- this.value = options.value || 50;
9
- this.platform = framework.platform;
10
- this.onChange = options.onChange;
11
- this.dragging = false;
12
-
13
- // Animation state
14
- this.thumbScale = 1.0;
15
- this.targetScale = 1.0;
16
-
17
- this.onPress = this.handlePress.bind(this);
18
- this.onMove = this.handleMove.bind(this);
19
- this.onClick = this.handleClick.bind(this);
20
- }
21
-
22
- handlePress(x, y) {
23
- this.dragging = true;
24
- this.targetScale = 1.5; // Agrandissement de 50%
25
- this.updateValue(x);
26
- return true;
27
- }
28
-
29
- handleMove(x, y) {
30
- if (this.dragging) {
31
- this.updateValue(x);
32
- }
33
- }
34
-
35
- handleClick() {
36
- this.dragging = false;
37
- this.targetScale = 1.0; // Retour à la taille normale
38
- }
39
-
40
- updateValue(x) {
41
- const relativeX = Math.max(0, Math.min(this.width, x - this.x));
42
- const newValue = this.min + (relativeX / this.width) * (this.max - this.min);
43
-
44
- if (newValue !== this.value) {
45
- this.value = newValue;
46
- if (this.onChange) this.onChange(this.value);
47
- }
48
- }
49
-
50
- draw(ctx) {
51
- ctx.save();
52
-
53
- // Animation du scale
54
- this.thumbScale += (this.targetScale - this.thumbScale) * 0.2;
55
-
56
- const progress = (this.value - this.min) / (this.max - this.min);
57
- const thumbX = this.x + progress * this.width;
58
-
59
- // Track
60
- ctx.strokeStyle = this.platform === 'material' ? '#E0E0E0' : '#C7C7CC';
61
- ctx.lineWidth = 2;
62
- ctx.beginPath();
63
- ctx.moveTo(this.x, this.y + this.height / 2);
64
- ctx.lineTo(this.x + this.width, this.y + this.height / 2);
65
- ctx.stroke();
66
-
67
- // Track rempli
68
- const trackColor = this.platform === 'material' ? '#6200EE' : '#007AFF';
69
- ctx.strokeStyle = trackColor;
70
- ctx.lineWidth = 2;
71
- ctx.beginPath();
72
- ctx.moveTo(this.x, this.y + this.height / 2);
73
- ctx.lineTo(thumbX, this.y + this.height / 2);
74
- ctx.stroke();
75
-
76
- // Curseur avec animation
77
- const baseRadius = 8;
78
- const currentRadius = baseRadius * this.thumbScale;
79
-
80
- // Effet d'ombre pendant le drag
81
- if (this.dragging) {
82
- ctx.shadowColor = trackColor;
83
- ctx.shadowBlur = 10;
84
- }
85
-
86
- ctx.fillStyle = trackColor;
87
- ctx.beginPath();
88
- ctx.arc(thumbX, this.y + this.height / 2, currentRadius, 0, Math.PI * 2);
89
- ctx.fill();
90
-
91
- if (this.dragging) {
92
- ctx.shadowColor = 'transparent';
93
- ctx.shadowBlur = 0;
94
- }
95
-
96
- ctx.restore();
97
- }
98
-
99
- isPointInside(x, y) {
100
- const progress = (this.value - this.min) / (this.max - this.min);
101
- const thumbX = this.x + progress * this.width;
102
- const thumbY = this.y + this.height / 2;
103
- const maxRadius = 8 * 1.5 + 5; // Rayon max + marge
104
-
105
- // Zone de clic plus large pour faciliter l'utilisation
106
- const distance = Math.sqrt((x - thumbX) ** 2 + (y - thumbY) ** 2);
107
- return distance <= maxRadius ||
108
- (x >= this.x && x <= this.x + this.width &&
109
- y >= this.y && y <= this.y + this.height);
110
- }
111
- }
112
-
113
- export default Slider;
@@ -1,139 +0,0 @@
1
- import AppBar from './AppBar.js';
2
- /**
3
- * SliverAppBar - CanvasFramework
4
- * Collapse / Stretch / Parallax
5
- * Compatible Material & Cupertino
6
- * ⚠️ Ne modifie PAS AppBar
7
- */
8
- class SliverAppBar extends AppBar {
9
- constructor(framework, options = {}) {
10
- super(framework, {
11
- ...options,
12
- y: 0
13
- });
14
- // Heights
15
- this.expandedHeight = options.expandedHeight || 240;
16
- this.collapsedHeight = options.collapsedHeight ?? 56;
17
- // Effects
18
- this.stretch = options.stretch ?? true;
19
- this.parallax = options.parallax ?? true;
20
- this.parallaxFactor = options.parallaxFactor ?? 0.4;
21
- // Background
22
- this.backgroundImage = options.backgroundImage || null;
23
- this.backgroundColor = options.backgroundColor || this.bgColor || '#FFFFFF';
24
- this.backgroundOpacity = this._extractOpacity(this.backgroundColor);
25
- // Overlay (au-dessus de l'image)
26
- this.overlayColor = options.overlayColor || '#000000';
27
- this.overlayOpacity = options.overlayOpacity ?? 0;
28
- // Foreground (titre + icônes)
29
- this.foregroundColor = options.foregroundColor || options.textColor || this.textColor || '#FFFFFF';
30
- // SliverAppBar participe au scroll
31
- this.fixed = false;
32
- }
33
-
34
- /**
35
- * Extrait l'opacité d'une couleur rgba() ou retourne 1
36
- */
37
- _extractOpacity(color) {
38
- if (typeof color === 'string' && color.startsWith('rgba')) {
39
- const match = color.match(/rgba?\([^,]+,[^,]+,[^,]+,\s*([\d.]+)\)/);
40
- return match ? parseFloat(match[1]) : 1;
41
- }
42
- return 1;
43
- }
44
-
45
- /**
46
- * Mise à jour dynamique selon le scroll
47
- */
48
- updateWithScroll(scrollOffset) {
49
- const scrollY = -scrollOffset;
50
- const collapseRange = this.expandedHeight - this.collapsedHeight;
51
- const collapse = Math.min(scrollY, collapseRange);
52
- let newHeight = this.expandedHeight - collapse;
53
- // Stretch (overscroll)
54
- if (scrollY < 0 && this.stretch) {
55
- newHeight = this.expandedHeight - scrollY;
56
- }
57
- this.height = Math.max(newHeight, this.collapsedHeight);
58
- }
59
-
60
- draw(ctx) {
61
- const scrollOffset = this.framework.scrollOffset || 0;
62
- this.updateWithScroll(scrollOffset);
63
- ctx.save();
64
- // ===== Collapse progress (0 → 1)
65
- const collapseProgress = Math.min(
66
- 1,
67
- Math.max(
68
- 0,
69
- (this.expandedHeight - this.height) /
70
- (this.expandedHeight - this.collapsedHeight)
71
- )
72
- );
73
- // ===== BACKGROUND IMAGE (en premier) =====
74
- if (this.backgroundImage && this.backgroundImage.complete) {
75
- let bgOffset = 0;
76
- if (this.parallax) {
77
- bgOffset = Math.max(0, -scrollOffset * this.parallaxFactor);
78
- }
79
- ctx.drawImage(
80
- this.backgroundImage,
81
- this.x,
82
- this.y - bgOffset,
83
- this.width,
84
- this.height + bgOffset
85
- );
86
- }
87
-
88
- // ===== BACKGROUND COLOR (overlay coloré au-dessus de l'image) =====
89
- ctx.globalAlpha = this.backgroundOpacity;
90
- ctx.fillStyle = this.backgroundColor;
91
- ctx.fillRect(this.x, this.y, this.width, this.height);
92
- ctx.globalAlpha = 1;
93
-
94
- // ===== OVERLAY SUPPLÉMENTAIRE (si besoin) =====
95
- if (this.overlayOpacity > 0) {
96
- ctx.globalAlpha = this.overlayOpacity;
97
- ctx.fillStyle = this.overlayColor;
98
- ctx.fillRect(this.x, this.y, this.width, this.height);
99
- ctx.globalAlpha = 1;
100
- }
101
- // ===== TITLE (fade with collapse) =====
102
- ctx.globalAlpha = 1 - collapseProgress;
103
- ctx.fillStyle = this.foregroundColor;
104
- ctx.font = `bold 20px -apple-system, Roboto, sans-serif`;
105
- ctx.textAlign = 'left';
106
- ctx.textBaseline = 'bottom';
107
- ctx.fillText(
108
- this.title,
109
- this.x + 16,
110
- this.y + this.height - 16
111
- );
112
- ctx.globalAlpha = 1;
113
-
114
- // ===== PREVENT APPBAR BACKGROUND OVERWRITE =====
115
- const originalBg = this.bgColor;
116
- const originalTextColor = this.textColor;
117
- const originalIconColor = this.iconColor;
118
- const originalPlatform = this.platform;
119
-
120
- // Force transparent pour éviter que super.draw() dessine un fond
121
- this.bgColor = 'rgba(0,0,0,0)';
122
- // Force la couleur du texte et des icônes
123
- this.textColor = this.foregroundColor;
124
- this.iconColor = this.foregroundColor;
125
- // Force Material pour uniformiser le comportement des couleurs
126
- this.platform = 'material';
127
-
128
- // Icons, ripple, elevation, etc.
129
- super.draw(ctx);
130
-
131
- // Restore
132
- this.bgColor = originalBg;
133
- this.textColor = originalTextColor;
134
- this.iconColor = originalIconColor;
135
- this.platform = originalPlatform;
136
- ctx.restore();
137
- }
138
- }
139
- export default SliverAppBar;