-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
WB-1808: Button - Use CSS pseudo-classes for styling states (hover, f…
…ocus, etc) (#2404) ## Summary: Changing the way we style different states. We are going to rely on CSS pseudo-classes for styling states (`:hover`, `:focus-visible`). Note that we have to keep some `ClickableBehavior` states for programmatic focus and preserve active/pressed overrides. Also took the opportunity to modify the primary variant to use `outline + outlineOffset` instead of `boxShadow`. Issue: https://khanacademy.atlassian.net/browse/WB-1808 ## Test plan: Navigate to `/?path=/docs/packages-button--docs` and verify that the buttons are styled correctly. <img width="1634" alt="Screenshot 2024-12-19 at 5 28 22 PM" src="https://github.com/user-attachments/assets/067b8c6d-2a2d-4be8-80b7-3a1ba01108c4" /> Author: jandrade Reviewers: jandrade, beaesguerra Required Reviewers: Approved By: beaesguerra Checks: ✅ Chromatic - Get results on regular PRs (ubuntu-latest, 20.x), ✅ Test / Test (ubuntu-latest, 20.x, 2/2), ✅ Test / Test (ubuntu-latest, 20.x, 1/2), ✅ Lint / Lint (ubuntu-latest, 20.x), ✅ Check build sizes (ubuntu-latest, 20.x), ✅ Publish npm snapshot (ubuntu-latest, 20.x), ✅ Chromatic - Build on regular PRs / chromatic (ubuntu-latest, 20.x), ✅ Check for .changeset entries for all changed files (ubuntu-latest, 20.x), ✅ Prime node_modules cache for primary configuration (ubuntu-latest, 20.x), ⏭️ Chromatic - Skip on Release PR (changesets), ✅ gerald, ⏭️ dependabot Pull Request URL: #2404
- Loading branch information
Showing
7 changed files
with
328 additions
and
3,593 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"@khanacademy/wonder-blocks-button": patch | ||
--- | ||
|
||
Use pseudo-classes for styling states (:hover, :focus-visible). Keep some clickable states for programmatic focus and preserve active/pressed overrides. |
194 changes: 194 additions & 0 deletions
194
__docs__/wonder-blocks-button/button-variants.stories.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,194 @@ | ||
import * as React from "react"; | ||
import {StyleSheet} from "aphrodite"; | ||
import {action} from "@storybook/addon-actions"; | ||
import type {Meta, StoryObj} from "@storybook/react"; | ||
|
||
import paperPlaneIcon from "@phosphor-icons/core/fill/paper-plane-tilt-fill.svg"; | ||
import {PropsFor, View} from "@khanacademy/wonder-blocks-core"; | ||
import {ThemeSwitcherContext} from "@khanacademy/wonder-blocks-theming"; | ||
import {color, semanticColor, spacing} from "@khanacademy/wonder-blocks-tokens"; | ||
import {HeadingLarge, LabelMedium} from "@khanacademy/wonder-blocks-typography"; | ||
import Button from "@khanacademy/wonder-blocks-button"; | ||
|
||
/** | ||
* The following stories are used to generate the pseudo states for the | ||
* Button component. This is only used for visual testing in Chromatic. | ||
*/ | ||
export default { | ||
title: "Packages / Button / All Variants", | ||
parameters: { | ||
docs: { | ||
autodocs: false, | ||
}, | ||
chromatic: { | ||
// NOTE: This is required to prevent Chromatic from cutting off the | ||
// dark background in screenshots (accounts for all the space taken | ||
// by the variants). | ||
viewports: [1700], | ||
}, | ||
}, | ||
} as Meta; | ||
|
||
type StoryComponentType = StoryObj<typeof Button>; | ||
|
||
type ButtonProps = PropsFor<typeof Button>; | ||
|
||
const sizes: Array<ButtonProps["size"]> = ["medium", "small", "large"]; | ||
const kinds: Array<ButtonProps["kind"]> = ["primary", "secondary", "tertiary"]; | ||
|
||
const colors: Array<ButtonProps["color"]> = ["default", "destructive"]; | ||
|
||
function VariantsGroup({ | ||
color = "default", | ||
disabled = false, | ||
label = "Button", | ||
light, | ||
size, | ||
}: { | ||
color?: ButtonProps["color"]; | ||
disabled?: ButtonProps["disabled"]; | ||
label?: string; | ||
light: boolean; | ||
size: ButtonProps["size"]; | ||
}) { | ||
const theme = React.useContext(ThemeSwitcherContext); | ||
const category = disabled ? "disabled" : color; | ||
|
||
return ( | ||
<View | ||
style={[ | ||
styles.variants, | ||
light && | ||
(theme === "khanmigo" | ||
? styles.darkKhanmigo | ||
: styles.darkDefault), | ||
]} | ||
> | ||
<LabelMedium style={[styles.label, light && styles.inverseLabel]}> | ||
{size} / {category} | ||
</LabelMedium> | ||
{kinds.map((kind) => ( | ||
<React.Fragment key={kind}> | ||
<Button | ||
onClick={action("clicked")} | ||
disabled={disabled} | ||
kind={kind} | ||
light={light} | ||
color={color} | ||
size={size} | ||
> | ||
{label} | ||
</Button> | ||
{/* startIcon */} | ||
<Button | ||
onClick={action("clicked")} | ||
disabled={disabled} | ||
kind={kind} | ||
light={light} | ||
color={color} | ||
size={size} | ||
startIcon={paperPlaneIcon} | ||
> | ||
{label} | ||
</Button> | ||
{/* endIcon */} | ||
<Button | ||
onClick={action("clicked")} | ||
disabled={disabled} | ||
kind={kind} | ||
light={light} | ||
color={color} | ||
size={size} | ||
endIcon={paperPlaneIcon} | ||
> | ||
{label} | ||
</Button> | ||
</React.Fragment> | ||
))} | ||
</View> | ||
); | ||
} | ||
|
||
const KindVariants = ({light}: {light: boolean}) => { | ||
return ( | ||
<> | ||
{sizes.map((size) => ( | ||
<> | ||
{colors.map((color) => ( | ||
<VariantsGroup | ||
size={size} | ||
color={color} | ||
light={light} | ||
/> | ||
))} | ||
<VariantsGroup size={size} disabled={true} light={light} /> | ||
</> | ||
))} | ||
</> | ||
); | ||
}; | ||
|
||
const VariantsByTheme = ({themeName = "Default"}: {themeName?: string}) => ( | ||
<View style={{marginBottom: spacing.large_24}}> | ||
<HeadingLarge>{themeName} theme</HeadingLarge> | ||
<KindVariants light={false} /> | ||
<KindVariants light={true} /> | ||
</View> | ||
); | ||
|
||
const AllVariants = () => ( | ||
<> | ||
<VariantsByTheme /> | ||
<ThemeSwitcherContext.Provider value="khanmigo"> | ||
<VariantsByTheme themeName="Khanmigo" /> | ||
</ThemeSwitcherContext.Provider> | ||
</> | ||
); | ||
|
||
export const Default: StoryComponentType = { | ||
render: AllVariants, | ||
}; | ||
|
||
export const Hover: StoryComponentType = { | ||
render: AllVariants, | ||
parameters: {pseudo: {hover: true}}, | ||
}; | ||
|
||
export const Focus: StoryComponentType = { | ||
render: AllVariants, | ||
parameters: {pseudo: {focusVisible: true}}, | ||
}; | ||
|
||
export const HoverFocus: StoryComponentType = { | ||
name: "Hover + Focus", | ||
render: AllVariants, | ||
parameters: {pseudo: {hover: true, focusVisible: true}}, | ||
}; | ||
|
||
export const Active: StoryComponentType = { | ||
render: AllVariants, | ||
parameters: {pseudo: {active: true}}, | ||
}; | ||
|
||
const styles = StyleSheet.create({ | ||
darkDefault: { | ||
backgroundColor: color.darkBlue, | ||
}, | ||
darkKhanmigo: { | ||
backgroundColor: color.eggplant, | ||
}, | ||
variants: { | ||
justifyContent: "flex-start", | ||
padding: spacing.medium_16, | ||
display: "flex", | ||
flexDirection: "row", | ||
alignItems: "center", | ||
gap: spacing.xLarge_32, | ||
}, | ||
label: { | ||
minWidth: 150, | ||
}, | ||
inverseLabel: { | ||
color: semanticColor.text.inverse, | ||
}, | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.