diff --git a/package.json b/package.json
index 6a3d290..80d6ba5 100644
--- a/package.json
+++ b/package.json
@@ -16,6 +16,7 @@
"apollo-server-core": "^2.12.0",
"apollo-server-env": "^2.4.3",
"dataloader": "^2.0.0",
+ "emotion": "^10.0.27",
"emotion-theming": "^10.0.27",
"graphql": "^15.0.0",
"immer": "^6.0.3",
diff --git a/src/ItemList.js b/src/ItemList.js
index aec43f8..3d7af94 100644
--- a/src/ItemList.js
+++ b/src/ItemList.js
@@ -1,4 +1,5 @@
import React from "react";
+import { css } from "emotion";
import { CSSTransition, TransitionGroup } from "react-transition-group";
import {
Box,
@@ -8,6 +9,7 @@ import {
PseudoBox,
Skeleton,
Tooltip,
+ useTheme,
} from "@chakra-ui/core";
import "./ItemList.css";
@@ -39,7 +41,11 @@ function ItemList({ items, outfitState, dispatchToOutfit }) {
);
}
-function ItemListSkeleton({ count }) {
+export function ItemListContainer({ children }) {
+ return {children};
+}
+
+export function ItemListSkeleton({ count }) {
return (
{Array.from({ length: count }).map((_, i) => (
@@ -51,28 +57,39 @@ function ItemListSkeleton({ count }) {
);
}
-function Item({ item, outfitState, dispatchToOutfit }) {
- const { wornItemIds, allItemIds } = outfitState;
-
- const isWorn = wornItemIds.includes(item.id);
+export function Item({ item, outfitState, dispatchToOutfit }) {
+ const { allItemIds } = outfitState;
const isInOutfit = allItemIds.includes(item.id);
+ const theme = useTheme();
return (
-
- dispatchToOutfit({
- type: isWorn ? "unwearItem" : "wearItem",
- itemId: item.id,
- })
+ border="1px"
+ borderColor="transparent"
+ className={
+ "item-container " +
+ css`
+ input:active + & {
+ border-color: ${theme.colors.green["800"]};
+ }
+ input:focus + & {
+ border-style: dotted;
+ border-color: ${theme.colors.gray["400"]};
+ }
+ `
}
>
-
+
- {item.name}
+ {item.name}
{isInOutfit && (
@@ -105,7 +122,7 @@ function Item({ item, outfitState, dispatchToOutfit }) {
/>
)}
-
+
);
}
@@ -119,53 +136,61 @@ function ItemSkeleton() {
);
}
-function ItemThumbnail({ src, isWorn }) {
+function ItemThumbnail({ src }) {
+ const theme = useTheme();
return (
-
-
+
);
}
-function ItemName({ children, isWorn }) {
+function ItemName({ children }) {
+ const theme = useTheme();
+
return (
-
{children}
-
+
);
}
export default ItemList;
-export { ItemListSkeleton };
diff --git a/src/ItemsPanel.js b/src/ItemsPanel.js
index 88c1213..99c1dde 100644
--- a/src/ItemsPanel.js
+++ b/src/ItemsPanel.js
@@ -8,11 +8,12 @@ import {
IconButton,
PseudoBox,
Skeleton,
+ VisuallyHidden,
} from "@chakra-ui/core";
import { CSSTransition, TransitionGroup } from "react-transition-group";
import { Delay, Heading1, Heading2 } from "./util";
-import ItemList, { ItemListSkeleton } from "./ItemList";
+import { ItemListContainer, Item, ItemListSkeleton } from "./ItemList";
import "./ItemsPanel.css";
@@ -48,7 +49,8 @@ function ItemsPanel({ outfitState, loading, dispatchToOutfit }) {
>
{zoneLabel}
- {
+ const itemId = e.target.value;
+ dispatchToOutfit({ type: "wearItem", itemId });
+ };
+
+ const onToggle = (e) => {
+ // Clicking the radio button when already selected deselects it - this is
+ // how you can select none!
+ const itemId = e.target.value;
+ if (outfitState.wornItemIds.includes(itemId)) {
+ // We need the event handler to finish before this, so that simulated
+ // events don't just come back around and undo it - but we can't just
+ // solve that with `preventDefault`, because it breaks the radio's
+ // intended visual updates when we unwear. So, we `setTimeout` to do it
+ // after all event handlers resolve!
+ setTimeout(() => dispatchToOutfit({ type: "unwearItem", itemId }), 0);
+ }
+ };
+
+ return (
+
+
+ {items.map((item) => (
+ {
+ e.style.height = e.offsetHeight + "px";
+ }}
+ >
+
+
+ ))}
+
+
+ );
+}
+
function OutfitHeading({ outfitState, dispatchToOutfit }) {
return (
diff --git a/yarn.lock b/yarn.lock
index 78b0f1f..e0c7e9a 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3974,6 +3974,16 @@ create-ecdh@^4.0.0:
bn.js "^4.1.0"
elliptic "^6.0.0"
+create-emotion@^10.0.27:
+ version "10.0.27"
+ resolved "https://registry.yarnpkg.com/create-emotion/-/create-emotion-10.0.27.tgz#cb4fa2db750f6ca6f9a001a33fbf1f6c46789503"
+ integrity sha512-fIK73w82HPPn/RsAij7+Zt8eCE8SptcJ3WoRMfxMtjteYxud8GDTKKld7MYwAX2TVhrw29uR1N/bVGxeStHILg==
+ dependencies:
+ "@emotion/cache" "^10.0.27"
+ "@emotion/serialize" "^0.11.15"
+ "@emotion/sheet" "0.9.4"
+ "@emotion/utils" "0.11.3"
+
create-hash@^1.1.0, create-hash@^1.1.2:
version "1.2.0"
resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196"
@@ -4684,6 +4694,14 @@ emotion-theming@^10.0.27:
"@emotion/weak-memoize" "0.2.5"
hoist-non-react-statics "^3.3.0"
+emotion@^10.0.27:
+ version "10.0.27"
+ resolved "https://registry.yarnpkg.com/emotion/-/emotion-10.0.27.tgz#f9ca5df98630980a23c819a56262560562e5d75e"
+ integrity sha512-2xdDzdWWzue8R8lu4G76uWX5WhyQuzATon9LmNeCy/2BHVC6dsEpfhN1a0qhELgtDVdjyEA6J8Y/VlI5ZnaH0g==
+ dependencies:
+ babel-plugin-emotion "^10.0.27"
+ create-emotion "^10.0.27"
+
encodeurl@~1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"