@codecademy/gamut
68.6.068.6.1-alpha.5064c8.0
agent-tools/skills/gamut-style-utilities/SKILL.md+
agent-tools/skills/gamut-style-utilities/SKILL.mdNew file+107
Index: package/agent-tools/skills/gamut-style-utilities/SKILL.md
===================================================================
--- package/agent-tools/skills/gamut-style-utilities/SKILL.md
+++ package/agent-tools/skills/gamut-style-utilities/SKILL.md
@@ -0,0 +1,107 @@
+---
+name: gamut-style-utilities
+description: Use this skill when authoring Gamut styles with @codecademy/gamut-styles — css(), variant(), states(), StyleProps from variance, or the useTheme() escape hatch; choosing between these APIs and system props; semantic tokens with ColorMode.
+---
+
+# Gamut style utilities
+
+Source: `@codecademy/gamut-styles` — [`variance/props.ts`](https://github.com/Codecademy/gamut/blob/main/packages/gamut-styles/src/variance/props.ts) (`css`, `variant`, `states` built on `PROPERTIES.all`).
+
+See also: [`gamut-theming`](../gamut-theming/SKILL.md) (which theme, `GamutProvider`, new themes). [`gamut-system-props`](../gamut-system-props/SKILL.md) (`system.*`, responsive props, `Box`). [`gamut-color-mode`](../gamut-color-mode/SKILL.md) (semantic color, `<ColorMode>`, `<Background>`). [Best practices](../../../../styleguide/src/lib/Meta/Best%20practices.mdx) and [system compose](https://gamut.codecademy.com/?path=/docs-foundations-system-compose--page).
+
+## Overview
+
+Use `css()`, `variant()`, and `states()` from `@codecademy/gamut-styles` for typed, token-scaled style objects (same scales as composed `system.*` props). Prefer semantic color keys so styles track ColorMode and theme.
+
+For layout-heavy styled components, prefer composing `system.*` via `variance.compose()` (see `gamut-system-props`) instead of re-stating every longhand in `css()`.
+
+## `css()` — static style objects
+
+```tsx
+import { css } from '@codecademy/gamut-styles';
+import styled from '@emotion/styled';
+
+const Box = styled.div(css({ bg: 'navy-400', p: 4 }));
+const Text = styled.div(css({ color: 'primary', p: 4 }));
+```
+
+## `variant()` and `states()` — branching and toggles
+
+- `variant()` — mutually exclusive modes: `base`, `defaultVariant`, and a `variants` map (semantic colors, spacing shorthands, nested selectors such as `'&:hover'`).
+
+```tsx
+import { variant } from '@codecademy/gamut-styles';
+import styled from '@emotion/styled';
+
+const Anchor = styled.a(
+ variant({
+ base: { p: 4 },
+ defaultVariant: 'interface',
+ variants: {
+ interface: {
+ color: 'text',
+ '&:hover': { color: 'text-accent' },
+ },
+ inline: {
+ color: 'primary',
+ '&:hover': { color: 'secondary' },
+ },
+ },
+ })
+);
+```
+
+- `states()` — independent boolean-style props (`base` + named keys).
+
+```tsx
+import { states } from '@codecademy/gamut-styles';
+import styled from '@emotion/styled';
+
+const UtilityBox = styled.div(
+ states({
+ base: { mx: 4, my: 8, p: 16 },
+ disabled: { bg: 'background-disabled', color: 'text-disabled' },
+ center: { alignItems: 'center', justifyContent: 'center' },
+ })
+);
+```
+
+### `StyleProps` on React components
+
+```tsx
+import { states } from '@codecademy/gamut-styles';
+import { StyleProps } from '@codecademy/variance';
+import styled from '@emotion/styled';
+
+const panelShellStates = states({ base: { p: 4 }, dense: { p: 2 } });
+const PanelShell = styled.div(panelShellStates);
+
+export type PanelShellProps = StyleProps<typeof panelShellStates> & {
+ title: string;
+};
+
+export const Panel: React.FC<PanelShellProps> = ({ title, ...rest }) => (
+ <PanelShell {...rest}>{title}</PanelShell>
+);
+```
+
+Prefer `variant` / `states` over branching on raw `theme` fields inside styled template literals when the output is Emotion-managed CSS.
+
+## `useTheme()` — escape hatch
+
+Prefer `css()`, `system.*`, `variant()`, and `states()` for styling. Use `useTheme()` from `@emotion/react` when a token value must be read in plain JS (charts, canvas, third-party props), not as the default way to color DOM nodes.
+
+```tsx
+import { useTheme } from '@emotion/react';
+
+const Sparkline = () => {
+ const theme = useTheme();
+ return <path strokeWidth={theme.spacing[4]} d="M0 0 L10 10" />;
+};
+```
+
+## Key principles
+
+- Prefer semantic color keys in `css` / `variant` / `states` so ColorMode and theme switches apply; see `gamut-color-mode`.
+- Never hardcode hex in component styles — use tokens / semantic aliases.
+- Prefer `variant` / `states` for modes and toggles instead of ad-hoc `theme` interpolation in template literals.