diff --git a/.changeset/upset-loops-enjoy.md b/.changeset/upset-loops-enjoy.md new file mode 100644 index 00000000000..a845151cc84 --- /dev/null +++ b/.changeset/upset-loops-enjoy.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/.cursor/rules/clerk-ui-theming.mdc b/.cursor/rules/clerk-ui-theming.mdc new file mode 100644 index 00000000000..a02f013f1cf --- /dev/null +++ b/.cursor/rules/clerk-ui-theming.mdc @@ -0,0 +1,598 @@ +--- +description: Styling and theming architecture for @clerk/ui package +globs: packages/ui/src/**/*.ts,packages/ui/src/**/*.tsx +alwaysApply: false +--- +# @clerk/ui Styling and Theming Architecture + +This document describes the complete styling and theming system for the `@clerk/ui` package - an internal package containing UI components for Clerk frontend SDKs. + +## Architecture Overview + +```mermaid +flowchart TD + AppConfig[Appearance Configuration] --> AppearanceProvider + AppearanceProvider --> parseAppearance + parseAppearance --> ParsedElements + parseAppearance --> ParsedInternalTheme + parseAppearance --> ParsedOptions + + ParsedInternalTheme --> InternalThemeProvider + InternalThemeProvider --> EmotionThemeProvider[Emotion ThemeProvider] + + ParsedElements --> makeCustomizable + makeCustomizable --> Primitives + + Primitives --> createVariants + createVariants --> FinalStyles[Final CSS Styles] + + subgraph ThemeSources[Theme Sources] + BaseTheme[baseTheme] + PrebuiltThemes[Prebuilt Themes: dark, shadcn, neobrutalism] + UserTheme[User Appearance Config] + end + + ThemeSources --> AppConfig +``` + +## Core Concepts + +### 1. Internal Theme (Design Tokens) + +The internal theme is a strongly-typed design token system defined in `packages/ui/src/foundations/`. + +**Key Files:** +- `packages/ui/src/foundations/defaultFoundations.ts` - Combines all foundation modules +- `packages/ui/src/foundations/colors.ts` - Color scales with light-dark support +- `packages/ui/src/foundations/sizes.ts` - Spacing, sizes, and border radius +- `packages/ui/src/foundations/shadows.ts` - Shadow definitions +- `packages/ui/src/foundations/typography.ts` - Font scales + +**Token Structure:** + +```typescript +const defaultInternalThemeFoundations = { + colors, // Primary, danger, success, warning + alpha scales + fonts, // Font family definitions + fontSizes, // xs, sm, md, lg, xl scale + fontWeights, // normal, medium, semibold, bold + radii, // none, sm, md, lg, xl, circle + sizes, // Static spacing values + space, // Dynamic spacing with CSS variables + shadows, // Menu, card, button, input shadows + // ... transitions, borders, zIndices, opacity +}; +``` + +**Token Access Pattern:** + +```typescript +// Tokens are prefixed with $ for type safety +theme.colors.$primary500 +theme.space.$4 +theme.radii.$md +theme.shadows.$cardBoxShadow +``` + +### 2. Appearance API (Public) + +Users configure theming via the `Appearance` type defined in `packages/ui/src/internal/appearance.ts`. + +**Three Customization Layers:** + +```typescript +interface Theme { + theme?: BaseTheme | BaseTheme[]; // Base theme(s) + variables?: Variables; // Design token overrides + elements?: Elements; // Per-element CSS overrides + options?: Options; // Layout/behavior options +} +``` + +**Variables (Design Tokens):** + +```typescript +interface Variables { + colorPrimary?: CssColorOrScale; // Brand color + colorPrimaryForeground?: CssColor; // Text on primary + colorDanger?: CssColorOrScale; // Error states + colorSuccess?: CssColorOrScale; // Success states + colorWarning?: CssColorOrScale; // Warning states + colorNeutral?: CssColorOrAlphaScale;// Borders, backgrounds + colorBackground?: CssColor; // Card background + colorForeground?: CssColor; // Default text + colorInput?: CssColor; // Input background + fontFamily?: FontFamily; // Main font + fontSize?: CssLengthUnit | FontSizeScale; + fontWeight?: FontWeightScale; + borderRadius?: CssLengthUnit; // Base radius + spacing?: CssLengthUnit; // Base spacing unit +} +``` + +### 3. Element Descriptors + +Element descriptors are the foundation of per-element styling. Defined in `packages/ui/src/customizables/elementDescriptors.ts`. + +**How Descriptors Work:** + +```typescript +// Descriptor creates targettable classnames +const descriptor = descriptors.button; +// -> { targettableClassname: 'cl-button', objectKey: 'button', ... } + +// Usage in components + +// Generates: class="cl-button" + +// With ID + +// Generates: class="cl-socialButtonsIconButton cl-socialButtonsIconButton__google" +``` + +**State Classes (automatic):** + +```typescript + +// Generates: class="cl-button cl-loading" +``` + +Available states: `loading`, `error`, `open`, `active` + +**Element Descriptor Structure:** + +```typescript +type ElementDescriptor = { + targettableClassname: TargettableClassname; // e.g., 'cl-button' + objectKey: ElementObjectKey; // e.g., 'button' + getTargettableIdClassname: (params: { id: AllowedIds }) => string; + getObjectKeyWithState: (state: AllowedStates) => ObjectKeyWithState; + getObjectKeyWithId: (id: ElementId>) => ObjectKeyWithIds; + getObjectKeyWithIdAndState: (id: ElementId>, state: AllowedStates) => ObjectKeyWithIdAndState; + setId: >(id?: Id) => ElementId | undefined; +}; +``` + +### 4. Styled System + +#### createVariants + +The `createVariants` function (`packages/ui/src/styledSystem/createVariants.ts`) creates type-safe variant-based styling: + +```typescript +const { applyVariants } = createVariants((theme) => ({ + base: { boxSizing: 'border-box' }, + variants: { + size: { + sm: { padding: theme.space.$2 }, + md: { padding: theme.space.$4 }, + }, + color: { + primary: { backgroundColor: theme.colors.$primary500 }, + danger: { backgroundColor: theme.colors.$danger500 }, + }, + }, + defaultVariants: { size: 'md', color: 'primary' }, + compoundVariants: [ + { condition: { size: 'sm', color: 'danger' }, styles: { border: '2px solid red' } } + ], +})); + +// Usage +