canvasframework 0.7.0 → 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/CanvasUtils.js +141 -0
- package/core/Component.js +124 -66
- package/core/ThemeManager.js +162 -176
- package/package.json +1 -1
|
@@ -1,156 +1,185 @@
|
|
|
1
1
|
import Component from '../core/Component.js';
|
|
2
|
+
import { roundRect, roundRectTop } from '../core/CanvasUtils.js';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
|
-
* BottomSheet
|
|
5
|
-
*
|
|
6
|
-
*
|
|
5
|
+
* BottomSheet — Material et Cupertino.
|
|
6
|
+
*
|
|
7
|
+
* Corrections :
|
|
8
|
+
* - roundRect / roundRectTop viennent de CanvasUtils
|
|
9
|
+
* - Guard _destroyed dans les boucles RAF
|
|
10
|
+
* - destroy() nettoie les ressources
|
|
7
11
|
*/
|
|
8
12
|
class BottomSheet extends Component {
|
|
13
|
+
/**
|
|
14
|
+
* @param {CanvasFramework} framework
|
|
15
|
+
* @param {Object} [options={}]
|
|
16
|
+
* @param {number} [options.height] - Hauteur de la feuille (défaut : 60% de l'écran)
|
|
17
|
+
* @param {boolean} [options.dragHandle=true]
|
|
18
|
+
* @param {boolean} [options.closeOnOverlayClick=true]
|
|
19
|
+
* @param {string} [options.bgColor]
|
|
20
|
+
* @param {number} [options.borderRadius]
|
|
21
|
+
*/
|
|
9
22
|
constructor(framework, options = {}) {
|
|
10
23
|
super(framework, {
|
|
11
24
|
x: 0,
|
|
12
25
|
y: framework.height,
|
|
13
26
|
width: framework.width,
|
|
14
27
|
height: options.height || framework.height * 0.6,
|
|
15
|
-
visible: false
|
|
28
|
+
visible: false,
|
|
16
29
|
});
|
|
17
30
|
|
|
18
|
-
this.platform
|
|
19
|
-
|
|
20
|
-
this.
|
|
21
|
-
this.dragHandle = options.dragHandle !== false;
|
|
31
|
+
this.platform = framework.platform;
|
|
32
|
+
this.children = [];
|
|
33
|
+
this.dragHandle = options.dragHandle !== false;
|
|
22
34
|
this.closeOnOverlayClick = options.closeOnOverlayClick !== false;
|
|
23
35
|
|
|
24
|
-
// Styles plateforme
|
|
36
|
+
// Styles selon la plateforme
|
|
25
37
|
if (this.platform === 'material') {
|
|
26
|
-
this.bgColor
|
|
27
|
-
this.overlayColor
|
|
28
|
-
this.shadowBlur
|
|
38
|
+
this.bgColor = options.bgColor || '#FFFFFF';
|
|
39
|
+
this.overlayColor = 'rgba(0,0,0,0.5)';
|
|
40
|
+
this.shadowBlur = 20;
|
|
29
41
|
this.shadowOffsetY = -5;
|
|
30
|
-
this.borderRadius
|
|
31
|
-
} else {
|
|
32
|
-
this.bgColor
|
|
33
|
-
this.overlayColor
|
|
34
|
-
this.shadowBlur
|
|
42
|
+
this.borderRadius = 11;
|
|
43
|
+
} else {
|
|
44
|
+
this.bgColor = options.bgColor || 'rgba(255,255,255,0.95)';
|
|
45
|
+
this.overlayColor = 'rgba(0,0,0,0.2)';
|
|
46
|
+
this.shadowBlur = 0;
|
|
35
47
|
this.shadowOffsetY = 0;
|
|
36
|
-
this.borderRadius
|
|
48
|
+
this.borderRadius = options.borderRadius || 20;
|
|
37
49
|
}
|
|
38
50
|
|
|
39
|
-
this.targetY
|
|
40
|
-
this.isOpen
|
|
41
|
-
this.
|
|
42
|
-
this.
|
|
43
|
-
this.
|
|
44
|
-
this.
|
|
51
|
+
this.targetY = framework.height;
|
|
52
|
+
this.isOpen = false;
|
|
53
|
+
this._animating = false;
|
|
54
|
+
this._rafId = null;
|
|
55
|
+
this.dragging = false;
|
|
56
|
+
this.dragStartY = 0;
|
|
57
|
+
this.dragOffset = 0;
|
|
45
58
|
this.lastClickTime = 0;
|
|
46
59
|
|
|
47
|
-
this.onPress
|
|
48
|
-
this.onMove
|
|
49
|
-
this.onRelease = this.
|
|
60
|
+
this.onPress = this._handlePress.bind(this);
|
|
61
|
+
this.onMove = this._handleMove.bind(this);
|
|
62
|
+
this.onRelease = this._handleRelease.bind(this);
|
|
50
63
|
}
|
|
51
64
|
|
|
65
|
+
// ─────────────────────────────────────────
|
|
66
|
+
// ENFANTS
|
|
67
|
+
// ─────────────────────────────────────────
|
|
68
|
+
|
|
52
69
|
add(child) {
|
|
53
70
|
this.children.push(child);
|
|
54
71
|
return child;
|
|
55
72
|
}
|
|
56
73
|
|
|
74
|
+
// ─────────────────────────────────────────
|
|
75
|
+
// OPEN / CLOSE
|
|
76
|
+
// ─────────────────────────────────────────
|
|
77
|
+
|
|
57
78
|
open() {
|
|
58
79
|
this.visible = true;
|
|
59
|
-
this.isOpen
|
|
80
|
+
this.isOpen = true;
|
|
60
81
|
this.targetY = this.framework.height - this.height;
|
|
61
|
-
this.
|
|
82
|
+
this._animate();
|
|
62
83
|
}
|
|
63
84
|
|
|
64
85
|
close() {
|
|
65
|
-
this.isOpen
|
|
86
|
+
this.isOpen = false;
|
|
66
87
|
this.targetY = this.framework.height;
|
|
67
|
-
this.
|
|
68
|
-
this.visible = false;
|
|
69
|
-
});
|
|
88
|
+
this._animate(() => { this.visible = false; });
|
|
70
89
|
}
|
|
71
90
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
this.
|
|
91
|
+
/** @private */
|
|
92
|
+
_animate(callback) {
|
|
93
|
+
if (this._animating) return;
|
|
94
|
+
this._animating = true;
|
|
95
|
+
|
|
96
|
+
if (this._rafId) cancelAnimationFrame(this._rafId);
|
|
75
97
|
|
|
76
98
|
const step = () => {
|
|
77
|
-
|
|
99
|
+
if (this._destroyed) { this._rafId = null; this._animating = false; return; }
|
|
100
|
+
|
|
101
|
+
const diff = this.targetY - this.y;
|
|
78
102
|
|
|
79
103
|
if (Math.abs(diff) < 1) {
|
|
80
|
-
this.y
|
|
81
|
-
this.
|
|
82
|
-
|
|
104
|
+
this.y = this.targetY;
|
|
105
|
+
this._animating = false;
|
|
106
|
+
this._rafId = null;
|
|
107
|
+
callback?.();
|
|
83
108
|
return;
|
|
84
109
|
}
|
|
85
110
|
|
|
86
|
-
//
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
} else {
|
|
90
|
-
diff *= 0.2; // easing
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
this.y += diff;
|
|
94
|
-
|
|
95
|
-
requestAnimationFrame(step);
|
|
111
|
+
// Spring iOS, easing Material
|
|
112
|
+
this.y += diff * (this.platform === 'cupertino' ? 0.15 : 0.2);
|
|
113
|
+
this._rafId = requestAnimationFrame(step);
|
|
96
114
|
};
|
|
97
115
|
|
|
98
|
-
step
|
|
116
|
+
this._rafId = requestAnimationFrame(step);
|
|
99
117
|
}
|
|
100
118
|
|
|
101
|
-
|
|
119
|
+
// ─────────────────────────────────────────
|
|
120
|
+
// INTERACTIONS
|
|
121
|
+
// ─────────────────────────────────────────
|
|
122
|
+
|
|
123
|
+
/** @private */
|
|
124
|
+
_handlePress(x, y) {
|
|
102
125
|
const now = Date.now();
|
|
103
126
|
if (now - this.lastClickTime < 300) return;
|
|
104
127
|
this.lastClickTime = now;
|
|
105
128
|
|
|
129
|
+
// Clic sur l'overlay
|
|
106
130
|
if (y < this.y && this.closeOnOverlayClick) {
|
|
107
131
|
this.close();
|
|
108
132
|
return;
|
|
109
133
|
}
|
|
110
134
|
|
|
111
|
-
// Clic sur la poignée
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
}
|
|
135
|
+
// Clic sur la poignée → fermeture
|
|
136
|
+
if (this.dragHandle && y >= this.y && y <= this.y + 40) {
|
|
137
|
+
this.close();
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
117
140
|
|
|
118
|
-
//
|
|
141
|
+
// Déléguer aux enfants
|
|
119
142
|
const contentY = this.y + (this.dragHandle ? 40 : 16);
|
|
120
143
|
for (let i = this.children.length - 1; i >= 0; i--) {
|
|
121
144
|
const child = this.children[i];
|
|
122
145
|
if (!child.visible) continue;
|
|
123
146
|
|
|
124
|
-
const
|
|
125
|
-
const
|
|
147
|
+
const absX = this.x + 16 + child.x;
|
|
148
|
+
const absY = contentY + child.y;
|
|
126
149
|
|
|
127
|
-
if (x >=
|
|
128
|
-
|
|
129
|
-
if (child.onClick) child.onClick();
|
|
150
|
+
if (x >= absX && x <= absX + child.width && y >= absY && y <= absY + child.height) {
|
|
151
|
+
child.onClick?.();
|
|
130
152
|
return;
|
|
131
153
|
}
|
|
132
154
|
}
|
|
133
155
|
}
|
|
134
156
|
|
|
135
|
-
|
|
157
|
+
/** @private */
|
|
158
|
+
_handleMove(x, y) {
|
|
136
159
|
if (!this.dragging) return;
|
|
137
160
|
this.dragOffset = y - this.dragStartY;
|
|
138
|
-
|
|
161
|
+
const newY = (this.framework.height - this.height) + this.dragOffset;
|
|
139
162
|
if (newY >= this.framework.height - this.height) this.y = newY;
|
|
140
163
|
}
|
|
141
164
|
|
|
142
|
-
|
|
165
|
+
/** @private */
|
|
166
|
+
_handleRelease() {
|
|
143
167
|
if (!this.dragging) return;
|
|
144
|
-
this.dragging
|
|
168
|
+
this.dragging = false;
|
|
145
169
|
this.framework.activeComponent = null;
|
|
146
170
|
|
|
147
|
-
if (this.dragOffset > this.height * 0.3)
|
|
148
|
-
|
|
171
|
+
if (this.dragOffset > this.height * 0.3) {
|
|
172
|
+
this.close();
|
|
173
|
+
} else {
|
|
149
174
|
this.targetY = this.framework.height - this.height;
|
|
150
|
-
this.
|
|
175
|
+
this._animate();
|
|
151
176
|
}
|
|
152
177
|
}
|
|
153
178
|
|
|
179
|
+
// ─────────────────────────────────────────
|
|
180
|
+
// DESSIN
|
|
181
|
+
// ─────────────────────────────────────────
|
|
182
|
+
|
|
154
183
|
draw(ctx) {
|
|
155
184
|
if (!this.visible) return;
|
|
156
185
|
ctx.save();
|
|
@@ -159,27 +188,27 @@ class BottomSheet extends Component {
|
|
|
159
188
|
ctx.fillStyle = this.overlayColor;
|
|
160
189
|
ctx.fillRect(0, 0, this.framework.width, this.framework.height);
|
|
161
190
|
|
|
162
|
-
//
|
|
163
|
-
ctx.fillStyle
|
|
164
|
-
ctx.shadowColor
|
|
165
|
-
ctx.shadowBlur
|
|
166
|
-
ctx.shadowOffsetY
|
|
191
|
+
// Feuille
|
|
192
|
+
ctx.fillStyle = this.bgColor;
|
|
193
|
+
ctx.shadowColor = this.platform === 'material' ? 'rgba(0,0,0,0.3)' : 'transparent';
|
|
194
|
+
ctx.shadowBlur = this.shadowBlur;
|
|
195
|
+
ctx.shadowOffsetY = this.shadowOffsetY;
|
|
167
196
|
|
|
168
197
|
ctx.beginPath();
|
|
169
|
-
|
|
198
|
+
roundRectTop(ctx, this.x, this.y, this.width, this.height, this.borderRadius);
|
|
170
199
|
ctx.fill();
|
|
171
200
|
ctx.shadowColor = 'transparent';
|
|
172
201
|
|
|
173
|
-
//
|
|
202
|
+
// Poignée
|
|
174
203
|
if (this.dragHandle) {
|
|
175
204
|
ctx.fillStyle = this.platform === 'material' ? '#CCCCCC' : '#E0E0E0';
|
|
176
205
|
ctx.beginPath();
|
|
177
|
-
|
|
206
|
+
roundRect(ctx, this.width / 2 - 20, this.y + 12, 40, 4, 2);
|
|
178
207
|
ctx.fill();
|
|
179
208
|
}
|
|
180
209
|
|
|
181
|
-
//
|
|
182
|
-
const contentY
|
|
210
|
+
// Clip pour les enfants
|
|
211
|
+
const contentY = this.y + (this.dragHandle ? 40 : 16);
|
|
183
212
|
const contentHeight = this.height - (this.dragHandle ? 40 : 16);
|
|
184
213
|
|
|
185
214
|
ctx.save();
|
|
@@ -187,7 +216,7 @@ class BottomSheet extends Component {
|
|
|
187
216
|
ctx.rect(this.x, contentY, this.width, contentHeight);
|
|
188
217
|
ctx.clip();
|
|
189
218
|
|
|
190
|
-
for (
|
|
219
|
+
for (const child of this.children) {
|
|
191
220
|
if (!child.visible) continue;
|
|
192
221
|
const origX = child.x;
|
|
193
222
|
const origY = child.y;
|
|
@@ -202,33 +231,22 @@ class BottomSheet extends Component {
|
|
|
202
231
|
ctx.restore();
|
|
203
232
|
}
|
|
204
233
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
ctx.lineTo(x + width - radius, y);
|
|
208
|
-
ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
|
|
209
|
-
ctx.lineTo(x + width, y + height);
|
|
210
|
-
ctx.lineTo(x, y + height);
|
|
211
|
-
ctx.lineTo(x, y + radius);
|
|
212
|
-
ctx.quadraticCurveTo(x, y, x + radius, y);
|
|
234
|
+
isPointInside(x, y) {
|
|
235
|
+
return this.visible;
|
|
213
236
|
}
|
|
214
237
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
ctx.lineTo(x + width - radius, y);
|
|
219
|
-
ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
|
|
220
|
-
ctx.lineTo(x + width, y + height - radius);
|
|
221
|
-
ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
|
|
222
|
-
ctx.lineTo(x + radius, y + height);
|
|
223
|
-
ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
|
|
224
|
-
ctx.lineTo(x, y + radius);
|
|
225
|
-
ctx.quadraticCurveTo(x, y, x + radius, y);
|
|
226
|
-
ctx.closePath();
|
|
227
|
-
}
|
|
238
|
+
// ─────────────────────────────────────────
|
|
239
|
+
// DESTROY
|
|
240
|
+
// ─────────────────────────────────────────
|
|
228
241
|
|
|
229
|
-
|
|
230
|
-
|
|
242
|
+
destroy() {
|
|
243
|
+
if (this._rafId) {
|
|
244
|
+
cancelAnimationFrame(this._rafId);
|
|
245
|
+
this._rafId = null;
|
|
246
|
+
}
|
|
247
|
+
this.children = [];
|
|
248
|
+
super.destroy();
|
|
231
249
|
}
|
|
232
250
|
}
|
|
233
251
|
|
|
234
|
-
export default BottomSheet;
|
|
252
|
+
export default BottomSheet;
|