Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
4dc74ca
improve SelectBox and SentimentRating
reidbarber Oct 3, 2023
ecb8da7
add NavigationBox
reidbarber Oct 3, 2023
2ded47a
add StarRating
reidbarber Oct 3, 2023
19472a1
add star rating
reidbarber Oct 5, 2023
eb8acf9
add GenInputField
reidbarber Oct 5, 2023
560d2a6
fix colors for star rating
reidbarber Oct 5, 2023
545251b
add PlanSwitcher
reidbarber Oct 6, 2023
0e50839
cleanup
reidbarber Oct 6, 2023
01c7b6b
initial docs add
reidbarber Oct 6, 2023
6fa39ff
cleanup docs
reidbarber Oct 6, 2023
6ca4be1
style links
reidbarber Oct 6, 2023
4fd9045
fis focus ring on GenInputField
reidbarber Oct 6, 2023
178ce73
add default to PlanSwitcher
reidbarber Oct 6, 2023
fc5f88e
add label to plan switcher
reidbarber Oct 6, 2023
c63b5ed
cleanup styles
reidbarber Oct 6, 2023
cde2e8d
cleanup docs
reidbarber Oct 6, 2023
6efbdcd
cleanup styles
reidbarber Oct 6, 2023
9932892
Merge remote-tracking branch 'origin/main' into rac-spectrum-tailwind…
reidbarber Oct 6, 2023
601bb8c
cleanup pointer hovering
reidbarber Oct 10, 2023
a4e1bb1
Merge remote-tracking branch 'origin/main' into rac-spectrum-tailwind…
reidbarber Oct 10, 2023
d910458
fix some styles in dark mode
reidbarber Oct 10, 2023
f7d1b54
improve PlanSwitcher badge label
reidbarber Oct 11, 2023
89b7cf6
remove old comment
reidbarber Oct 11, 2023
6f68455
fix StarRating example
reidbarber Oct 11, 2023
dfa0339
add aria-hidden="true" to underline
reidbarber Oct 11, 2023
93703e9
fomatting
reidbarber Oct 11, 2023
d6d2497
Merge branch 'main' into rac-spectrum-tailwind-improvements
reidbarber Oct 17, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
336 changes: 231 additions & 105 deletions examples/rac-spectrum-tailwind/src/App.js
Original file line number Diff line number Diff line change
@@ -1,128 +1,254 @@
import { useState } from "react";
import { defaultTheme, Provider } from "@adobe/react-spectrum";
import { Label, Radio, RadioGroup, Button } from "react-aria-components";
import { defaultTheme, Link, Provider } from "@adobe/react-spectrum";
import User from "@spectrum-icons/workflow/User";
import UserGroup from "@spectrum-icons/workflow/UserGroup";
import Building from "@spectrum-icons/workflow/Building";
import CheckmarkCircle from "@spectrum-icons/workflow/CheckmarkCircle";
import ThemeSwitcher from "./ThemeSwitcher";
import { SelectBoxGroup, SelectBox } from "./components/SelectBoxGroup";
import { SentimentRatingGroup } from "./components/SentimentRatingGroup";
import { NavigationBox } from "./components/NavigationBox";
import { StarRatingGroup } from "./components/StarRatingGroup";
import { GenInputField } from "./components/GenInputField";
import { PlanSwitcher } from "./components/PlanSwitcher";

