Skip to content

Commit

Permalink
Autofocus on search input in modals
Browse files Browse the repository at this point in the history
In MBIDMapping modal when clicking the button to copy text, otherwise it looks like there are no results as the text input needs to have focus to show the search results.

Apply same mechanism for "add listens" modal where applicable (mostly reset buttons)
  • Loading branch information
MonkeyDo committed Jul 29, 2024
1 parent 4af88c6 commit 336e68e
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 7 deletions.
5 changes: 5 additions & 0 deletions frontend/js/src/common/listens/MBIDMappingModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ export default NiceModal.create(({ listenToMap }: MBIDMappingModalProps) => {
TrackMetadata
>();

const searchInputRef = React.useRef<HTMLInputElement>(null);

const closeModal = React.useCallback(() => {
modal.hide();
document?.body?.classList?.remove("modal-open");
Expand Down Expand Up @@ -141,6 +143,8 @@ export default NiceModal.create(({ listenToMap }: MBIDMappingModalProps) => {
setDefaultValue(
`${getTrackName(listenToMap)} - ${getArtistName(listenToMap)}`
);
// Autofocus on the search input in order to automatically show list of results
searchInputRef?.current?.focus();
}, [listenToMap]);

const listenFromSelectedRecording = getListenFromSelectedRecording(
Expand Down Expand Up @@ -270,6 +274,7 @@ export default NiceModal.create(({ listenToMap }: MBIDMappingModalProps) => {
) : (
<div className="card listen-card">
<SearchTrackOrMBID
ref={searchInputRef}
expectedPayload="trackmetadata"
key={`${defaultValue}-${copyTextClickCounter}`}
onSelectRecording={(trackMetadata) => {
Expand Down
6 changes: 5 additions & 1 deletion frontend/js/src/user/components/AddSingleListen.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useEffect, useState } from "react";
import React, { useEffect, useRef, useState } from "react";
import {
faChevronDown,
faTimesCircle,
Expand Down Expand Up @@ -26,6 +26,8 @@ export default function AddSingleListen({
| undefined;
}>({});

const searchInputRef = useRef<HTMLInputElement>(null);

const removeRecording = (recordingMBID: string) => {
setSelectedRecordings((prevRecordings) =>
prevRecordings.filter((rec) => rec.id !== recordingMBID)
Expand Down Expand Up @@ -72,6 +74,7 @@ export default function AddSingleListen({
return (
<div>
<SearchTrackOrMBID
ref={searchInputRef}
expectedPayload="recording"
onSelectRecording={selectRecording}
/>
Expand Down Expand Up @@ -101,6 +104,7 @@ export default function AddSingleListen({
iconSize="lg"
action={() => {
removeRecording(recording.id);
searchInputRef?.current?.focus();
}}
/>
}
Expand Down
3 changes: 3 additions & 0 deletions frontend/js/src/utils/SearchAlbumOrMBID.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export default function SearchAlbumOrMBID({
const { APIService } = useContext(GlobalAppContext);
const { lookupMBReleaseGroup, searchMBRelease } = APIService;
const dropdownRef = DropdownRef();
const searchInputRef = useRef<HTMLInputElement>(null);
const [inputValue, setInputValue] = useState(defaultValue ?? "");
const [searchResults, setSearchResults] = useState<
Array<MusicBrainzRelease & Partial<WithMedia> & WithArtistCredits>
Expand Down Expand Up @@ -122,6 +123,7 @@ export default function SearchAlbumOrMBID({
setInputValue("");
setSearchResults([]);
onSelectAlbum();
searchInputRef?.current?.focus();
};

useEffect(() => {
Expand All @@ -143,6 +145,7 @@ export default function SearchAlbumOrMBID({
<div>
<div className="input-group dropdown-search" ref={dropdownRef}>
<input
ref={searchInputRef}
type="search"
value={inputValue}
className="form-control"
Expand Down
36 changes: 30 additions & 6 deletions frontend/js/src/utils/SearchTrackOrMBID.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ import { faTimesCircle } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { throttle } from "lodash";
import React, {
forwardRef,
useCallback,
useContext,
useEffect,
useImperativeHandle,
useMemo,
useRef,
useState,
Expand Down Expand Up @@ -37,11 +39,10 @@ type SearchTrackOrMBIDProps = {
expectedPayload: PayloadType;
} & ConditionalReturnValue;

export default function SearchTrackOrMBID({
onSelectRecording,
expectedPayload,
defaultValue,
}: SearchTrackOrMBIDProps) {
const SearchTrackOrMBID = forwardRef(function SearchTrackOrMBID(
{ onSelectRecording, expectedPayload, defaultValue }: SearchTrackOrMBIDProps,
inputRefForParent
) {
const { APIService } = useContext(GlobalAppContext);
const { lookupMBRecording } = APIService;
const dropdownRef = DropdownRef();
Expand All @@ -50,6 +51,25 @@ export default function SearchTrackOrMBID({
[]
);
const [selectedIndex, setSelectedIndex] = useState(-1);
const inputRefLocal = useRef<HTMLInputElement>(null);

// Allow parents to focus on input
useImperativeHandle(
inputRefForParent,
() => {
return {
focus() {
inputRefLocal?.current?.focus();
},
};
},
[]
);

// Autofocus once on load
useEffect(() => {
inputRefLocal?.current?.focus();
}, []);

const handleError = useCallback(
(error: string | Error, title?: string): void => {
Expand Down Expand Up @@ -180,6 +200,7 @@ export default function SearchTrackOrMBID({
setInputValue("");
setSearchResults([]);
setSelectedIndex(-1);
inputRefLocal?.current?.focus();
};

useEffect(() => {
Expand All @@ -199,6 +220,7 @@ export default function SearchTrackOrMBID({
<div>
<div className="input-group dropdown-search" ref={dropdownRef}>
<input
ref={inputRefLocal}
type="search"
value={inputValue}
className="form-control"
Expand Down Expand Up @@ -261,4 +283,6 @@ export default function SearchTrackOrMBID({
</div>
</div>
);
}
});

export default SearchTrackOrMBID;

0 comments on commit 336e68e

Please sign in to comment.