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