diff --git a/src/ItemList.js b/src/ItemList.js
index 1a9d451..d38bf8b 100644
--- a/src/ItemList.js
+++ b/src/ItemList.js
@@ -1,12 +1,10 @@
import React from "react";
import { css } from "emotion";
-import { CSSTransition, TransitionGroup } from "react-transition-group";
import {
Box,
Flex,
IconButton,
Image,
- PseudoBox,
Skeleton,
Tooltip,
useTheme,
@@ -14,33 +12,6 @@ import {
import "./ItemList.css";
-function ItemList({ items, outfitState, dispatchToOutfit }) {
- return (
-
-
- {items.map((item) => (
- {
- e.style.height = e.offsetHeight + "px";
- }}
- >
-
-
-
-
- ))}
-
-
- );
-}
-
export function ItemListContainer({ children }) {
return {children};
}
@@ -55,7 +26,7 @@ export function ItemListSkeleton({ count }) {
);
}
-export function Item({ item, outfitState, dispatchToOutfit }) {
+export function Item({ item, itemNameId, outfitState, dispatchToOutfit }) {
const { allItemIds } = outfitState;
const isInOutfit = allItemIds.includes(item.id);
const theme = useTheme();
@@ -64,7 +35,7 @@ export function Item({ item, outfitState, dispatchToOutfit }) {
- {item.name}
+ {item.name}
{isInOutfit && (
@@ -175,7 +146,7 @@ function ItemThumbnail({ src }) {
);
}
-function ItemName({ children }) {
+function ItemName({ children, ...props }) {
const theme = useTheme();
return (
@@ -194,10 +165,9 @@ function ItemName({ children }) {
font-weight: ${theme.fontWeights.bold};
}
`}
+ {...props}
>
{children}
);
}
-
-export default ItemList;
diff --git a/src/ItemsPanel.js b/src/ItemsPanel.js
index 178c02e..5541e81 100644
--- a/src/ItemsPanel.js
+++ b/src/ItemsPanel.js
@@ -21,7 +21,7 @@ function ItemsPanel({ outfitState, loading, dispatchToOutfit }) {
const { zonesAndItems } = outfitState;
return (
-
+
diff --git a/src/SearchPanel.js b/src/SearchPanel.js
index 1381d4d..9ef441a 100644
--- a/src/SearchPanel.js
+++ b/src/SearchPanel.js
@@ -1,17 +1,18 @@
import React from "react";
import gql from "graphql-tag";
-import { Box, Text } from "@chakra-ui/core";
+import { Box, Text, VisuallyHidden } from "@chakra-ui/core";
import { useQuery } from "@apollo/react-hooks";
import { Delay, Heading1, useDebounce } from "./util";
-import ItemList, { ItemListSkeleton } from "./ItemList";
+import { ItemListContainer, ItemListSkeleton, Item } from "./ItemList";
import { itemAppearanceFragment } from "./OutfitPreview";
function SearchPanel({
query,
outfitState,
dispatchToOutfit,
- getScrollParent,
+ firstSearchResultRef,
+ onMoveFocusUpToQuery,
}) {
return (
@@ -20,13 +21,20 @@ function SearchPanel({
query={query}
outfitState={outfitState}
dispatchToOutfit={dispatchToOutfit}
- getScrollParent={getScrollParent}
+ firstSearchResultRef={firstSearchResultRef}
+ onMoveFocusUpToQuery={onMoveFocusUpToQuery}
/>
);
}
-function SearchResults({ query, outfitState, dispatchToOutfit }) {
+function SearchResults({
+ query,
+ outfitState,
+ dispatchToOutfit,
+ firstSearchResultRef,
+ onMoveFocusUpToQuery,
+}) {
const { speciesId, colorId } = outfitState;
const debouncedQuery = useDebounce(query, 300, { waitForFirstPause: true });
@@ -159,19 +167,74 @@ function SearchResults({ query, outfitState, dispatchToOutfit }) {
);
}
+ const onChange = (e) => {
+ const itemId = e.target.value;
+ const willBeWorn = e.target.checked;
+ if (willBeWorn) {
+ dispatchToOutfit({ type: "wearItem", itemId });
+ } else {
+ dispatchToOutfit({ type: "unwearItem", itemId });
+ }
+ };
+
+ const goToPrevItem = (e) => {
+ const prevLabel = e.target.closest("label").previousSibling;
+ if (prevLabel) {
+ prevLabel.querySelector("input[type=checkbox]").focus();
+ e.preventDefault();
+ } else {
+ // If we're at the top of the list, move back up to the search box!
+ onMoveFocusUpToQuery(e);
+ }
+ };
+
+ const goToNextItem = (e) => {
+ const nextLabel = e.target.closest("label").nextSibling;
+ if (nextLabel) {
+ nextLabel.querySelector("input[type=checkbox]").focus();
+ e.preventDefault();
+ }
+ };
+
+ console.log(firstSearchResultRef);
return (
-
+
+ {items.map((item, index) => (
+
+ ))}
+
{items && loading && }
);
}
-function ScrollTracker({ children, query, threshold, onScrolledToBottom }) {
+function ScrollTracker({ children, threshold, onScrolledToBottom }) {
const containerRef = React.useRef();
const scrollParent = React.useRef();
@@ -209,7 +272,7 @@ function ScrollTracker({ children, query, threshold, onScrolledToBottom }) {
};
}, [onScroll]);
- return {children};
+ return {children}
;
}
export default SearchPanel;
diff --git a/src/WardrobePage.js b/src/WardrobePage.js
index fbae50d..d9ae9e3 100644
--- a/src/WardrobePage.js
+++ b/src/WardrobePage.js
@@ -21,6 +21,8 @@ function WardrobePage() {
const [searchQuery, setSearchQuery] = React.useState("");
const toast = useToast();
const searchContainerRef = React.useRef();
+ const searchQueryRef = React.useRef();
+ const firstSearchResultRef = React.useRef();
React.useEffect(() => {
if (error) {
@@ -72,13 +74,24 @@ function WardrobePage() {
-
+ {
+ if (firstSearchResultRef.current) {
+ firstSearchResultRef.current.focus();
+ e.preventDefault();
+ }
+ }}
+ />
{searchQuery ? (
{
+ if (searchQueryRef.current) {
+ searchQueryRef.current.focus();
+ e.preventDefault();
+ }
+ }}
/>
) : (
-
+
@@ -118,11 +148,14 @@ function SearchToolbar({ query, onChange }) {
focusBorderColor="green.600"
color="green.800"
value={query}
+ ref={queryRef}
onChange={(e) => onChange(e.target.value)}
onKeyDown={(e) => {
if (e.key === "Escape") {
onChange("");
e.target.blur();
+ } else if (e.key === "ArrowDown") {
+ onMoveFocusDownToResults(e);
}
}}
/>