This commit is contained in:
Louis Mazin 2026-09-20 04:46:33 +02:00
parent 7c0ebd6923
commit e150c59408

View File

@ -335,7 +335,12 @@ const TimePicker = ({
placeholder = 'Choisir une heure',
}) => {
const [open, setOpen] = useState(false);
const touchStartY = useRef(null);
const touchState = useRef({
active: false,
lastY: 0,
accumulated: 0,
});
const [hours = '', minutes = ''] = value
? value.split(':')
@ -366,10 +371,16 @@ const TimePicker = ({
const currentHour = Number(hours || 0);
const currentMinute = Number(minutes || 0);
let nextHour = currentHour + direction;
let nextHour =
currentHour + direction;
if (nextHour < 0) nextHour = 23;
if (nextHour > 23) nextHour = 0;
if (nextHour < 0) {
nextHour = 23;
}
if (nextHour > 23) {
nextHour = 0;
}
updateTime(
nextHour,
@ -381,11 +392,14 @@ const TimePicker = ({
const currentHour = Number(hours || 0);
const currentMinute = Number(minutes || 0);
let nextMinute = currentMinute + direction;
let nextMinute =
currentMinute + direction;
let nextHour = currentHour;
if (nextMinute < 0) {
nextMinute = 59;
nextHour =
currentHour === 0
? 23
@ -394,6 +408,7 @@ const TimePicker = ({
if (nextMinute > 59) {
nextMinute = 0;
nextHour =
currentHour === 23
? 0
@ -406,6 +421,7 @@ const TimePicker = ({
);
};
// PC : une molette = une unité
const handleWheel = (
event,
type,
@ -413,7 +429,6 @@ const TimePicker = ({
event.preventDefault();
event.stopPropagation();
// Une molette = une seule unité
const direction =
event.deltaY > 0 ? 1 : -1;
@ -424,42 +439,74 @@ const TimePicker = ({
}
};
// MOBILE : début du déplacement
const handleTouchStart = (event) => {
touchStartY.current =
event.touches[0].clientY;
const touch = event.touches[0];
touchState.current = {
active: true,
lastY: touch.clientY,
accumulated: 0,
};
};
const handleTouchEnd = (
// MOBILE : déplacement continu
const handleTouchMove = (
event,
type,
) => {
if (touchStartY.current === null) {
if (!touchState.current.active) {
return;
}
const touchEndY =
event.changedTouches[0].clientY;
const touch = event.touches[0];
const currentY = touch.clientY;
// Distance parcourue depuis le dernier mouvement
const deltaY =
touchStartY.current - touchEndY;
touchState.current.lastY - currentY;
touchStartY.current = null;
touchState.current.lastY = currentY;
// Ignore les tout petits mouvements
if (Math.abs(deltaY) < 20) {
// On accumule le déplacement
touchState.current.accumulated +=
deltaY;
/*
* Distance nécessaire pour changer
* d'une unité.
*
* Plus petit = plus sensible
* Plus grand = plus lent
*/
const pixelsPerUnit = 18;
const steps = Math.trunc(
touchState.current.accumulated /
pixelsPerUnit,
);
if (steps === 0) {
return;
}
// Swipe vers le haut = +1
// Swipe vers le bas = -1
const direction =
deltaY > 0 ? 1 : -1;
// On retire uniquement les unités déjà consommées
touchState.current.accumulated -=
steps * pixelsPerUnit;
if (type === 'hours') {
changeHour(direction);
changeHour(steps);
} else {
changeMinute(direction);
changeMinute(steps);
}
event.preventDefault();
event.stopPropagation();
};
const handleTouchEnd = () => {
touchState.current.active = false;
touchState.current.accumulated = 0;
};
const clearTime = () => {
@ -514,7 +561,7 @@ const TimePicker = ({
{/* HEURES */}
<div
className="flex-1 touch-none"
className="flex-1 touch-none select-none"
onWheel={(event) =>
handleWheel(
event,
@ -522,14 +569,16 @@ const TimePicker = ({
)
}
onTouchStart={handleTouchStart}
onTouchEnd={(event) =>
handleTouchEnd(
onTouchMove={(event) =>
handleTouchMove(
event,
'hours',
)
}
onTouchEnd={handleTouchEnd}
onTouchCancel={handleTouchEnd}
>
<div className="flex h-full flex-col items-center justify-center select-none">
<div className="flex h-full flex-col items-center justify-center">
<span className="h-9 text-sm text-muted-foreground/40">
{
hourOptions[
@ -565,7 +614,7 @@ const TimePicker = ({
{/* MINUTES */}
<div
className="flex-1 touch-none"
className="flex-1 touch-none select-none"
onWheel={(event) =>
handleWheel(
event,
@ -573,14 +622,16 @@ const TimePicker = ({
)
}
onTouchStart={handleTouchStart}
onTouchEnd={(event) =>
handleTouchEnd(
onTouchMove={(event) =>
handleTouchMove(
event,
'minutes',
)
}
onTouchEnd={handleTouchEnd}
onTouchCancel={handleTouchEnd}
>
<div className="flex h-full flex-col items-center justify-center select-none">
<div className="flex h-full flex-col items-center justify-center">
<span className="h-9 text-sm text-muted-foreground/40">
{
minuteOptions[
@ -609,7 +660,7 @@ const TimePicker = ({
</div>
<p className="mt-2 text-center text-[10px] text-muted-foreground">
Molette ou glissement pour modifier
Glissez pour modifier
</p>
<div className="mt-2 border-t pt-2">