export function App() {
let [colorScheme, setColorScheme] = useState(undefined);

return (
<Provider theme={defaultTheme} colorScheme={colorScheme}>
<ThemeSwitcher setColorScheme={setColorScheme} />
<div className="grid justify-center grid-cols-1 gap-160 auto-rows-fr">
<SelectBoxExample />
<SentimentRatingGroup />
<div className="flex justify-center">
<div className="flex flex-col max-w-sm">
<label for="test-input">Native input</label>
<input id="test-input" className="border focus:bg-gray-200 focus:outline-none focus:border-blue-600 hover:border-blue-300" />
<p>For the purpose of ensuring Tailwind's default selectors still work for non-RAC elements when using the plugin.</p>
<h1 className="text-4xl font-bold text-center mb-300 pt-300">
[RAC + Spectrum + Tailwind] Cookbook
</h1>
<section className="max-w-xl m-auto">
<section className="mb-300">
<h2 className="text-2xl font-semibold text-center underline underline-offset-2">
Intro
</h2>
<h3 className="text-xl font-semibold">📙 Overview</h3>
<div className="mb-200">
This resource is meant to help you get started with creating custom
components using{" "}
<Link href="https://react-spectrum.adobe.com/react-aria/react-aria-components.html">
React Aria Components
</Link>{" "}
and <Link href="https://tailwindcss.com/">Tailwind CSS</Link>, with
a theme that features{" "}
<Link href="https://spectrum.adobe.com/">Spectrum</Link> styles and
values. The goal for this is to enable you to deliver accessible
custom Spectrum components more quickly.
</div>
</div>
<div className="flex justify-center">
<div className="flex flex-col">
<Button className="flex flex-col justify-center bg-white dark:bg-black border rounded group/button p-160 m-160 focus:outline-none focus-visible:ring">
<div className="w-full">Test Button</div>
<div className="w-full invisible group-hover/button:visible">Group is hovered</div>
</Button>
<p>For the purpose of testing named groups.</p>
<h3 className="text-xl font-semibold">✅ When to use this</h3>
<div className="mb-200">
When you need to implement a component that follows Spectrum
guidelines, but doesn't exist in React Spectrum.
</div>
</div>
</div>
</Provider>
);
<h3 className="text-xl font-semibold">❌ When not to use this</h3>
<div className="mb-200">
When you want to avoid patterns specifically outlined by Spectrum,
or when a React Spectrum component already exists for your use case.
</div>
<h3 className="text-xl font-semibold">⚠️ Risks</h3>
<div className="mb-200">
Since you're taking ownership of the components you build, you still
need to ensure they follow Spectrum guidelines and accessibility
guidelines.
</div>
</section>
<section className="mb-300">
<h2 className="text-2xl font-semibold text-center underline underline-offset-2">
Setup
</h2>
<ol>
<li>
<h3 className="text-xl font-semibold">📦 Install dependencies</h3>
<div className="mb-200">
We need to install{" "}
<Link href="https://react-spectrum.adobe.com/react-spectrum/getting-started.html">
React Spectrum
</Link>
,{" "}
<Link href="https://react-spectrum.adobe.com/react-aria/react-aria-components.html#installation">
React Aria Components
</Link>
, and the{" "}
<Link href="https://react-spectrum.adobe.com/react-aria/styling.html#plugin">
RAC Tailwind plugin
</Link>
.
</div>
<code className="p-40 bg-gray-200 rounded mb-200">
yarn add @adobe/react-spectrum react-aria-components
tailwindcss-react-aria-components
</code>
<div className="mb-200 mt-200">
Note that the reason React Spectrum is needed, is because the
Provider will provide CSS variables that our theme will
reference.
</div>
</li>
<li>
<h3 className="text-xl font-semibold">⚡ Install Tailwind</h3>
<div className="mb-200">
Follow the instructions in the{" "}
<Link href="https://tailwindcss.com/docs/installation">
Tailwind Docs
</Link>{" "}
based on your build setup.{" "}
</div>
</li>
<li>
<h3 className="text-xl font-semibold">🛠️ Configure Tailwind</h3>
<div className="mb-200">
<div className="mb-200">
In your tailwind.config.js, include the preset from this
template:
</div>
<pre className="block p-40 bg-gray-200 rounded mb-200">{`/** @type {import('tailwindcss').Config} */
module.exports = {
presets: [
require('./src/spectrum-preset.js')
],
plugins: [
require('tailwindcss-react-aria-components')
],
}
`}</pre>
</div>
</li>
<li>
Then, add a React Spectrum{" "}
<Link href="https://react-spectrum.adobe.com/react-spectrum/Provider.html">
Provider
</Link>{" "}
to your app if one doesn't already exist. This will ensure that
your page has access to the proper CSS variables. If you include
these variables using some other method, that will work too.
</li>
</ol>
<div></div>
</section>
<section className="mb-600">
<h2 className="text-2xl font-semibold text-center underline underline-offset-2">
Usage
</h2>
<div>
<h3 className="text-xl font-semibold">🎨 Add styles</h3>
<div className="mb-200">
You can now use Tailwind classes to style your components.
</div>
<div className="mb-100">Here are some examples:</div>
<ul className="list-disc mb-200">
<li>
Using <code className="p-40 bg-gray-200 rounded">ring</code>{" "}
will give you a focus ring with good default Spectrum styles for
it's color, width, and offset.
</li>
<li>
Using{" "}
<code className="p-40 bg-gray-200 rounded">bg-blue-600</code>{" "}
will give you a background that matches
--spectrum-global-color-blue-600.
</li>
<li>
Using <code className="p-40 bg-gray-200 rounded">w-25</code>{" "}
will give you a width of
var(--spectrum-global-dimension-size-25).
</li>
<li>
Using{" "}
<code className="p-40 bg-gray-200 rounded">
ease-in duration-100
</code>{" "}
will give you a transition that matches Spectrum's motion
values.
</li>
<li>
Using{" "}
<code className="p-40 bg-gray-200 rounded">sm:text-left</code>{" "}
will give you left text alignment for small width devices based
on Spectrum's break points.
</li>
<li>
Using{" "}
<code className="p-40 bg-gray-200 rounded">dark:bg-black</code>{" "}
will give you a black background if the user is in dark mode
based on the React Spectrum provider.
</li>
</ul>
<div>
<h3 className="text-xl font-semibold">
🪄 Styling based on state
</h3>
To see how to add Tailwind styles based on state, see the{" "}
<Link href="https://react-spectrum.adobe.com/react-aria/styling.html#tailwind-css">
RAC Styling docs
</Link>
.
</div>
</div>
</section>
</section>
<section>
<h2 className="text-2xl font-bold text-center underline mb-300 underline-offset-2">
Examples
</h2>
<div className="grid justify-center grid-cols-1 gap-160 auto-rows-fr">
<SelectBoxGroup label="Select Boxes" defaultValue="Team">
<SelectBox
name="Individual"
icon={<User size="XL" />}
description="For 1 person"
/>
<SelectBox
name="Team"
icon={<UserGroup size="XL" />}
description="For teams of 9 or less"
/>
<SelectBox
name="Enterprise"
icon={<Building size="XL" />}
description="For of 10 or more"
/>
</SelectBoxGroup>

function SelectBoxExample() {
return (
<RadioGroup
data-rac
className="flex flex-col space-y-2 text-center"
defaultValue="Team"
>
<Label className="text-xl font-semibold">Select Boxes</Label>
<div className="flex justify-center">
<SelectBox
name="Individual"
icon={<User size="XL" />}
description="For 1 person"
/>
<SelectBox
name="Team"
icon={<UserGroup size="XL" />}
description="For teams of 9 or less"
/>
<SelectBox
name="Enterprise"
icon={<Building size="XL" />}
description="For of 10 or more"
/>
</div>
</RadioGroup>
);
}
<SentimentRatingGroup />

function SelectBox({ name, icon, description }) {
return (
<Radio
data-rac
value={name}
className={({ isFocusVisible, isSelected, isPressed }) => `
flex justify-center p-160 m-160 h-2000 w-2000 focus:outline-none border rounded
${isFocusVisible ? "ring-half ring-offset-0" : ""}
${isSelected ? "bg-accent-100 border-accent-700" : ""}
${isPressed && !isSelected ? "bg-gray-200" : ""}
${!isSelected && !isPressed ? "bg-white dark:bg-black" : ""}
`}
>
{({ isSelected }) => (
<div className="relative flex flex-col items-center justify-center w-full h-full gap-150">
{isSelected && (
<div className="absolute top-0 left-0 text-accent-800 -mt-125 -ml-75">
<CheckmarkCircle size="S" />
<div className="text-center">
<span className="text-xl font-semibold mb-200">
Navigation Boxes
</span>
<div className="flex justify-center">
<NavigationBox
href="https://adobe.com"
src="https://i.imgur.com/DhygPot.jpg"
>
Premium
</NavigationBox>
<NavigationBox
href="https://adobe.com"
src="https://i.imgur.com/Z7AzH2c.png"
>
Templates
</NavigationBox>
</div>
)}
{icon && <div className="text-gray-500">{icon}</div>}
<div>
<div className={`font-semibold`}>{name}</div>
{description && <div className="text-sm">{description}</div>}
</div>
</div>
)}
</Radio>
);
}

function SentimentRatingGroup() {
let ratings = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"];
return (
<RadioGroup className="flex flex-col m-auto space-y-10 text-center">
<Label className="text-xl font-semibold">Sentiment Rating</Label>
<div className="flex justify-between">
<span>Least Likely</span>
<span>Most Likely</span>
</div>
<div className="flex justify-evenly">
{ratings.map((rating) => (
<SentimentRating key={rating} rating={rating} />
))}
</div>
</RadioGroup>
);
}
<div className="m-auto space-y-200">
<StarRatingGroup label="Star Rating" />
<StarRatingGroup isEmphasized label="Star Rating (Emphasized)" />
</div>

function SentimentRating({ rating }) {
return (
<Radio
data-rac
value={rating}
className="flex items-center justify-center bg-white border rounded-full p-160 m-75 h-200 w-200 focus:outline-none focus-visible:ring dark:bg-black selected:bg-accent-800 dark:selected:bg-accent-800 selected:border-accent-800 selected:text-white pressed:bg-gray-200 dark:pressed:bg-gray-200 hover:border-gray-300"
>
{rating}
</Radio>
<PlanSwitcher />

<div className="w-full m-auto">
<div className="text-xl font-semibold text-center mb-200">
GenAI Input
</div>
<GenInputField />
</div>
</div>
</section>
</Provider>
);
}
2 changes: 1 addition & 1 deletion examples/rac-spectrum-tailwind/src/ThemeSwitcher.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export default function ThemeSwitcher({ setColorScheme }) {
let otherScheme = colorScheme === "light" ? "dark" : "light";

return (
<div className="float-right m-50">
<div className="absolute right-0 m-50">
<ActionButton
aria-label={label}
onPress={() => setColorScheme(otherScheme)}
Expand Down
Loading