diff --git a/.changeset/shiny-chicken-speak.md b/.changeset/shiny-chicken-speak.md new file mode 100644 index 0000000000..3b2c665ed5 --- /dev/null +++ b/.changeset/shiny-chicken-speak.md @@ -0,0 +1,5 @@ +--- +"@khanacademy/wonder-blocks-tokens": minor +--- + +Adds `fadedOffBlack72` color primitive token and sets the `semanticColor.text.secondary` token to this primitive. The slightly darker gray has better color contrast on a variety of backgrounds, including the fadedBlue8 background diff --git a/.changeset/wise-actors-peel.md b/.changeset/wise-actors-peel.md new file mode 100644 index 0000000000..89dfa13a42 --- /dev/null +++ b/.changeset/wise-actors-peel.md @@ -0,0 +1,20 @@ +--- +"@khanacademy/wonder-blocks-cell": patch +--- + +DetailCell and CompactCell: update styling to address accessibility issues (color contrast and using color as the only visual indicator). Updated styles include: + +- General: + - Changing the grey used for subtitles + - Using `icon.primary` for the right accessory +- Press state: + - Changing the background to `fadedBlue8` + - Adding a thin left border when clickable cells are pressed +- Hover state: + - Changing the background to `fadedBlue8` +- Disabled state: + - Changing the focus outline to `action.disabled.default` +- Selected state (cells with `active=true`): + - Adding a thick left border + - Changing the text color to `activeBlue` + - The styling no longer changes when a selected cell is hovered or pressed on diff --git a/__docs__/wonder-blocks-cell/compact-cell-variants.stories.tsx b/__docs__/wonder-blocks-cell/compact-cell-variants.stories.tsx new file mode 100644 index 0000000000..f194fb8378 --- /dev/null +++ b/__docs__/wonder-blocks-cell/compact-cell-variants.stories.tsx @@ -0,0 +1,120 @@ +import * as React from "react"; +import {StyleSheet} from "aphrodite"; +import type {Meta, StoryObj} from "@storybook/react"; + +import {PropsFor, View} from "@khanacademy/wonder-blocks-core"; +import {spacing} from "@khanacademy/wonder-blocks-tokens"; +import {CompactCell} from "@khanacademy/wonder-blocks-cell"; +import {PhosphorIcon} from "@khanacademy/wonder-blocks-icon"; +import {IconMappings} from "../wonder-blocks-icon/phosphor-icon.argtypes"; +import {LabelSmall} from "@khanacademy/wonder-blocks-typography"; + +/** + * The following stories are used to generate the pseudo states for the + * CompactCell component. This is only used for visual testing in Chromatic. + */ +export default { + title: "Packages / Cell / CompactCell / All Variants", + parameters: { + docs: { + autodocs: false, + }, + backgrounds: { + default: "offWhite", + }, + }, +} as Meta; + +type StoryComponentType = StoryObj; + +const states = [ + { + label: "Default", + props: {}, + }, + { + label: "Disabled", + props: {disabled: true}, + }, + { + label: "Selected using active: true", + props: {active: true}, + }, +]; + +const defaultProps = { + title: "Title for article item", + leftAccessory: ( + + ), + rightAccessory: , +}; + +const States = (props: {label: string} & PropsFor) => { + return ( + + + {states.map((scenario) => { + return ( + + + {props.label} ({scenario.label}) + + + + ); + })} + + + ); +}; + +const AllVariants = () => ( + + + {}} /> + + +); + +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({ + statesContainer: { + padding: spacing.medium_16, + }, + scenarios: { + display: "flex", + flexDirection: "row", + alignItems: "center", + gap: spacing.xxxLarge_64, + flexWrap: "wrap", + }, + scenario: { + gap: spacing.small_12, + overflow: "hidden", + }, +}); diff --git a/__docs__/wonder-blocks-cell/detail-cell-variants.stories.tsx b/__docs__/wonder-blocks-cell/detail-cell-variants.stories.tsx index a22f4b190f..c7b391bb4a 100644 --- a/__docs__/wonder-blocks-cell/detail-cell-variants.stories.tsx +++ b/__docs__/wonder-blocks-cell/detail-cell-variants.stories.tsx @@ -37,7 +37,7 @@ const states = [ props: {disabled: true}, }, { - label: "Active", + label: "Selected using active: true", props: {active: true}, }, ]; diff --git a/__docs__/wonder-blocks-cell/detail-cell.stories.tsx b/__docs__/wonder-blocks-cell/detail-cell.stories.tsx index 4d7a137901..5127e0fd22 100644 --- a/__docs__/wonder-blocks-cell/detail-cell.stories.tsx +++ b/__docs__/wonder-blocks-cell/detail-cell.stories.tsx @@ -3,8 +3,13 @@ import {StyleSheet} from "aphrodite"; import {MemoryRouter, Route, Switch} from "react-router-dom"; import type {Meta, StoryObj} from "@storybook/react"; -import {View} from "@khanacademy/wonder-blocks-core"; -import {color, spacing} from "@khanacademy/wonder-blocks-tokens"; +import {PropsFor, View} from "@khanacademy/wonder-blocks-core"; +import { + border, + color, + semanticColor, + spacing, +} from "@khanacademy/wonder-blocks-tokens"; import {PhosphorIcon} from "@khanacademy/wonder-blocks-icon"; import {DetailCell} from "@khanacademy/wonder-blocks-cell"; @@ -469,6 +474,82 @@ export const Scenarios = () => { ); }; +/** + * Custom styling can be applied to the component using the `rootStyle` or + * `style` props. + */ +export const CustomRootStyle = { + args: { + title: "Title for article item", + subtitle1: "Subtitle for article item", + subtitle2: "Subtitle for article item", + leftAccessory: ( + + ), + }, + render(args: PropsFor) { + return ( + + Active (with rootStyle prop): + + Pressed (with rootStyle prop): + + Different content heights (with style prop) + + {}} + style={[ + { + border: `1px solid ${semanticColor.border.primary}`, + }, + ]} + horizontalRule={"none"} + /> + {}} + style={[ + args.rootStyle, + { + border: `1px solid ${semanticColor.border.primary}`, + }, + ]} + horizontalRule={"none"} + /> + {}} + style={[ + args.rootStyle, + { + border: `1px solid ${semanticColor.border.primary}`, + }, + ]} + horizontalRule={"none"} + /> + + + ); + }, + parameters: {pseudo: {active: true}}, +}; + const styles = StyleSheet.create({ example: { backgroundColor: color.offWhite, diff --git a/packages/wonder-blocks-cell/src/components/detail-cell.tsx b/packages/wonder-blocks-cell/src/components/detail-cell.tsx index 1b1661c0e8..cc0e92bbb6 100644 --- a/packages/wonder-blocks-cell/src/components/detail-cell.tsx +++ b/packages/wonder-blocks-cell/src/components/detail-cell.tsx @@ -2,7 +2,7 @@ import * as React from "react"; import {StyleSheet} from "aphrodite"; import {Strut} from "@khanacademy/wonder-blocks-layout"; -import {color, spacing} from "@khanacademy/wonder-blocks-tokens"; +import {semanticColor, spacing} from "@khanacademy/wonder-blocks-tokens"; import {LabelSmall, LabelMedium} from "@khanacademy/wonder-blocks-typography"; import CellCore from "./internal/cell-core"; @@ -94,7 +94,7 @@ const DetailCell = function (props: DetailCellProps): React.ReactElement { const styles = StyleSheet.create({ subtitle: { - color: color.offBlack64, + color: semanticColor.text.secondary, }, // This is to override the default padding of the CellCore innerWrapper. diff --git a/packages/wonder-blocks-cell/src/components/internal/cell-core.tsx b/packages/wonder-blocks-cell/src/components/internal/cell-core.tsx index 35c5d6bddf..c3b8a613a8 100644 --- a/packages/wonder-blocks-cell/src/components/internal/cell-core.tsx +++ b/packages/wonder-blocks-cell/src/components/internal/cell-core.tsx @@ -6,7 +6,12 @@ import type {StyleType} from "@khanacademy/wonder-blocks-core"; import Clickable from "@khanacademy/wonder-blocks-clickable"; import {View} from "@khanacademy/wonder-blocks-core"; import {Strut} from "@khanacademy/wonder-blocks-layout"; -import {color, spacing} from "@khanacademy/wonder-blocks-tokens"; +import { + border, + color, + semanticColor, + spacing, +} from "@khanacademy/wonder-blocks-tokens"; import {CellMeasurements, getHorizontalRuleStyles} from "./common"; @@ -118,7 +123,11 @@ function CellInner(props: CellCoreProps): React.ReactElement { // custom styles style, horizontalRuleStyles, + active && styles.activeInnerWrapper, ]} + // Set className so we can set styles on the inner wrapper directly + // when the clickable element is pressed + className="inner-wrapper" > {/* Left accessory */}