Skip to content

feat(player): scroll wheel on volume slider to adjust volume (#118)#121

Merged
InstaZDLL merged 3 commits into
mainfrom
feat/volume-wheel-scroll
May 23, 2026
Merged

feat(player): scroll wheel on volume slider to adjust volume (#118)#121
InstaZDLL merged 3 commits into
mainfrom
feat/volume-wheel-scroll

Conversation

@InstaZDLL
Copy link
Copy Markdown
Owner

@InstaZDLL InstaZDLL commented May 23, 2026

Closes #118.

Summary

Hovering the volume control in the player bar and scrolling the wheel now nudges the volume by 5 % per tick — wheel up raises, wheel down lowers. The step matches the keyboard arrow step that's already wired up below in the same component.

Why `addEventListener` instead of `onWheel`

React 17+ attaches root `wheel` listeners as passive, so a JSX `onWheel` handler can't `preventDefault` the underlying page scroll. Without that, scrolling over the slider would also scroll the track list behind the player bar. Binding directly with `addEventListener('wheel', handler, { passive: false })` suppresses the page scroll cleanly. No other wheel handlers in the codebase, so no precedent to follow.

The listener is attached to the first inner `

` that already wraps the volume icon + slider track — scrolling anywhere over the visible control area works, including over the mute icon button.

Test plan

  • Hover the volume slider in the player bar → scroll up → volume rises by 5 %
  • Scroll down → volume lowers by 5 %
  • Scroll past 0 / 100 → clamps (no negative or > 100 values)
  • Scroll over the mute icon at the left of the slider → also works
  • Page behind the player bar (e.g. a long track list scrolled to bottom) does NOT scroll while wheeling over the slider
  • Existing pointer drag + click + keyboard arrows still work identically
  • `bun run lint` ✅
  • `bun run typecheck` ✅

Summary by CodeRabbit

  • Nouvelles Fonctionnalités

    • Contrôle du volume par molette sur l’élément de volume : ajustement par pas de 5%, sensible uniquement au mouvement vertical, avec blocage du défilement de la page pendant l’usage pour une interaction fluide.
  • Documentation

    • Mise à jour de la documentation UI pour décrire les modalités d’entrée (molette, glisser, raccourcis), la granularité et les comportements aux limites (0%/100%).

Review Change Stack

Hovering the volume control in the player bar and scrolling the
wheel now nudges the volume by 5 % per tick — wheel up raises,
wheel down lowers, matching the keyboard arrow step that's
already wired up.

Bound directly with `addEventListener('wheel', ..., { passive:
false })` instead of an `onWheel` JSX handler because React 17+
attaches root wheel listeners as passive: a JSX `onWheel` can't
`preventDefault` the underlying page scroll, so the track list
behind the player bar would scroll at the same time. The native
listener with `passive: false` suppresses that cleanly.

The handler sits on the first inner `<div>` that already groups
the volume icon + slider track, so scrolling anywhere over the
visible control area works. Effect deps keep `volume` and
`setVolume` in scope; re-binding on every wheel tick is cheap
(single addEventListener / removeEventListener pair).
@InstaZDLL InstaZDLL added scope: frontend React/Vite frontend (src/) type: feat New feature labels May 23, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 23, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 8fe66fcc-65d8-4fa8-8769-693de90d40da

📥 Commits

Reviewing files that changed from the base of the PR and between d9fb661 and 9b3f966.

📒 Files selected for processing (1)
  • docs/features/ui.md

📝 Walkthrough

Walkthrough

Le composant VolumeControl enregistre un écouteur wheel non-passif sur son conteneur (wheelHostRef) et ajuste l'état volume par pas de 5% selon le signe de deltaY, en appelant preventDefault() pour bloquer le scroll de page; le listener est détaché au démontage.

Changes

Contrôle du volume à la molette

Couche / Fichier(s) Résumé
Gestionnaire d'événement wheel et ajustement du volume
src/components/player/VolumeControl.tsx
Ajout de l'import useEffect, définition de WHEEL_STEP et wheelHostRef, et useEffect qui attache/détache un listener wheel non-passif sur le conteneur. Le handler ignore deltaY === 0, appelle preventDefault() pour bloquer le scroll, et ajuste volume par pas de 5% selon le sens du défilement; le conteneur reçoit ref={wheelHostRef}.
Documentation UI
docs/features/ui.md
Mise à jour de la section Player-bar layout pour documenter le support du scroll souris sur la zone icône+barre, granularité (5%), sauts aux extrêmes (0/100) et l'ignorance des scrolls horizontaux.

Estimated Code Review Effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🎡 La molette tourne, le son suit la danse,
Cinq pour cent à chaque brusque cadence,
Un souffle vers le haut, la voix se lève,
Vers le bas elle s’éteint, douce trêve,
Le clic s’efface, la musique avance.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed Le titre suit exactement la convention Conventional Commits avec le scope kebab-case « player » et décrit clairement la fonctionnalité ajoutée : le contrôle du volume via la molette.
Description check ✅ Passed La description est complète : elle explique le comportement, justifie le choix technique (addEventListener vs onWheel), détaille le plan de test avec tous les cas couverts, et confirme que lint/typecheck passent.
Linked Issues check ✅ Passed Le code implémente exactement la demande #118 : contrôle du volume à la molette avec étapes de 5 %, gestion des limites 0–100 %, et vérification que les interactions existantes restent intactes.
Out of Scope Changes check ✅ Passed Les changements sont strictement limités à VolumeControl.tsx pour ajouter le support de la molette ; aucun impact sur les dépendances, l'architecture ou les autres composants.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/volume-wheel-scroll

Comment @coderabbitai help to get the list of available commands and usage tips.

@InstaZDLL InstaZDLL added the size: s 10-50 lines label May 23, 2026
@InstaZDLL InstaZDLL self-assigned this May 23, 2026
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/components/player/VolumeControl.tsx`:
- Around line 28-33: Le gestionnaire `handler` considère `e.deltaY === 0` comme
une baisse de volume (car il utilise `e.deltaY < 0 ? WHEEL_STEP : -WHEEL_STEP`),
il faut ignorer ce cas pour éviter une baisse involontaire; modify `handler` in
`VolumeControl.tsx` to early-return when `e.deltaY === 0` (i.e., check `if
(e.deltaY === 0) return;`) before calling `preventDefault()`/`setVolume`, so
only non‑zero vertical wheel deltas change the volume via `setVolume` using
`WHEEL_STEP`.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 0c604eea-7c58-477d-ba62-c783d5549e28

📥 Commits

Reviewing files that changed from the base of the PR and between 0274cf2 and 2e653a5.

📒 Files selected for processing (1)
  • src/components/player/VolumeControl.tsx

Comment thread src/components/player/VolumeControl.tsx
…review)

`(e.deltaY < 0 ? WHEEL_STEP : -WHEEL_STEP)` treated `deltaY === 0`
as a downward tick. Trackpad horizontal swipes deliver exactly
that shape (deltaX != 0, deltaY === 0), so swiping sideways over
the volume slider silently dropped the level.

Early-return on `deltaY === 0` before `preventDefault` so
horizontal scrolls pass through to the parent and only true
vertical wheel input changes the volume.
@InstaZDLL
Copy link
Copy Markdown
Owner Author

Applied in d9fb661. Real bug — trackpad horizontal swipes (deltaX != 0, deltaY === 0) hit the else branch of (e.deltaY < 0 ? WHEEL_STEP : -WHEEL_STEP) and silently dropped the volume.

Fix: if (e.deltaY === 0) return; before preventDefault so horizontal scrolls pass through to the parent untouched and only true vertical wheel input adjusts the volume.

@InstaZDLL InstaZDLL added the scope: docs Docs, README, assets label May 23, 2026
@InstaZDLL InstaZDLL merged commit d444339 into main May 23, 2026
12 of 13 checks passed
@InstaZDLL InstaZDLL deleted the feat/volume-wheel-scroll branch May 23, 2026 18:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

scope: docs Docs, README, assets scope: frontend React/Vite frontend (src/) size: s 10-50 lines type: feat New feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: scrolling mouse wheel on top of the volume slider bar

1 participant