mirror of
https://github.com/jeffvli/feishin.git
synced 2026-05-10 04:30:25 +02:00
fix tab index on command palette play buttons
This commit is contained in:
@@ -134,6 +134,7 @@ export const CommandPalette = ({ modalProps }: CommandPaletteProps) => {
|
|||||||
const [pages, setPages] = useState<CommandPalettePages[]>([CommandPalettePages.HOME]);
|
const [pages, setPages] = useState<CommandPalettePages[]>([CommandPalettePages.HOME]);
|
||||||
const activePage = pages[pages.length - 1];
|
const activePage = pages[pages.length - 1];
|
||||||
const isHome = activePage === CommandPalettePages.HOME;
|
const isHome = activePage === CommandPalettePages.HOME;
|
||||||
|
const commandRootRef = useRef<HTMLDivElement>(null);
|
||||||
const searchInputRef = useRef<HTMLInputElement>(null);
|
const searchInputRef = useRef<HTMLInputElement>(null);
|
||||||
|
|
||||||
const popPage = useCallback(() => {
|
const popPage = useCallback(() => {
|
||||||
@@ -189,8 +190,33 @@ export const CommandPalette = ({ modalProps }: CommandPaletteProps) => {
|
|||||||
if (e.key === 'ArrowDown' || e.key === 'ArrowUp') {
|
if (e.key === 'ArrowDown' || e.key === 'ArrowUp') {
|
||||||
searchInputRef.current?.focus();
|
searchInputRef.current?.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (e.key === 'Tab' && !e.shiftKey) {
|
||||||
|
const root = commandRootRef.current;
|
||||||
|
if (!root) return;
|
||||||
|
|
||||||
|
const selectedItem = root.querySelector(
|
||||||
|
'[cmdk-item][aria-selected="true"]',
|
||||||
|
) as HTMLElement | null;
|
||||||
|
|
||||||
|
if (!selectedItem) return;
|
||||||
|
|
||||||
|
const focusTarget = selectedItem.querySelector(
|
||||||
|
'button:not([disabled]), [tabindex]:not([tabindex="-1"])',
|
||||||
|
) as HTMLElement | null;
|
||||||
|
|
||||||
|
if (!focusTarget) return;
|
||||||
|
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
focusTarget.focus();
|
||||||
|
});
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
onValueChange={setValue}
|
onValueChange={setValue}
|
||||||
|
ref={commandRootRef}
|
||||||
value={value}
|
value={value}
|
||||||
>
|
>
|
||||||
<CommandPaletteSearch
|
<CommandPaletteSearch
|
||||||
|
|||||||
@@ -32,3 +32,14 @@
|
|||||||
background: alpha(var(--theme-colors-foreground-muted), 0.3);
|
background: alpha(var(--theme-colors-foreground-muted), 0.3);
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.controls {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
svg {
|
||||||
|
width: var(--theme-font-size-sm);
|
||||||
|
height: var(--theme-font-size-sm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -16,6 +16,24 @@ import { Text } from '/@/shared/components/text/text';
|
|||||||
import { ExplicitStatus, LibraryItem, Song } from '/@/shared/types/domain-types';
|
import { ExplicitStatus, LibraryItem, Song } from '/@/shared/types/domain-types';
|
||||||
import { Play } from '/@/shared/types/types';
|
import { Play } from '/@/shared/types/types';
|
||||||
|
|
||||||
|
const createPlayKeyDownHandler = (
|
||||||
|
playType: Play,
|
||||||
|
disabled: boolean,
|
||||||
|
onPlay: (type: Play) => void,
|
||||||
|
) => {
|
||||||
|
return (e: React.KeyboardEvent) => {
|
||||||
|
if (e.key === ' ' || e.key === 'Enter') {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
if (!disabled) {
|
||||||
|
onPlay(playType);
|
||||||
|
}
|
||||||
|
} else if (e.key === 'Tab') {
|
||||||
|
e.stopPropagation();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
interface LibraryCommandItemProps {
|
interface LibraryCommandItemProps {
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
explicitStatus?: ExplicitStatus | null;
|
explicitStatus?: ExplicitStatus | null;
|
||||||
@@ -119,29 +137,47 @@ export const LibraryCommandItem = ({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{showControls && (
|
{showControls && (
|
||||||
<ActionIconGroup>
|
<ActionIconGroup className={styles.controls}>
|
||||||
<PlayTooltip disabled={disabled} type={Play.NOW}>
|
<PlayTooltip disabled={disabled} type={Play.NOW}>
|
||||||
<ActionIcon
|
<ActionIcon
|
||||||
icon="mediaPlay"
|
icon="mediaPlay"
|
||||||
variant="subtle"
|
size="xs"
|
||||||
|
variant="default"
|
||||||
{...handlePlayNow.handlers}
|
{...handlePlayNow.handlers}
|
||||||
{...handlePlayNow.props}
|
{...handlePlayNow.props}
|
||||||
|
onKeyDown={createPlayKeyDownHandler(
|
||||||
|
Play.NOW,
|
||||||
|
Boolean(disabled ?? handlePlayNow.props.disabled),
|
||||||
|
handlePlay,
|
||||||
|
)}
|
||||||
/>
|
/>
|
||||||
</PlayTooltip>
|
</PlayTooltip>
|
||||||
<PlayTooltip disabled={disabled} type={Play.NEXT}>
|
<PlayTooltip disabled={disabled} type={Play.NEXT}>
|
||||||
<ActionIcon
|
<ActionIcon
|
||||||
icon="mediaPlayNext"
|
icon="mediaPlayNext"
|
||||||
variant="subtle"
|
size="xs"
|
||||||
|
variant="default"
|
||||||
{...handlePlayNext.handlers}
|
{...handlePlayNext.handlers}
|
||||||
{...handlePlayNext.props}
|
{...handlePlayNext.props}
|
||||||
|
onKeyDown={createPlayKeyDownHandler(
|
||||||
|
Play.NEXT,
|
||||||
|
Boolean(disabled ?? handlePlayNext.props.disabled),
|
||||||
|
handlePlay,
|
||||||
|
)}
|
||||||
/>
|
/>
|
||||||
</PlayTooltip>
|
</PlayTooltip>
|
||||||
<PlayTooltip disabled={disabled} type={Play.LAST}>
|
<PlayTooltip disabled={disabled} type={Play.LAST}>
|
||||||
<ActionIcon
|
<ActionIcon
|
||||||
icon="mediaPlayLast"
|
icon="mediaPlayLast"
|
||||||
variant="subtle"
|
size="xs"
|
||||||
|
variant="default"
|
||||||
{...handlePlayLast.handlers}
|
{...handlePlayLast.handlers}
|
||||||
{...handlePlayLast.props}
|
{...handlePlayLast.props}
|
||||||
|
onKeyDown={createPlayKeyDownHandler(
|
||||||
|
Play.LAST,
|
||||||
|
Boolean(disabled ?? handlePlayLast.props.disabled),
|
||||||
|
handlePlay,
|
||||||
|
)}
|
||||||
/>
|
/>
|
||||||
</PlayTooltip>
|
</PlayTooltip>
|
||||||
</ActionIconGroup>
|
</ActionIconGroup>
|
||||||
|
|||||||
Reference in New Issue
Block a user