# Stratum — llms.txt > Stratum is a copy-paste atomic design system for React Native (Expo). > Paste this file into your AI tool to get idiomatic, type-correct Stratum code on the first try. --- ## What Is Stratum? Stratum is an atomic design system for React Native with: - **Unistyles 3.0** — zero-re-render theme switching via typed TypeScript style sheets - **Three built-in themes** — Slate (Wealthsimple-inspired), Obsidian (Gumroad-inspired), Quartz (Go Club-inspired) - **Atomic Design layers** — Tokens → Atoms → Molecules → Organisms → Templates → Screens - **TypeScript throughout** — every prop, token, and theme value is typed - **Copy-paste ownership** — components live in your repo; no black-box dependency --- ## Hard Rules (never violate these) 1. **Never hardcode values.** No hex colors, pixel sizes, or font sizes inline. Always use `theme.*` tokens. 2. **Import components from `@/components`.** Import raw token values from `@/tokens`. 3. **Access the theme via `useTheme()`.** Never reach into theme files directly. 4. **Don't skip atomic layers.** A screen uses templates → organisms → molecules → atoms. Never put atoms directly in a screen unless that layer is trivially simple. 5. **Use `` instead of `` for themed backgrounds.** Surface handles BlurView on Quartz automatically. 6. **FormField owns its own error state.** Pass `errorMessage` to FormField; never set `isError` on the wrapped Input separately. 7. **Never import from the palette (`colors.ts`) in components.** Use `theme.colors.*` semantic slots only. 8. **`` always needs `accessibilityLabel`.** It is required by the type system. --- ## File Structure ``` src/ ├── tokens/ # Design tokens — import raw values from here │ ├── spacing.ts # 4px grid: xs(4) sm(8) md(16) lg(24) xl(32) 2xl(48) 3xl(64) │ ├── typography.ts # fontSizes, fontWeights, lineHeights, letterSpacings │ ├── radii.ts # borderRadius scale │ ├── shadows.ts # shadow presets │ ├── borders.ts # border widths │ ├── theme-protocol.ts # AppTheme interface │ └── themes/ │ ├── registry.ts # THEME_REGISTRY — single source of truth │ ├── createTheme.ts # createTheme(base, overrides) deep-merge utility │ ├── slate.ts # High-contrast B&W, pill buttons, soft shadows │ ├── obsidian.ts # Warm off-white, zero radii, thick borders, offset shadows │ └── quartz.ts # Electric blue, glass blur, aggressive opacity ├── providers/ │ ├── ThemeProvider.tsx # Wrap your app in this │ └── unistyles.ts # Auto-derived from THEME_REGISTRY ├── hooks/ │ ├── useTheme.ts # const theme = useTheme() — access active theme │ └── useThemeToggle.ts # const { themeName, setTheme, toggleColorScheme } = useThemeToggle() ├── components/ │ ├── 1-atoms/ # Text, Heading, Icon, Surface, Button, IconButton, Input, │ │ # TextArea, Checkbox, Switch, Radio, Slider, Card, Chip, Badge │ ├── 2-molecules/ # FormField, SearchBar, SettingsRow, ListItem, ToggleRow, TagInput │ ├── 3-organisms/ # TopNavBar, AuthForm, SettingsGroup, ListSection │ └── 4-templates/ # AuthLayout, SettingsLayout └── screens/ # LoginScreen, SettingsScreen ``` --- ## Tokens Reference ```ts import { spacing, fontSizes, fontWeights, lineHeights, letterSpacings } from '@/tokens'; // Spacing — 4px grid spacing.xs // 4 spacing.sm // 8 spacing.md // 16 spacing.lg // 24 spacing.xl // 32 spacing['2xl'] // 48 spacing['3xl'] // 64 // Font sizes fontSizes.xs // 11 fontSizes.sm // 13 fontSizes.md // 15 fontSizes.lg // 17 fontSizes.xl // 20 fontSizes['2xl'] // 24 fontSizes['3xl'] // 30 // Font weights (string literals for RN) fontWeights.regular // '400' fontWeights.medium // '500' fontWeights.semibold // '600' fontWeights.bold // '700' // Line heights (multipliers — multiply by font size) lineHeights.tight // 1.2 lineHeights.normal // 1.4 lineHeights.relaxed // 1.6 ``` --- ## Theme Protocol (AppTheme) ```ts // Access via: const theme = useTheme() theme.colors.background // page background theme.colors.surface // card / panel background theme.colors.surfaceRaised // elevated surface (above surface) theme.colors.textPrimary // main body text theme.colors.textSecondary // secondary text (less emphasis) theme.colors.textMuted // placeholder, labels, captions theme.colors.textInverse // text on dark backgrounds theme.colors.textOnAccent // text on accent-coloured backgrounds theme.colors.accent // primary brand color theme.colors.accentHover // darker accent for press states theme.colors.accentSubtle // very light accent tint (chips, badges, pills) theme.colors.success // success signal color theme.colors.successSubtle // light success tint theme.colors.warning // warning signal color theme.colors.warningSubtle // light warning tint theme.colors.error // error / destructive color theme.colors.errorSubtle // light error tint theme.colors.border // default divider / input border theme.colors.borderStrong // emphasized border theme.colors.borderSubtle // very light separator theme.colors.overlay // modal scrim theme.radius.none // 0 theme.radius.sm // 4 (Slate/Quartz) | 0 (Obsidian) theme.radius.md // 8 | 0 theme.radius.lg // 12 | 0 theme.radius.xl // 16 | 0 theme.radius.full // 9999 (pill) theme.border.thin // 1 (Slate/Quartz) | 2 (Obsidian) theme.border.medium // 2 | 3 theme.border.strong // 3 | 4 theme.shadow.none // no shadow theme.shadow.sm // subtle elevation theme.shadow.md // card elevation theme.shadow.lg // modal / sheet elevation theme.iconWeight // 'regular' (Slate) | 'bold' (Obsidian) | 'light' (Quartz) theme.buttonShape // 'pill' (Slate/Quartz) | 'default' (Obsidian) theme.typography.fontFamily.heading // platform default or custom theme.typography.fontFamily.body theme.typography.fontFamily.mono ``` --- ## Component APIs ### Text ```tsx import { Text } from '@/components'; // Types type TextVariant = 'body' | 'caption' | 'label'; type TextSize = 'xs' | 'sm' | 'md' | 'lg'; type TextWeight = 'regular' | 'medium' | 'semibold' | 'bold'; type TextColor = 'primary' | 'secondary' | 'muted' | 'accent' | 'inverse' | 'onAccent'; // Props: variant?, size?, weight?, color?, children, numberOfLines?, style? Main content Timestamp · 3 min ago See all ``` Variant defaults: `body` → md/regular, `caption` → xs/regular, `label` → sm/medium. --- ### Heading ```tsx import { Heading } from '@/components'; // Props: level (1|2|3|4), style? Screen Title Section Header Card Title Subsection ``` --- ### Icon ```tsx import { Icon } from '@/components'; import { House, Bell, Gear } from 'phosphor-react-native'; // Types type IconSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl'; type IconColor = 'primary' | 'secondary' | 'muted' | 'accent' | 'inverse' | 'onAccent' | 'success' | 'warning' | 'error'; type IconWeight = 'thin' | 'light' | 'regular' | 'bold' | 'fill' | 'duotone'; // Props: icon (required), size?, color?, weight?, accessibilityLabel?, testID? // Leave weight unset to use theme.iconWeight — icons feel native to the theme ``` --- ### Surface ```tsx import { Surface } from '@/components'; // Props: elevation?, padding?, radius?, border?, children // On Quartz: renders BlurView when theme.effects.blurIntensity > 0 // On Slate/Obsidian: plain themed View {children} ``` --- ### Button ```tsx import { Button } from '@/components'; // Types type ButtonVariant = 'primary' | 'secondary' | 'ghost' | 'destructive'; type ButtonSize = 'sm' | 'md' | 'lg'; type ButtonShape = 'default' | 'pill'; // Props: variant?, size?, shape?, isElevated?, isLoading?, isDisabled?, onPress?, children // Rules: // - One primary button per screen // - destructive only for irreversible actions (delete, remove, not logout) // - ghost for low-emphasis actions (skip, dismiss, see more) // - Omit shape to use theme.buttonShape (pill for Slate/Quartz, default for Obsidian) ``` --- ### IconButton ```tsx import { IconButton } from '@/components'; import { ArrowLeft, X, MagnifyingGlass } from 'phosphor-react-native'; // Props: icon (required), accessibilityLabel (required), variant?, size?, shape?, isElevated?, isDisabled?, onPress? ``` --- ### Input ```tsx import { Input } from '@/components'; // Types type InputShape = 'default' | 'pill'; // Props: value, onChangeText, placeholder?, isError?, isDisabled?, shape?, // keyboardType?, autoCapitalize?, secureTextEntry?, returnKeyType?, // onSubmitEditing?, onFocus?, onBlur? // Use FormField (not bare Input) in forms — FormField adds label + error handling ``` --- ### TextArea ```tsx import { TextArea } from '@/components'; // Props: value, onChangeText, placeholder?, numberOfLines?, isError?, isDisabled?, shape?