Function
Optionalstorage: StorageOverrides the browser's localStorage; tests inject a fake
here instead of monkey-patching the global
The step in force, in seconds, and choose to change it
How far a double tap on the video skips is a preference of the player's
chrome, not learner data. That is why it is stored here rather than behind
a domain port the way playback position, continue-watching and completion
are: no use case reasons about it, and the domain would gain an interface
nothing in the domain calls. What it does keep from those adapters is the
learning-english: key namespace and the rule that storage which is absent,
denied or corrupt degrades to the default instead of throwing.
Two consumers in one tree need the same answer — PlaybackGestures and
SeekStepMenu — and a second tab can change it underneath both. A
module-level subscriber set plus useSyncExternalStore serves all three
without a context provider: a write notifies the subscribers directly (the
storage event does not fire in the tab that wrote), and the event covers
the other tabs.
getServerSnapshot returns the default, so the server's HTML and the
hydration render agree by construction; React compares the two snapshots
once hydration commits and re-renders with the stored one itself, which is
why nothing here has to nudge it. For that one commit the step is the
default even for a learner who chose ten seconds; no gesture can land in
it, and the menu reads the same store, so it can never show a step the
gestures do not have.
Client hook: the seek step the learner chose, and the way to change it.