canvasframework 0.6.3 → 0.7.1
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 +159 -99
- package/components/Avatar.js +142 -143
- package/components/BottomSheet.js +124 -106
- package/components/Button.js +207 -254
- package/components/Checkbox.js +98 -91
- package/components/Chip.js +137 -106
- package/components/Dialog.js +161 -146
- package/components/FAB.js +122 -195
- package/components/Switch.js +146 -112
- package/components/Text.js +104 -103
- package/components/Toast.js +132 -156
- package/components/VirtualList.js +88 -59
- package/core/CanvasFramework.js +115 -44
- package/core/CanvasUtils.js +141 -0
- package/core/Component.js +124 -66
- package/core/ThemeManager.js +162 -176
- package/core/WebGLCanvasAdapter.js +88 -39
- package/package.json +1 -1
package/core/ThemeManager.js
CHANGED
|
@@ -1,347 +1,333 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Gestionnaire de thèmes indépendant et fiable
|
|
3
|
-
* Gère automatiquement le light/dark mode avec persistance
|
|
2
|
+
* Gestionnaire de thèmes indépendant et fiable.
|
|
3
|
+
* Gère automatiquement le light/dark mode avec persistance localStorage.
|
|
4
|
+
*
|
|
5
|
+
* IMPORTANT : Ce gestionnaire est la seule source de vérité pour le thème.
|
|
6
|
+
* Ne pas dupliquer la logique themeMode / setupSystemThemeListener dans
|
|
7
|
+
* CanvasFramework — déléguer entièrement à cette classe.
|
|
4
8
|
*/
|
|
5
9
|
class ThemeManager {
|
|
6
10
|
constructor(framework, options = {}) {
|
|
7
11
|
this.framework = framework;
|
|
8
|
-
|
|
9
|
-
// Thèmes par défaut (peuvent être overridés)
|
|
12
|
+
|
|
13
|
+
// Thèmes par défaut (peuvent être overridés via options)
|
|
10
14
|
this.themes = {
|
|
11
15
|
light: options.lightTheme || {
|
|
12
16
|
// Couleurs de base
|
|
13
17
|
background: '#FFFFFF',
|
|
14
18
|
surface: '#F5F5F5',
|
|
15
19
|
surfaceVariant: '#E7E0EC',
|
|
16
|
-
|
|
20
|
+
|
|
17
21
|
// Texte
|
|
18
22
|
text: '#1C1B1F',
|
|
19
23
|
textSecondary: '#49454F',
|
|
20
24
|
textDisabled: '#79747E',
|
|
21
|
-
|
|
25
|
+
|
|
22
26
|
// Primaire
|
|
23
27
|
primary: '#6750A4',
|
|
24
28
|
onPrimary: '#FFFFFF',
|
|
25
29
|
primaryContainer: '#EADDFF',
|
|
26
30
|
onPrimaryContainer: '#21005D',
|
|
27
|
-
|
|
31
|
+
|
|
28
32
|
// Secondaire
|
|
29
33
|
secondary: '#625B71',
|
|
30
34
|
onSecondary: '#FFFFFF',
|
|
31
35
|
secondaryContainer: '#E8DEF8',
|
|
32
36
|
onSecondaryContainer: '#1D192B',
|
|
33
|
-
|
|
37
|
+
|
|
34
38
|
// Tertiaire
|
|
35
39
|
tertiary: '#7D5260',
|
|
36
40
|
onTertiary: '#FFFFFF',
|
|
37
41
|
tertiaryContainer: '#FFD8E4',
|
|
38
42
|
onTertiaryContainer: '#31111D',
|
|
39
|
-
|
|
43
|
+
|
|
40
44
|
// Erreur
|
|
41
45
|
error: '#B3261E',
|
|
42
46
|
onError: '#FFFFFF',
|
|
43
47
|
errorContainer: '#F9DEDC',
|
|
44
48
|
onErrorContainer: '#410E0B',
|
|
45
|
-
|
|
49
|
+
|
|
46
50
|
// Bordures et dividers
|
|
47
51
|
border: '#CAC4D0',
|
|
48
52
|
divider: '#E0E0E0',
|
|
49
53
|
outline: '#79747E',
|
|
50
54
|
outlineVariant: '#CAC4D0',
|
|
51
|
-
|
|
55
|
+
|
|
52
56
|
// États
|
|
53
57
|
hover: 'rgba(103, 80, 164, 0.08)',
|
|
54
58
|
pressed: 'rgba(103, 80, 164, 0.12)',
|
|
55
59
|
focus: 'rgba(103, 80, 164, 0.12)',
|
|
56
60
|
disabled: 'rgba(28, 27, 31, 0.12)',
|
|
57
|
-
|
|
61
|
+
|
|
58
62
|
// Ombres
|
|
59
63
|
shadow: 'rgba(0, 0, 0, 0.2)',
|
|
60
64
|
elevation1: 'rgba(0, 0, 0, 0.05)',
|
|
61
65
|
elevation2: 'rgba(0, 0, 0, 0.08)',
|
|
62
66
|
elevation3: 'rgba(0, 0, 0, 0.12)',
|
|
63
67
|
},
|
|
64
|
-
|
|
68
|
+
|
|
65
69
|
dark: options.darkTheme || {
|
|
66
70
|
// Couleurs de base
|
|
67
71
|
background: '#1C1B1F',
|
|
68
72
|
surface: '#2B2930',
|
|
69
73
|
surfaceVariant: '#49454F',
|
|
70
|
-
|
|
74
|
+
|
|
71
75
|
// Texte
|
|
72
76
|
text: '#E6E1E5',
|
|
73
77
|
textSecondary: '#CAC4D0',
|
|
74
78
|
textDisabled: '#938F99',
|
|
75
|
-
|
|
79
|
+
|
|
76
80
|
// Primaire
|
|
77
81
|
primary: '#D0BCFF',
|
|
78
82
|
onPrimary: '#381E72',
|
|
79
83
|
primaryContainer: '#4F378B',
|
|
80
84
|
onPrimaryContainer: '#EADDFF',
|
|
81
|
-
|
|
85
|
+
|
|
82
86
|
// Secondaire
|
|
83
87
|
secondary: '#CCC2DC',
|
|
84
88
|
onSecondary: '#332D41',
|
|
85
89
|
secondaryContainer: '#4A4458',
|
|
86
90
|
onSecondaryContainer: '#E8DEF8',
|
|
87
|
-
|
|
91
|
+
|
|
88
92
|
// Tertiaire
|
|
89
93
|
tertiary: '#EFB8C8',
|
|
90
94
|
onTertiary: '#492532',
|
|
91
95
|
tertiaryContainer: '#633B48',
|
|
92
96
|
onTertiaryContainer: '#FFD8E4',
|
|
93
|
-
|
|
97
|
+
|
|
94
98
|
// Erreur
|
|
95
99
|
error: '#F2B8B5',
|
|
96
100
|
onError: '#601410',
|
|
97
101
|
errorContainer: '#8C1D18',
|
|
98
102
|
onErrorContainer: '#F9DEDC',
|
|
99
|
-
|
|
103
|
+
|
|
100
104
|
// Bordures et dividers
|
|
101
105
|
border: '#938F99',
|
|
102
106
|
divider: '#3D3D3D',
|
|
103
107
|
outline: '#938F99',
|
|
104
108
|
outlineVariant: '#49454F',
|
|
105
|
-
|
|
109
|
+
|
|
106
110
|
// États
|
|
107
111
|
hover: 'rgba(208, 188, 255, 0.08)',
|
|
108
112
|
pressed: 'rgba(208, 188, 255, 0.12)',
|
|
109
113
|
focus: 'rgba(208, 188, 255, 0.12)',
|
|
110
114
|
disabled: 'rgba(230, 225, 229, 0.12)',
|
|
111
|
-
|
|
115
|
+
|
|
112
116
|
// Ombres
|
|
113
117
|
shadow: 'rgba(0, 0, 0, 0.8)',
|
|
114
118
|
elevation1: 'rgba(0, 0, 0, 0.3)',
|
|
115
119
|
elevation2: 'rgba(0, 0, 0, 0.4)',
|
|
116
120
|
elevation3: 'rgba(0, 0, 0, 0.5)',
|
|
117
|
-
}
|
|
121
|
+
},
|
|
118
122
|
};
|
|
119
|
-
|
|
123
|
+
|
|
120
124
|
// État actuel
|
|
121
|
-
this.currentMode = null; // 'light'
|
|
125
|
+
this.currentMode = null; // 'light' | 'dark' | 'system'
|
|
122
126
|
this.currentTheme = null;
|
|
123
|
-
|
|
124
|
-
// Callbacks
|
|
127
|
+
|
|
128
|
+
// Callbacks enregistrés via addListener()
|
|
125
129
|
this.listeners = [];
|
|
126
|
-
|
|
127
|
-
//
|
|
130
|
+
|
|
131
|
+
// Clé de persistence localStorage
|
|
128
132
|
this.storageKey = options.storageKey || 'app-theme-mode';
|
|
129
|
-
|
|
130
|
-
//
|
|
131
|
-
this.
|
|
133
|
+
|
|
134
|
+
// Références pour cleanup
|
|
135
|
+
this.systemMediaQuery = null;
|
|
136
|
+
this.systemChangeHandler = null;
|
|
137
|
+
|
|
138
|
+
this._init();
|
|
132
139
|
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
// 3. Appliquer le thème
|
|
145
|
-
if (savedMode) {
|
|
146
|
-
this.setMode(savedMode, false); // false = ne pas re-sauvegarder
|
|
147
|
-
} else {
|
|
148
|
-
this.setMode('system', false);
|
|
149
|
-
}
|
|
140
|
+
|
|
141
|
+
// ─────────────────────────────────────────
|
|
142
|
+
// INITIALISATION
|
|
143
|
+
// ─────────────────────────────────────────
|
|
144
|
+
|
|
145
|
+
/** @private */
|
|
146
|
+
_init() {
|
|
147
|
+
const savedMode = this._loadPreference();
|
|
148
|
+
this._setupSystemListener();
|
|
149
|
+
// false = ne pas re-sauvegarder lors de l'init
|
|
150
|
+
this.setMode(savedMode || 'system', false);
|
|
150
151
|
}
|
|
151
|
-
|
|
152
|
-
/**
|
|
153
|
-
|
|
154
|
-
*/
|
|
155
|
-
loadPreference() {
|
|
152
|
+
|
|
153
|
+
/** @private */
|
|
154
|
+
_loadPreference() {
|
|
156
155
|
try {
|
|
157
156
|
const saved = localStorage.getItem(this.storageKey);
|
|
158
|
-
if (saved && ['light', 'dark', 'system'].includes(saved))
|
|
159
|
-
return saved;
|
|
160
|
-
}
|
|
157
|
+
if (saved && ['light', 'dark', 'system'].includes(saved)) return saved;
|
|
161
158
|
} catch (e) {
|
|
162
|
-
console.warn('Impossible de charger les préférences
|
|
159
|
+
console.warn('[ThemeManager] Impossible de charger les préférences :', e);
|
|
163
160
|
}
|
|
164
161
|
return null;
|
|
165
162
|
}
|
|
166
|
-
|
|
167
|
-
/**
|
|
168
|
-
|
|
169
|
-
*/
|
|
170
|
-
savePreference(mode) {
|
|
163
|
+
|
|
164
|
+
/** @private */
|
|
165
|
+
_savePreference(mode) {
|
|
171
166
|
try {
|
|
172
167
|
localStorage.setItem(this.storageKey, mode);
|
|
173
168
|
} catch (e) {
|
|
174
|
-
console.warn('Impossible de sauvegarder les préférences
|
|
169
|
+
console.warn('[ThemeManager] Impossible de sauvegarder les préférences :', e);
|
|
175
170
|
}
|
|
176
171
|
}
|
|
177
|
-
|
|
178
|
-
/**
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
const handleChange = (e) => {
|
|
185
|
-
// Ne réagir que si on est en mode 'system'
|
|
186
|
-
if (this.currentMode === 'system') {
|
|
187
|
-
this.applySystemTheme();
|
|
188
|
-
}
|
|
172
|
+
|
|
173
|
+
/** @private */
|
|
174
|
+
_setupSystemListener() {
|
|
175
|
+
this.systemMediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
|
|
176
|
+
this.systemChangeHandler = () => {
|
|
177
|
+
if (this.currentMode === 'system') this._applySystemTheme();
|
|
189
178
|
};
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
mediaQuery.addEventListener('change', handleChange);
|
|
179
|
+
|
|
180
|
+
if (this.systemMediaQuery.addEventListener) {
|
|
181
|
+
this.systemMediaQuery.addEventListener('change', this.systemChangeHandler);
|
|
194
182
|
} else {
|
|
195
|
-
// Fallback
|
|
196
|
-
|
|
183
|
+
// Fallback anciens navigateurs
|
|
184
|
+
this.systemMediaQuery.addListener(this.systemChangeHandler);
|
|
197
185
|
}
|
|
198
|
-
|
|
199
|
-
// Sauvegarder pour cleanup
|
|
200
|
-
this.systemMediaQuery = mediaQuery;
|
|
201
|
-
this.systemChangeHandler = handleChange;
|
|
202
186
|
}
|
|
203
|
-
|
|
204
|
-
/**
|
|
205
|
-
|
|
206
|
-
*/
|
|
207
|
-
applySystemTheme() {
|
|
187
|
+
|
|
188
|
+
/** @private */
|
|
189
|
+
_applySystemTheme() {
|
|
208
190
|
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
|
209
|
-
|
|
210
|
-
this.applyTheme(theme);
|
|
191
|
+
this._applyTheme(prefersDark ? this.themes.dark : this.themes.light);
|
|
211
192
|
}
|
|
212
|
-
|
|
193
|
+
|
|
194
|
+
// ─────────────────────────────────────────
|
|
195
|
+
// API PUBLIQUE
|
|
196
|
+
// ─────────────────────────────────────────
|
|
197
|
+
|
|
213
198
|
/**
|
|
214
|
-
* Définit le mode de thème
|
|
199
|
+
* Définit le mode de thème.
|
|
215
200
|
* @param {'light'|'dark'|'system'} mode
|
|
216
|
-
* @param {boolean} save -
|
|
201
|
+
* @param {boolean} [save=true] - Persister la préférence
|
|
217
202
|
*/
|
|
218
203
|
setMode(mode, save = true) {
|
|
219
204
|
if (!['light', 'dark', 'system'].includes(mode)) {
|
|
220
|
-
console.warn(`Mode invalide: ${mode}.
|
|
205
|
+
console.warn(`[ThemeManager] Mode invalide : "${mode}". Utiliser 'light', 'dark' ou 'system'.`);
|
|
221
206
|
return;
|
|
222
207
|
}
|
|
223
|
-
|
|
208
|
+
|
|
224
209
|
this.currentMode = mode;
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
if (save) {
|
|
228
|
-
this.savePreference(mode);
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
// Appliquer le thème correspondant
|
|
210
|
+
if (save) this._savePreference(mode);
|
|
211
|
+
|
|
232
212
|
if (mode === 'system') {
|
|
233
|
-
this.
|
|
213
|
+
this._applySystemTheme();
|
|
234
214
|
} else {
|
|
235
|
-
|
|
236
|
-
this.applyTheme(theme);
|
|
215
|
+
this._applyTheme(this.themes[mode]);
|
|
237
216
|
}
|
|
238
217
|
}
|
|
239
|
-
|
|
240
|
-
/**
|
|
241
|
-
* Applique un thème au framework
|
|
242
|
-
*/
|
|
243
|
-
applyTheme(theme) {
|
|
244
|
-
this.currentTheme = theme;
|
|
245
|
-
|
|
246
|
-
// Mettre à jour le framework
|
|
247
|
-
if (this.framework) {
|
|
248
|
-
this.framework.theme = theme;
|
|
249
|
-
|
|
250
|
-
// Forcer le rendu de tous les composants
|
|
251
|
-
if (this.framework.components) {
|
|
252
|
-
this.framework.components.forEach(comp => {
|
|
253
|
-
if (comp.markDirty) {
|
|
254
|
-
comp.markDirty();
|
|
255
|
-
}
|
|
256
|
-
});
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
// Notifier les listeners
|
|
261
|
-
this.notifyListeners(theme);
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
/**
|
|
265
|
-
* Obtient le mode actuel
|
|
266
|
-
*/
|
|
218
|
+
|
|
219
|
+
/** Retourne le mode actuel : 'light', 'dark' ou 'system'. */
|
|
267
220
|
getMode() {
|
|
268
221
|
return this.currentMode;
|
|
269
222
|
}
|
|
270
|
-
|
|
223
|
+
|
|
271
224
|
/**
|
|
272
|
-
*
|
|
225
|
+
* Retourne le mode effectif résolu ('light' ou 'dark').
|
|
226
|
+
* Utile quand currentMode === 'system'.
|
|
227
|
+
* @returns {'light'|'dark'}
|
|
273
228
|
*/
|
|
229
|
+
getResolvedMode() {
|
|
230
|
+
if (this.currentMode !== 'system') return this.currentMode;
|
|
231
|
+
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/** Retourne le thème courant (objet de couleurs). */
|
|
274
235
|
getTheme() {
|
|
275
236
|
return this.currentTheme;
|
|
276
237
|
}
|
|
277
|
-
|
|
238
|
+
|
|
278
239
|
/**
|
|
279
|
-
*
|
|
240
|
+
* Retourne une couleur spécifique du thème courant.
|
|
241
|
+
* @param {string} colorName
|
|
242
|
+
* @returns {string}
|
|
280
243
|
*/
|
|
281
244
|
getColor(colorName) {
|
|
282
|
-
return this.currentTheme?.[colorName]
|
|
245
|
+
return this.currentTheme?.[colorName] ?? '#000000';
|
|
283
246
|
}
|
|
284
|
-
|
|
285
|
-
/**
|
|
286
|
-
* Bascule entre light et dark
|
|
287
|
-
*/
|
|
247
|
+
|
|
248
|
+
/** Bascule entre light et dark (ou quitte system). */
|
|
288
249
|
toggle() {
|
|
289
250
|
if (this.currentMode === 'system') {
|
|
290
|
-
// Si en mode system, basculer vers le mode opposé
|
|
291
251
|
const isDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
|
292
252
|
this.setMode(isDark ? 'light' : 'dark');
|
|
293
253
|
} else {
|
|
294
|
-
// Basculer entre light et dark
|
|
295
254
|
this.setMode(this.currentMode === 'light' ? 'dark' : 'light');
|
|
296
255
|
}
|
|
297
256
|
}
|
|
298
|
-
|
|
257
|
+
|
|
299
258
|
/**
|
|
300
|
-
*
|
|
259
|
+
* Enregistre un callback appelé à chaque changement de thème.
|
|
260
|
+
* Le callback est appelé immédiatement avec le thème courant,
|
|
261
|
+
* SEULEMENT si celui-ci est déjà initialisé (évite les appels avec null).
|
|
262
|
+
*
|
|
263
|
+
* @param {Function} callback - Reçoit le thème courant en argument
|
|
301
264
|
*/
|
|
302
265
|
addListener(callback) {
|
|
303
|
-
if (typeof callback
|
|
304
|
-
|
|
305
|
-
|
|
266
|
+
if (typeof callback !== 'function') return;
|
|
267
|
+
this.listeners.push(callback);
|
|
268
|
+
// Appel immédiat uniquement si le thème est déjà prêt
|
|
269
|
+
if (this.currentTheme !== null) {
|
|
306
270
|
callback(this.currentTheme);
|
|
307
271
|
}
|
|
308
272
|
}
|
|
309
|
-
|
|
273
|
+
|
|
310
274
|
/**
|
|
311
|
-
*
|
|
275
|
+
* Supprime un callback enregistré.
|
|
276
|
+
* @param {Function} callback
|
|
312
277
|
*/
|
|
313
278
|
removeListener(callback) {
|
|
314
279
|
const index = this.listeners.indexOf(callback);
|
|
315
|
-
if (index > -1)
|
|
316
|
-
this.listeners.splice(index, 1);
|
|
317
|
-
}
|
|
280
|
+
if (index > -1) this.listeners.splice(index, 1);
|
|
318
281
|
}
|
|
319
|
-
|
|
282
|
+
|
|
320
283
|
/**
|
|
321
|
-
*
|
|
284
|
+
* Enregistre un thème personnalisé sous un nom donné.
|
|
285
|
+
* @param {string} name - Ex : 'high-contrast'
|
|
286
|
+
* @param {Object} theme - Objet de couleurs
|
|
322
287
|
*/
|
|
323
|
-
|
|
324
|
-
this.
|
|
288
|
+
setCustomTheme(name, theme) {
|
|
289
|
+
this.themes[name] = theme;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// ─────────────────────────────────────────
|
|
293
|
+
// INTERNE
|
|
294
|
+
// ─────────────────────────────────────────
|
|
295
|
+
|
|
296
|
+
/** @private */
|
|
297
|
+
_applyTheme(theme) {
|
|
298
|
+
this.currentTheme = theme;
|
|
299
|
+
|
|
300
|
+
if (this.framework) {
|
|
301
|
+
this.framework.theme = theme;
|
|
302
|
+
|
|
303
|
+
// Invalider tous les composants pour forcer un redessin
|
|
304
|
+
if (this.framework.components) {
|
|
305
|
+
for (const comp of this.framework.components) {
|
|
306
|
+
comp.markDirty?.();
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
this._notifyListeners(theme);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/** @private */
|
|
315
|
+
_notifyListeners(theme) {
|
|
316
|
+
for (const callback of this.listeners) {
|
|
325
317
|
try {
|
|
326
318
|
callback(theme);
|
|
327
319
|
} catch (e) {
|
|
328
|
-
console.error('Erreur dans un listener de thème:', e);
|
|
320
|
+
console.error('[ThemeManager] Erreur dans un listener de thème :', e);
|
|
329
321
|
}
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
/**
|
|
334
|
-
* Définit un thème personnalisé
|
|
335
|
-
*/
|
|
336
|
-
setCustomTheme(name, theme) {
|
|
337
|
-
this.themes[name] = theme;
|
|
322
|
+
}
|
|
338
323
|
}
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
324
|
+
|
|
325
|
+
// ─────────────────────────────────────────
|
|
326
|
+
// DESTROY
|
|
327
|
+
// ─────────────────────────────────────────
|
|
328
|
+
|
|
329
|
+
/** Nettoie les ressources (event listeners système, callbacks). */
|
|
343
330
|
destroy() {
|
|
344
|
-
// Retirer l'écoute système
|
|
345
331
|
if (this.systemMediaQuery && this.systemChangeHandler) {
|
|
346
332
|
if (this.systemMediaQuery.removeEventListener) {
|
|
347
333
|
this.systemMediaQuery.removeEventListener('change', this.systemChangeHandler);
|
|
@@ -349,9 +335,9 @@ class ThemeManager {
|
|
|
349
335
|
this.systemMediaQuery.removeListener(this.systemChangeHandler);
|
|
350
336
|
}
|
|
351
337
|
}
|
|
352
|
-
|
|
353
|
-
// Vider les listeners
|
|
354
338
|
this.listeners = [];
|
|
339
|
+
this.systemMediaQuery = null;
|
|
340
|
+
this.systemChangeHandler = null;
|
|
355
341
|
}
|
|
356
342
|
}
|
|
357
343
|
|