diff --git a/.changeset/hot-panthers-kneel.md b/.changeset/hot-panthers-kneel.md
new file mode 100644
index 0000000000..19bf4c2cb4
--- /dev/null
+++ b/.changeset/hot-panthers-kneel.md
@@ -0,0 +1,9 @@
+---
+"@khanacademy/wonder-blocks-tokens": major
+---
+
+- Reworked semanticColor actions to use a new structure. Every `action` now includes `default`, `hover` and `press` states, and each state includes `border`, `background` and `foreground` tokens.
+
+- Renamed `primary` to `progressive`.
+
+- Added more categories to actions: `filled` and `outline`.
diff --git a/__docs__/components/color.tsx b/__docs__/components/color.tsx
index 2ea55276fb..9157754f17 100644
--- a/__docs__/components/color.tsx
+++ b/__docs__/components/color.tsx
@@ -17,6 +17,8 @@ import {
} from "@khanacademy/wonder-blocks-tokens";
import {getTokenName} from "./tokens-util";
+type Variant = "primitive" | "semantic" | "compact";
+
type Props = {
/**
* A dictionary of colors to display.
@@ -25,7 +27,7 @@ type Props = {
/**
* The type of color group to display.
*/
- variant: "primitive" | "semantic";
+ variant: Variant;
/**
* The group name to use as a prefix for the color names.
*/
@@ -59,15 +61,70 @@ export function ColorGroup({
type ColorProps = {
name: string;
value: string;
- variant: "primitive" | "semantic";
+ variant: Variant;
};
function Color({name, value, variant}: ColorProps) {
- const TypographyComponent =
- variant === "semantic" ? LabelLarge : LabelSmall;
+ function renderInfo() {
+ if (variant === "compact") {
+ const tokenName = name.toString().split(".");
+ return (
+
+
+ {tokenName.at(tokenName.length - 1)}
+
+
+ {name}
+
+
+
+ Primitive:{" "}
+ {getTokenName(color, value) || value}
+
+
+ );
+ }
+
+ if (variant === "primitive") {
+ return (
+ <>
+
+ {name}
+
+ {value}
+ >
+ );
+ }
+
+ return (
+ <>
+
+ {name}
+
+
+ Primitive: {getTokenName(color, value) || value}
+
+
+ Value: {value}
+
+ >
+ );
+ }
return (
-
+
-
-
- {name}
-
- {variant === "semantic" ? (
- <>
-
- Primitive: {getTokenName(color, value)}
-
-
- Value:{" "}
- {value}
-
- >
- ) : (
- {value}
- )}
-
+
+ {renderInfo()}
+
+ );
+}
+
+type ActionColorGroupProps = {
+ /**
+ * A dictionary of colors to display.
+ */
+ category: Record>;
+ /**
+ * The group name to use as a prefix for the color names.
+ */
+ group: string;
+};
+
+export function ActionColorGroup({category, group}: ActionColorGroupProps) {
+ return Object.entries(category).map(([state, colorGroup]) => (
+
+ {state}
+
+
+ ));
+}
+
+function Example({style}: {style?: any}) {
+ return (
+ <>
+
+ Some Text
+
+ >
);
}
+const itemWidth = 200;
+const itemHeight = 120;
+
const styles = StyleSheet.create({
group: {
flexDirection: "row",
flexWrap: "wrap",
- marginBlock: spacing.large_24,
+ marginBlock: spacing.medium_16,
+ },
+ actionGroup: {
+ margin: spacing.xxxSmall_4,
+ padding: spacing.xxxSmall_4,
+ gap: spacing.xxxSmall_4,
+ border: `1px dashed ${semanticColor.border.subtle}`,
},
item: {
- marginBlockEnd: spacing.medium_16,
+ maxWidth: itemWidth,
+ overflowWrap: "break-word",
+ },
+ compactItem: {
+ marginBlockEnd: spacing.xSmall_8,
+ maxWidth: "100%",
+ width: "100%",
+
+ backgroundColor: semanticColor.surface.secondary,
+ border: `1px solid ${semanticColor.border.primary}`,
+ borderRadius: border.radius.medium_4,
},
pattern: {
backgroundImage: `radial-gradient(${color.blue} 0.5px, ${color.offWhite} 0.5px)`,
backgroundSize: `${spacing.small_12}px ${spacing.small_12}px`,
+ boxShadow: `0 0 1px 0 ${semanticColor.border.primary}`,
},
thumbnail: {
- width: 200,
- height: 160,
+ width: itemWidth,
+ height: itemHeight,
},
primitiveThumbnail: {
width: 160,
height: spacing.xxxLarge_64,
},
+ compactThumbnail: {
+ justifyContent: "space-between",
+ width: "100%",
+ height: spacing.xxxLarge_64,
+ },
+ info: {
+ paddingInlineEnd: spacing.medium_16,
+ },
+ card: {
+ paddingInline: spacing.xSmall_8,
+ },
code: {
alignSelf: "flex-start",
color: semanticColor.text.primary,
@@ -137,4 +255,7 @@ const styles = StyleSheet.create({
padding: spacing.xxxxSmall_2,
borderRadius: border.radius.medium_4,
},
+ capitalized: {
+ textTransform: "capitalize",
+ },
});
diff --git a/__docs__/foundations-color.mdx b/__docs__/foundations-color.mdx
index c80b5b2891..f4e8bbebbb 100644
--- a/__docs__/foundations-color.mdx
+++ b/__docs__/foundations-color.mdx
@@ -5,8 +5,9 @@ import Banner from "@khanacademy/wonder-blocks-banner";
import {View} from "@khanacademy/wonder-blocks-core";
import Link from "@khanacademy/wonder-blocks-link";
import {color, semanticColor, spacing} from "@khanacademy/wonder-blocks-tokens";
+import {LabelLarge} from "@khanacademy/wonder-blocks-typography";
-import {ColorGroup} from "./components/color";
+import {ColorGroup, ActionColorGroup} from "./components/color";
-
-
+
-
+
+##### Destructive
+
+
+
+#### Outlined
+
+Communicates secondary actions and less emphasis.
+
+#### Progressive
+
+
+
+
+
+#### Destructive
+
+
+
+
+
+#### Disabled
+
+
+
### Status
For labels, icons, filters, alerts, and other elements where color can add
@@ -389,10 +437,12 @@ content is accessible to all users.
For more detail, you can check the following Success Criteria documents:
-- Use of Color
-- Contrast (minimum)
-- Non-text
- Contrast (Level AA)
\ No newline at end of file
+-
+ Use of Color
+
+-
+ Contrast (minimum)
+
+-
+ Non-text Contrast (Level AA)
+
diff --git a/packages/wonder-blocks-tokens/src/tokens/semantic-color.ts b/packages/wonder-blocks-tokens/src/tokens/semantic-color.ts
index 0f92484977..367dc48302 100644
--- a/packages/wonder-blocks-tokens/src/tokens/semantic-color.ts
+++ b/packages/wonder-blocks-tokens/src/tokens/semantic-color.ts
@@ -1,18 +1,93 @@
import {color} from "./color";
+const border = {
+ primary: color.fadedOffBlack16,
+ subtle: color.fadedOffBlack8,
+ strong: color.fadedOffBlack50,
+ inverse: color.white,
+};
+
export const semanticColor = {
/**
* For buttons, links, and controls to communicate the presence and meaning
* of interaction.
*/
action: {
- primary: {
- default: color.blue,
- active: color.activeBlue,
+ // Filled buttons are meant for primary actions.
+ filled: {
+ progressive: {
+ default: {
+ border: "transparent",
+ background: color.blue,
+ foreground: color.white,
+ },
+ hover: {
+ border: color.blue,
+ background: color.blue,
+ foreground: color.white,
+ },
+ press: {
+ border: color.activeBlue,
+ background: color.activeBlue,
+ foreground: color.white,
+ },
+ },
+ destructive: {
+ default: {
+ border: "transparent",
+ background: color.red,
+ foreground: color.white,
+ },
+ hover: {
+ border: color.red,
+ background: color.red,
+ foreground: color.white,
+ },
+ press: {
+ border: color.activeRed,
+ background: color.activeRed,
+ foreground: color.white,
+ },
+ },
},
- destructive: {
- default: color.red,
- active: color.activeRed,
+
+ // Outlined is meant for use on secondary controls, or controls over
+ // white/transparent backgrounds.
+ outlined: {
+ progressive: {
+ default: {
+ border: border.strong,
+ background: color.white,
+ foreground: color.blue,
+ },
+ hover: {
+ border: color.blue,
+ background: color.white,
+ foreground: color.blue,
+ },
+ press: {
+ border: color.activeBlue,
+ background: color.fadedBlue,
+ foreground: color.activeBlue,
+ },
+ },
+ destructive: {
+ default: {
+ border: border.strong,
+ background: color.white,
+ foreground: color.red,
+ },
+ hover: {
+ border: color.red,
+ background: color.white,
+ foreground: color.red,
+ },
+ press: {
+ border: color.activeRed,
+ background: color.fadedRed,
+ foreground: color.activeRed,
+ },
+ },
},
disabled: {
default: color.fadedOffBlack32,
@@ -71,12 +146,7 @@ export const semanticColor = {
* elements would use -Primary, rows and layout elements use -Subtle and
* -Strong for when 3:1 contrast is a priority (ex. form elements)
*/
- border: {
- primary: color.fadedOffBlack16,
- subtle: color.fadedOffBlack8,
- strong: color.fadedOffBlack50,
- inverse: color.white,
- },
+ border: border,
/**
* Default icon colors that change in context (like actions).
*/