diff --git a/src/components/AddToPlaylistSheet.jsx b/src/components/AddToPlaylistSheet.jsx index 5059de2..97867df 100644 --- a/src/components/AddToPlaylistSheet.jsx +++ b/src/components/AddToPlaylistSheet.jsx @@ -5,6 +5,7 @@ import { usePlayer } from '../state/PlayerProvider' import { addToPlaylist, createPlaylist, toggleStar, deleteTrack } from '../lib/db' import PromptModal from './PromptModal' import ConfirmModal from './ConfirmModal' +import { useDialog } from '../lib/useDialog' // Track actions sheet (opened from a TrackRow's ⋯). Quick playback actions on // top (Play next / Add to queue / Favorite), then the "add to playlist" picker. @@ -14,6 +15,9 @@ export default function AddToPlaylistSheet() { const { playNext, addToQueue } = usePlayer() const [creating, setCreating] = useState(false) const [confirmDelete, setConfirmDelete] = useState(false) + // This host is always mounted (returns null when closed), so key the focus on + // whether a track is open, not on mount. + const dialog = useDialog(closeAddToPlaylist, { active: !!addTarget }) if (!addTarget) return null const close = closeAddToPlaylist @@ -25,7 +29,15 @@ export default function AddToPlaylistSheet() { return ( <>
{addTarget.title}
diff --git a/src/components/ConfirmModal.jsx b/src/components/ConfirmModal.jsx index e411d73..cb0e67d 100644 --- a/src/components/ConfirmModal.jsx +++ b/src/components/ConfirmModal.jsx @@ -1,4 +1,4 @@ -import { useEffect } from 'react' +import { useDialog } from '../lib/useDialog' // Destructive confirm dialog (e.g. delete a playlist) — replaces window.confirm. export default function ConfirmModal({ @@ -8,15 +8,19 @@ export default function ConfirmModal({ onConfirm, onClose, }) { - useEffect(() => { - const onKey = (e) => e.key === 'Escape' && onClose() - window.addEventListener('keydown', onKey) - return () => window.removeEventListener('keydown', onKey) - }, [onClose]) + const dialog = useDialog(onClose) return ({message}
}{playlist.name}
diff --git a/src/components/PromptModal.jsx b/src/components/PromptModal.jsx index ff9d878..2dacf85 100644 --- a/src/components/PromptModal.jsx +++ b/src/components/PromptModal.jsx @@ -1,4 +1,5 @@ import { useState, useEffect, useRef } from 'react' +import { useDialog } from '../lib/useDialog' // A small centered text-entry modal — replaces window.prompt() so naming a // playlist feels native and on-brand instead of a browser system dialog. @@ -13,14 +14,13 @@ export default function PromptModal({ }) { const [value, setValue] = useState(initialValue) const inputRef = useRef(null) + // autoFocus:false — we focus the text input, not the form container. + const dialog = useDialog(onClose, { autoFocus: false }) useEffect(() => { inputRef.current?.focus() inputRef.current?.select() - const onKey = (e) => e.key === 'Escape' && onClose() - window.addEventListener('keydown', onKey) - return () => window.removeEventListener('keydown', onKey) - }, [onClose]) + }, []) const submit = (e) => { e.preventDefault() @@ -30,7 +30,15 @@ export default function PromptModal({ return (