switch from react-spectrum to react-aria custom components

This commit is contained in:
2022-11-17 20:50:54 -08:00
parent d28ee00866
commit a9dd2e25d5
79 changed files with 386 additions and 1313 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+23 -18
View File
@@ -1,7 +1,12 @@
import * as React from "react";
import { lightTheme, Provider, SSRProvider } from "@adobe/react-spectrum";
// import * as React from "react";
import "./src/styles/global.css";
declare global {
interface Window {
plausible: any;
}
}
const env =
process.env.GATSBY_ACTIVE_ENV || process.env.NODE_ENV || "development";
export const onRouteUpdate = function () {
@@ -22,21 +27,21 @@ export const onRouteUpdate = function () {
// p: MyParagraph,
// };
export const wrapRootElement = ({ element }) => (
<SSRProvider>
<Provider
UNSAFE_className="overflow-x-hidden"
UNSAFE_style={{
background: "unset",
color: "unset",
}}
colorScheme="light"
// scale="medium"
theme={lightTheme}
>
{element}
</Provider>
</SSRProvider>
);
// export const wrapRootElement = ({ element }) => (
// <SSRProvider>
// <Provider
// UNSAFE_className="overflow-x-hidden"
// UNSAFE_style={{
// background: "unset",
// color: "unset",
// }}
// colorScheme="light"
// // scale="medium"
// theme={{light: {}, ...lightTheme}}
// >
// {element}
// </Provider>
// </SSRProvider>
// );
// {/* // <MDXProvider components={components}>{element}</MDXProvider> */}
+4 -4
View File
@@ -1,11 +1,11 @@
import * as React from "react";
import { lightTheme, Provider } from "@adobe/react-spectrum";
// import { lightTheme, Provider } from "@adobe/react-spectrum";
import "./src/styles/global.css";
import { SSRProvider } from "@react-aria/ssr";
export const wrapRootElement = ({ element }) => (
<SSRProvider>
<Provider
{/* <Provider
UNSAFE_style={{
background: "unset",
color: "unset",
@@ -14,8 +14,8 @@ export const wrapRootElement = ({ element }) => (
colorScheme="light"
// scale="medium"
theme={lightTheme}
>
> */}
{element}
</Provider>
{/* </Provider> */}
</SSRProvider>
);
+4 -2
View File
@@ -22,8 +22,8 @@
"pretty": "prettier --write ."
},
"dependencies": {
"@adobe/react-spectrum": "^3.19.0",
"@spectrum-icons/workflow": "^4.0.0",
"@react-spectrum/provider": "^3.6.0",
"@spectrum-icons/workflow": "^4.0.4",
"autoprefixer": "^10.2.6",
"chalk": "^4.1.1",
"chroma-js": "^2.1.2",
@@ -47,10 +47,12 @@
"postcss-nested": "^6.0.0",
"ramda": "^0.27.1",
"react": "^18.2.0",
"react-aria": "^3.21.0",
"react-cool-dimensions": "^2.0.7",
"react-div-100vh": "^0.7.0",
"react-dom": "^18.2.0",
"react-helmet": "^6.1.0",
"react-stately": "^3.19.0",
"react-tiny-popover": "^7.2.0",
"sass": "^1.34.0",
"tailwindcss": "^3.2.4",
+12 -7
View File
@@ -39,6 +39,11 @@ const logKeyShortcut = (keyCode) => {
}
};
const IconStyle = {
width: '24px',
margin: '0 4px'
}
const ArrowLinkClasses = `hover:underline text-vibrant-light hover:text-muted-light
lg:px-4 self-stretch flex items-center hover:bg-black/50 max-h-screen sticky top-0
`;
@@ -260,37 +265,37 @@ const GalleryImage = ({ data, location: { state } }) => {
<div className="flex flex-col items-end">
<MetadataItem
data={dateTaken.toLocaleDateString()}
icon={<Calendar />}
icon={<Calendar UNSAFE_style={IconStyle} />}
title="date taken"
/>
<div className="sm:flex justify-end gap-2 border border-vibrant-light pl-2 rounded">
<MetadataItem
data={shutterSpeed}
icon={<Stopwatch />}
icon={<Stopwatch UNSAFE_style={IconStyle} />}
title="shutter speed"
/>
{meta.FNumber && (
<MetadataItem
data={`f/${meta.FNumber}`}
icon={<Exposure />}
icon={<Exposure UNSAFE_style={IconStyle} />}
title="aperture"
/>
)}
<MetadataItem
data={meta.ISO}
icon={<Filmroll />}
icon={<Filmroll UNSAFE_style={IconStyle} />}
title="ISO"
/>
</div>
<MetadataItem
data={locationString}
icon={<Location />}
icon={<Location UNSAFE_style={IconStyle} />}
title="location"
/>
{(meta.Make || meta.Model) && (
<MetadataItem
data={[meta.Make, meta.Model].join(" ")}
icon={<Camera />}
icon={<Camera UNSAFE_style={IconStyle} />}
title="camera"
/>
)}
@@ -302,7 +307,7 @@ const GalleryImage = ({ data, location: { state } }) => {
]
.filter(Boolean)
.join(" @")}
icon={<Circle />}
icon={<Circle UNSAFE_style={IconStyle} />}
title="lens"
/>
)}
+14 -9
View File
@@ -1,5 +1,6 @@
import * as React from "react";
import classNames from "classnames";
import Checkmark from "@spectrum-icons/workflow/Checkmark";
interface KeywordsPickerProps {
keywords: string[];
@@ -9,7 +10,7 @@ interface KeywordsPickerProps {
const KeywordsPicker = ({ keywords, value, onChange }: KeywordsPickerProps) => {
return (
<div className="mx-2 mt-2">
<span className="text-xs text-[var(--spectrum-fieldlabel-text-color,var(--spectrum-alias-label-text-color))]">
<span className="text-xs text-black">
Collections
</span>
<ul className="flex gap-1 flex-wrap mt-1 mb-2">
@@ -19,20 +20,24 @@ const KeywordsPicker = ({ keywords, value, onChange }: KeywordsPickerProps) => {
<li key={keyword}>
<button
className={classNames(
"transition",
`py-[5px] px-3 rounded-full`,
`text-[var(--spectrum-fieldbutton-text-color,var(--spectrum-alias-text-color))]
border border-[var(--spectrum-fieldbutton-border-color,var(--spectrum-alias-border-color))]`,
`text-black border border-black`,
selected
? "bg-green-500 hover:bg-green-300"
: `bg-[var(--spectrum-fieldbutton-background-color,var(--spectrum-global-color-gray-75))]
hover:bg-[var(--spectrum-fieldbutton-background-color-down,var(--spectrum-global-color-gray-200))]`
? "bg-transparentblack font-bold"
: `bg-white
hover:bg-transparentblack`
)}
onClick={() => (selected ? onChange(null) : onChange(keyword))}
type="button"
>
{keyword}
{keyword}{" "}
{selected && (
<Checkmark
UNSAFE_className="mx-1"
UNSAFE_style={{ width: "15px" }}
aria-hidden="true"
/>
)}
</button>
</li>
);
+105
View File
@@ -0,0 +1,105 @@
/* eslint-disable @typescript-eslint/no-use-before-define */
import * as React from "react";
import type { AriaListBoxOptions } from "@react-aria/listbox";
import type { ListState } from "react-stately";
import type { Node } from "@react-types/shared";
import { useListBox, useListBoxSection, useOption } from "react-aria";
// import { CheckIcon } from "@heroicons/react/solid";
import Checkmark from '@spectrum-icons/workflow/Checkmark'
interface ListBoxProps extends AriaListBoxOptions<unknown> {
listBoxRef?: React.RefObject<HTMLUListElement>;
state: ListState<unknown>;
}
interface SectionProps {
section: Node<unknown>;
state: ListState<unknown>;
}
interface OptionProps {
item: Node<unknown>;
state: ListState<unknown>;
}
export function ListBox(props: ListBoxProps) {
let ref = React.useRef<HTMLUListElement>(null);
let { listBoxRef = ref, state } = props;
let { listBoxProps } = useListBox(props, state, listBoxRef);
return (
<ul
{...listBoxProps}
className="w-full max-h-72 overflow-auto outline-none"
ref={listBoxRef}
>
{[...state.collection].map((item) =>
item.type === "section" ? (
<ListBoxSection key={item.key} section={item} state={state} />
) : (
<Option item={item} key={item.key} state={state} />
)
)}
</ul>
);
}
function ListBoxSection({ section, state }: SectionProps) {
let { itemProps, headingProps, groupProps } = useListBoxSection({
heading: section.rendered,
"aria-label": section["aria-label"]
});
return (
<>
<li {...itemProps} className="pt-2">
{section.rendered && (
<span
{...headingProps}
className="text-xs font-bold uppercase text-gray-500 mx-3"
>
{section.rendered}
</span>
)}
<ul {...groupProps}>
{[...section.childNodes].map((node) => (
<Option item={node} key={node.key} state={state} />
))}
</ul>
</li>
</>
);
}
function Option({ item, state }: OptionProps) {
let ref = React.useRef<HTMLLIElement>(null);
let { optionProps, isDisabled, isSelected, isFocused } = useOption(
{
key: item.key
},
state,
ref
);
let text = "text-black";
if (isFocused || isSelected) {
text = "text-black";
} else if (isDisabled) {
text = "text-gray-200";
}
return (
<li
{...optionProps}
className={`p-3 outline-none cursor-default flex items-center justify-between ${text} ${
isFocused ? "bg-transparentblack" : ""
} ${isSelected ? "font-bold" : ""}`}
ref={ref}
>
{item.rendered}
{isSelected && (
<Checkmark UNSAFE_className="mx-1" UNSAFE_style={{ width: '15px' }} aria-hidden="true" />
)}
</li>
);
}
+2 -2
View File
@@ -138,7 +138,7 @@ const MasonryGallery = ({
return (
<Link
className={classNames(
"border-4 overflow-hidden",
"border-4 border-white overflow-hidden",
debugHue && "border-8"
)}
id={image.base}
@@ -159,7 +159,7 @@ const MasonryGallery = ({
${image.fields?.imageMeta?.dominantHue?.[1] ?? 0 * 100}%,
${image.fields?.imageMeta?.dominantHue?.[2] ?? 0 * 100}%
)`
: "white",
: "",
}}
to={`/photogallery/${image.base}`}
>
+39
View File
@@ -0,0 +1,39 @@
import type { OverlayTriggerState } from "react-stately";
import type { AriaPopoverProps } from "@react-aria/overlays";
import * as React from "react";
import { usePopover, DismissButton, Overlay } from "@react-aria/overlays";
interface PopoverProps extends Omit<AriaPopoverProps, "popoverRef"> {
children: React.ReactNode;
state: OverlayTriggerState;
className?: string;
popoverRef?: React.RefObject<HTMLDivElement>;
}
export function Popover(props: PopoverProps) {
let ref = React.useRef<HTMLDivElement>(null);
let { popoverRef = ref, state, children, className, isNonModal } = props;
let { popoverProps, underlayProps } = usePopover(
{
...props,
popoverRef
},
state
);
return (
<Overlay>
{!isNonModal && <div {...underlayProps} className="fixed inset-0" />}
<div
{...popoverProps}
className={`z-10 shadow border border-black bg-white rounded mt-1 ${className}`}
ref={popoverRef}
>
{!isNonModal && <DismissButton onDismiss={state.close} />}
{children}
<DismissButton onDismiss={state.close} />
</div>
</Overlay>
);
}
+89
View File
@@ -0,0 +1,89 @@
import * as React from "react";
import type { AriaSelectProps } from "@react-types/select";
import { useSelectState } from "react-stately";
import {
useSelect,
HiddenSelect,
useButton,
mergeProps,
useFocusRing
} from "react-aria";
// import { SelectorIcon } from "@heroicons/react/solid";
import ChevronDown from "@spectrum-icons/workflow/ChevronDown";
import { ListBox } from "./ListBox";
import { Popover } from "./Popover";
export { Item } from "react-stately";
export function Select<T extends object>(props: AriaSelectProps<T>) {
// Create state based on the incoming props
let state = useSelectState(props);
// Get props for child elements from useSelect
let ref = React.useRef(null);
let { labelProps, triggerProps, valueProps, menuProps } = useSelect(
props,
state,
ref
);
// Get props for the button based on the trigger props from useSelect
let { buttonProps } = useButton(triggerProps, ref);
let { focusProps, isFocusVisible } = useFocusRing();
return (
<div className="inline-flex flex-col relative">
<div
{...labelProps}
className="block text-sm text-left cursor-default mb-1"
>
{props.label}
</div>
<HiddenSelect
label={props.label}
name={props.name}
state={state}
triggerRef={ref}
/>
<button
{...mergeProps(buttonProps, focusProps)}
className={`py-[5px] px-3 w-[150px] flex flex-row items-center justify-between overflow-hidden cursor-default rounded border ${
isFocusVisible ? "border-green-500" : "border-black"
} ${state.isOpen ? "bg-gray-100" : "bg-white"}`}
ref={ref}
>
<span
{...valueProps}
// className={`text-md flex-auto ${
// state.selectedItem ? "text-gray-800" : "text-gray-500"
// }`}
>
{state.selectedItem
? state.selectedItem.rendered
: "Select an option"}
</span>
<ChevronDown
UNSAFE_className="mx-1"
UNSAFE_style={{
width: '15px'
}}
// UNSAFE_className={`w-[20px] h-5 ${
// isFocusVisible ? "text-pink-500" : "text-gray-500"
// }`}
/>
</button>
{state.isOpen && (
<Popover
className="w-[150px]"
placement="bottom start"
state={state}
triggerRef={ref}
>
<ListBox {...menuProps} state={state} />
</Popover>
)}
</div>
);
}
+2 -2
View File
@@ -78,8 +78,8 @@ const IndexPage = ({
LightMuted: [0, 0, 0],
Vibrant: [0, 0, 0],
LightVibrant: [0, 0, 0],
DarkMuted: [255, 255, 255],
DarkVibrant: [255, 255, 255],
DarkMuted: [238, 238, 238],
DarkVibrant: [238, 238, 238],
})}
/>
</Helmet>
+6 -5
View File
@@ -2,12 +2,13 @@ import * as React from "react";
import * as R from "ramda";
import { graphql, PageProps } from "gatsby";
import { Helmet } from "react-helmet";
import { Picker, Item } from "@adobe/react-spectrum";
// import { Picker, Item } from "@adobe/react-spectrum";
import MasonryGallery from "../components/MasonryGallery";
import KeywordsPicker from "../components/KeywordsPicker";
import { getGalleryPageUrl, getHelmetSafeBodyStyle } from "../utils";
import Nav from "../components/Nav";
import { Item, Select } from "../components/Select";
const SORT_KEYS = {
hue: ["fields", "imageMeta", "vibrantHue"],
@@ -170,8 +171,8 @@ const GalleryPage = ({ data }: PageProps<Queries.GalleryPageQueryQuery>) => {
LightMuted: [0, 0, 0],
Vibrant: [0, 0, 0],
LightVibrant: [0, 0, 0],
DarkMuted: [255, 255, 255],
DarkVibrant: [255, 255, 255],
DarkMuted: [238, 238, 238],
DarkVibrant: [238, 238, 238],
})}
/>
</Helmet>
@@ -205,7 +206,7 @@ const GalleryPage = ({ data }: PageProps<Queries.GalleryPageQueryQuery>) => {
value={filterKeyword}
/>
<div className="m-2">
<Picker
<Select
label="Sort by..."
// @ts-ignore
onSelectionChange={setSortKey}
@@ -214,7 +215,7 @@ const GalleryPage = ({ data }: PageProps<Queries.GalleryPageQueryQuery>) => {
<Item key="rating">Curated</Item>
<Item key="date">Date</Item>
<Item key="hue">Hue</Item>
</Picker>
</Select>
</div>
</div>
</div>
+2 -1
View File
@@ -45,8 +45,9 @@ module.exports = {
"huge-2": "max(7.8vw, 120px)",
},
colors: {
"white": "#EEEEEE",
buzzwordsPrimary: "#F6C54B",
transparentblack: "rgba(0,0,0,0.3)",
transparentblack: "rgba(0,0,0,0.24)",
vibrant: {
DEFAULT: ({ opacityVariable, opacityValue }) => {
if (opacityValue !== undefined) {
+84 -1263
View File
File diff suppressed because it is too large Load Diff