theme overlay is one plain rotation, favourites in place, tab toggles a favourites filter
This commit is contained in:
@@ -36,12 +36,11 @@ import type { ThemeId } from './themes';
|
||||
* The starting theme is captured when the list opens, so `h` and `Escape` can undo an entire browse
|
||||
* regardless of how many previews happened in between.
|
||||
*
|
||||
* Browsing walks `browseOrder` — the list as DISPLAYED — not the registry. The overlay pins favourites
|
||||
* in a block at the top, and stepping in registry order through a display ordered differently meant the
|
||||
* focus hopped up into that block and back out whenever a registry-neighbour happened to be starred.
|
||||
* The favourites block is a shortlist, deliberately outside the rotation; the global cycle
|
||||
* (`ctrl+shift+←/→`) still covers every theme, because with no list on screen there is no order to
|
||||
* disagree with.
|
||||
* Browsing walks `browseOrder` — the list as DISPLAYED — not the registry. The two orders must be the
|
||||
* same list or the focus visibly jumps, which is exactly what happened when the overlay lifted
|
||||
* favourites to a top block while stepping walked registry order. The overlay now shows one plain
|
||||
* rotation and `tab` flips a favourites-only filter (`onToggleFilter`); either way, what you see is
|
||||
* what `j`/`k` walk.
|
||||
*
|
||||
* ── Not a UI ──
|
||||
*
|
||||
@@ -61,6 +60,8 @@ type ThemeKeysOptions = {
|
||||
* browse falls back to the full registry rotation.
|
||||
*/
|
||||
browseOrder?: readonly ThemeId[];
|
||||
/** Flip the favourites-only filter — bound to `tab` while the list is open. App state, like the stars. */
|
||||
onToggleFilter?: () => void;
|
||||
};
|
||||
|
||||
export function useThemeKeys(options: ThemeKeysOptions = {}) {
|
||||
@@ -71,6 +72,8 @@ export function useThemeKeys(options: ThemeKeysOptions = {}) {
|
||||
onToggleFavorite.current = options.onToggleFavorite;
|
||||
const browseOrder = useRef(options.browseOrder);
|
||||
browseOrder.current = options.browseOrder;
|
||||
const onToggleFilter = useRef(options.onToggleFilter);
|
||||
onToggleFilter.current = options.onToggleFilter;
|
||||
const [open, setOpen] = useState(false);
|
||||
const [focused, setFocused] = useState<ThemeId>(themeId);
|
||||
const startedOn = useRef<ThemeId>(themeId);
|
||||
@@ -188,6 +191,12 @@ export function useThemeKeys(options: ThemeKeysOptions = {}) {
|
||||
event.preventDefault();
|
||||
onToggleFavorite.current?.(focus);
|
||||
return;
|
||||
case 'Tab':
|
||||
// Favourites only ↔ everything. preventDefault or the browser also moves focus, and the
|
||||
// overlay has nothing focusable to move it to.
|
||||
event.preventDefault();
|
||||
onToggleFilter.current?.();
|
||||
return;
|
||||
case 'j':
|
||||
case 'J':
|
||||
case 'ArrowDown':
|
||||
|
||||
Reference in New Issue
Block a user