From 7693a3f244a8972e738fa0efaba5d38bad878427 Mon Sep 17 00:00:00 2001 From: Alex Carpenter Date: Fri, 17 Jul 2026 14:49:47 -0400 Subject: [PATCH 1/5] init --- .claude/skills/README.md | 9 +- .claude/skills/mosaic-stylex/SKILL.md | 130 +++++++++ .../mosaic-stylex/references/authoring.md | 250 +++++++++++++++++ .../skills/mosaic-stylex/references/build.md | 116 ++++++++ .../mosaic-stylex/references/migration.md | 101 +++++++ .../mosaic-stylex/references/organization.md | 139 ++++++++++ .../mosaic-stylex/references/overrides.md | 150 +++++++++++ .../references/relational-and-dynamic.md | 138 ++++++++++ .../references/tokens-and-theming.md | 255 ++++++++++++++++++ 9 files changed, 1284 insertions(+), 4 deletions(-) create mode 100644 .claude/skills/mosaic-stylex/SKILL.md create mode 100644 .claude/skills/mosaic-stylex/references/authoring.md create mode 100644 .claude/skills/mosaic-stylex/references/build.md create mode 100644 .claude/skills/mosaic-stylex/references/migration.md create mode 100644 .claude/skills/mosaic-stylex/references/organization.md create mode 100644 .claude/skills/mosaic-stylex/references/overrides.md create mode 100644 .claude/skills/mosaic-stylex/references/relational-and-dynamic.md create mode 100644 .claude/skills/mosaic-stylex/references/tokens-and-theming.md diff --git a/.claude/skills/README.md b/.claude/skills/README.md index 0031ac9bc9c..dbebb0e3f54 100644 --- a/.claude/skills/README.md +++ b/.claude/skills/README.md @@ -41,7 +41,8 @@ Skills are Claude Code specific. Cursor does not read this directory; it uses `. ## Skills in this repo -| Skill | Use it for | -| ---------------- | --------------------------------------------------------------------------------------------------------------------------------------- | -| `clerk-monorepo` | Day-to-day work in the monorepo: setup, build/test loops, the package map, changesets, commits, PRs, breaking-change checks. | -| `mosaic` | Mosaic flow UI: authoring machines, controllers, and views, and migrating a legacy component into the split (with parity verification). | +| Skill | Use it for | +| ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `clerk-monorepo` | Day-to-day work in the monorepo: setup, build/test loops, the package map, changesets, commits, PRs, breaking-change checks. | +| `mosaic` | Mosaic flow UI: authoring machines, controllers, and views, and migrating a legacy component into the split (with parity verification). | +| `mosaic-stylex` | Authoring StyleX for Mosaic: `stylex.create`/`props`, `--cl-*` tokens, the stable class + cascade-layer override contract, markers, build, and migrating off Emotion/`useRecipe`. | diff --git a/.claude/skills/mosaic-stylex/SKILL.md b/.claude/skills/mosaic-stylex/SKILL.md new file mode 100644 index 00000000000..5227c3ec3b6 --- /dev/null +++ b/.claude/skills/mosaic-stylex/SKILL.md @@ -0,0 +1,130 @@ +--- +name: mosaic-stylex +description: >- + Author and organize StyleX styles for Mosaic components. Use when writing a + component's styles with `stylex.create` / `stylex.props`, defining or consuming + design tokens (`defineVars` / `defineConsts` / `createTheme`), exposing the + stable public styling contract (stable `.cl-*` classes, `--cl-*` CSS variables, + `data-*` attributes, cascade layers), setting up relational/state styling + (markers + `stylex.when`), wiring the build (rollup/tsdown plugin, layers, + ESLint), or migrating a Mosaic component off Emotion/`useRecipe` onto StyleX. + The direction: compile-time atomic CSS, a shipped static stylesheet, and + consumer overrides through their own CSS instead of the `appearance` prop. +--- + +# StyleX for Mosaic + +Mosaic is pivoting its styling engine from **Emotion** (runtime CSS-in-JS, +`useRecipe`/`appearance`) to **StyleX** (compile-time atomic CSS, a shipped +static stylesheet). This skill is the how-to for authoring StyleX the Mosaic +way. It is grounded in two sources: + +- The **astryx** design system (`../research/astryx`, ~350 `.stylex.ts` files) — + a mature, production StyleX design system. Its patterns are the reference. +- The Clerk **mosaic-x POC** (`packages/ui/src/mosaic-x/`, PR #9189) and its + writeup `references/mosaic-stylex-migration.md` — the proven direction for + _this_ repo. + +## The contract we are building toward + +Four public-surface goals drive every decision. Consumers style Mosaic from +**their own CSS**, never from an `appearance` prop: + +1. **Stable CSS variables** — `--cl-foreground`, `--cl-primary`, … default in + our sheet and a consumer overrides them with plain `:root { --cl-foreground: red }`. +2. **Stable class names** — every button carries `.cl-button`; a consumer targets + `.cl-button { … }` in their CSS. +3. **Stable data attributes** — variant/state reflected as `data-variant`, + `data-size`, etc. for scoped targeting (`.cl-button[data-variant='outline']`). +4. **A shipped static stylesheet** (`mosaic.css`) imported once into a cascade + layer the consumer controls. + +StyleX gives us goals 1, 3, 4 natively. Goal 2 (stable classes) needs a specific +technique — you attach your own plain `.cl-*` class alongside StyleX's atomic +classes. See `references/overrides.md`. + +## The core authoring shape + +Every styled part follows the same three moves. Read this, then the references. + +```tsx +import * as stylex from '@stylexjs/stylex'; +import { mergeProps, themeProps } from '../shared/naming'; // cl-* stable class + data-attr helpers +import { colors, radius, space } from './tokens.stylex'; + +// 1. stylex.create — base + each variant VALUE as its own style object. +// Variants are COMPOSED conditionally, not resolved by a recipe engine. +const styles = stylex.create({ + base: { + display: 'inline-flex', + borderRadius: radius['--cl-radius-md'], + // states live inside property values as { default, ':hover', … } — never as top-level keys + outline: { default: 'none', ':focus-visible': `2px solid ${colors['--cl-primary']}` }, + }, + filledPrimary: { backgroundColor: colors['--cl-primary'], color: colors['--cl-primary-foreground'] }, + outline: { backgroundColor: 'transparent', borderColor: colors['--cl-border'] }, + sizeSm: { paddingBlock: space['--cl-spacing'], fontSize: '0.75rem' }, + disabled: { opacity: 0.5, cursor: 'not-allowed', pointerEvents: 'none' }, +}); + +// 2. Infer props; provide variant defaults. +export interface ButtonProps extends React.ComponentPropsWithRef<'button'> { + variant?: 'filled' | 'outline'; + size?: 'sm' | 'md'; +} + +// 3. Compose in stylex.props(...); merge the stable class + data-attrs first, +// consumer className/style last (they win). +export const Button = ({ variant = 'filled', size = 'md', disabled, className, style, ...rest }: ButtonProps) => ( +