# ThemeKit

> A token-driven, **brand-neutral** SwiftUI design system — **246 components** (52 atoms · 110 molecules · 84 organisms), **34 theme presets**, **217 design tokens**, runtime theming, and an AI-native toolchain (MCP server + agent skill + Figma round-trip). Every color, radius, spacing, type style and shadow is a design token resolved at runtime from the active `Theme`; **components never hardcode a color**, so the whole UI re-skins from a single accent color. Swift 6.2 · iOS 17+ / macOS 14+ · zero core dependencies.

This is the quick-reference index. Deeper files:
- **llms-full.txt** — architecture, token deep-dive, code-generation rules, patterns, integration.
- **llms-components.txt** — every component's init + modifiers + usage snippet.
- **llms-patterns.txt** — recipes (custom themes, per-subtree theming, custom styles, forms…).

## Philosophy

1. **Token-driven.** No literal colors/radii/spacings in UI — only tokens from the active `Theme`.
2. **Brand-neutral.** One accent hex generates a full palette on-device (`ThemeGenerator`).
3. **Composable & chainable.** Required content/bindings in `init`; everything else a modifier.
4. **AI-native.** The same data drives an MCP server (22 tools), an agent skill, and Figma round-trip.

## Rules for generating ThemeKit code (critical)

1. **Never hardcode a color.** No `.foregroundStyle(.blue)` / `Color(hex:)`. Use `theme.text(.textPrimary)`, `theme.background(.bgWhite)`, or a `SemanticColor`.
2. **Read the theme from the environment:** `@Environment(\.theme) private var theme` (defaults to `Theme.shared`). **Inject once at the root:** `.environment(Theme.shared)`.
3. **Required content/bindings/actions in `init`;** variants/sizes/flags/colors/callbacks are **chainable modifiers** — `Badge("New").badgeStyle(.info).badgeShape(.rounded)`.
4. **Sizes** use `.controlSize(_:)`; **disabled** uses `.disabled(_:)` (native, universal). Never `size:` / `isEnabled:` init args. Many components also expose `.a11yID(_:)` — check the component's modifier list; where absent use SwiftUI's `.accessibilityIdentifier(_:)`.
5. **No hardcoded radius/spacing.** Use `Theme.RadiusRole.box.value` / `Theme.SpacingKey.md.value`.
6. **Recolor** with `Theme.shared.applyGenerated(primaryHex:)` or `ThemePreset.named("dracula")?.apply()`. Scope to one subtree with `.theme(customTheme)`.
7. **Don't re-implement** a Card / Sheet / Toast / field — use the existing component.

## Token system (resolved from the active `Theme`)

- **Text** `theme.text(_:)` — `.textPrimary .textSecondary .textTertiary .textDisabled .textHero .textPurple .textSecondaryInverse`
- **Surfaces** `theme.background(_:)` — `.bgWhite` (default surface) `.bgHero .bgElevatorPrimary .bgSecondary .bgTertiary` + system/badge tints (24 keys)
- **Borders** `theme.border(_:)` (12 keys) · **Foreground** `theme.foreground(_:)` (10 keys)
- **Semantic colors** `SemanticColor` — `.primary .secondary .accent .neutral .info .success .warning .error .turquoise .orange .purple .pink`; 50→900 shade ladder; pair with `FillVariant` (`.solid .soft .outline .ghost`).
- **Radius** — role: `Theme.RadiusRole.box|field|selector`; size: `Theme.RadiusKey.none|xs|sm|md|base|lg|xl|xl4` (`rd-xs`…`rd-4xl`).
- **Spacing** `Theme.SpacingKey.none|xs|sm|md|base|lg|xl|xl4` (`sp-xs`…`sp-4xl`).
- **Typography** `.textStyle(_:)` — 34 `TextStyle`s (Montserrat): Display, Heading (2xl→3xs), Label, Body, Overline, Link.
- **Shadows** `ShadowStyle.elevated|.tabBar|.soft`.

## Packages (SPM products)

- **ThemeKit** — full catalog (re-exports the core). `import ThemeKit`.
- **ThemeKitCore** — token engine only (tokens + `@Environment(\.theme)` + presets + generator), zero components, zero third-party deps.
- **ThemeKitLottie** — optional Lottie animations (behind the `Lottie` package trait).
- **ThemeKitCalendar** — optional token-bound calendar (behind the `Calendar` trait, iOS-only).

Default traits are **empty**, so a plain package reference resolves **zero** dependencies.

## Atoms (52)

`AnimatedImage`, `Aura`, `Avatar`, `AvatarGroup`, `Badge`, `Barcode`, `Chip`, `CloseButton`, `CodeBlock`, `ColorSwatch`, `Confetti`, `Ribbon`, `CountdownTimer`, `DescriptionModal`, `DividerView`, `FareFeatureRow`, `GaugeView`, `HelperText`, `Icon`, `IconTile`, `InlineText`, `InputLabel`, `Join`, `Kbd`, `PointsBadge`, `PriceTag`, `ProgressBar`, `StepIndicator`, `QRCode`, `RadialProgress`, `Rating`, `RemoteImage`, `RollingNumber`, `ScoreBadge`, `SearchBadge`, `ShareButton`, `Skeleton`, `SkeletonGroup`, `Spinner`, `StatusDot`, `SurfaceView`, `Swap`, `SwapButton`, `Tag`, `CheckableTag`, `TextLink`, `TextRotate`, `TiltCard`, `Title`, `TrendChip`, `FlightStatusBadge`, `SeatCell`

## Molecules (110)

`Affix`, `AmenityGrid`, `AnchorNav`, `Autocomplete`, `Breadcrumbs`, `ButtonGroup`, `PrimaryButton`, `SecondaryButton`, `OutlineButton`, `GhostButton`, `LinkButton`, `TertiaryButton`, `DangerButton`, `DangerSoftButton`, `ThemeButton`, `CalendarView`, `CalendarYearPicker`, `Cascader`, `AreaChart`, `BarChart`, `DonutChart`, `LineChart`, `Checkbox`, `CheckboxGroup`, `ImageChip`, `CompactChip`, `ChoseChip`, `FilterChip`, `ChipGroup`, `ColorArea`, `ColorField`, `ColorSlider`, `ColorSwatchPicker`, `ColumnsGrid`, `ControlRow`, `CurrencyPicker`, `DateField`, `Dropdown`, `EmojiReactionButton`, `FieldButton`, `Fieldset`, `FileInput`, `FilterGroup`, `FilterRow`, `Flex`, `FlowLayout`, `GuestSelector`, `InputAffix`, `InputGroup`, `InputNumber`, `InstallmentPicker`, `InstallmentSelector`, `LanguageSwitcher`, `MapPriceMarker`, `Masonry`, `Mentions`, `MultiLineTextInput`, `MultiSelect`, `OTPInput`, `Pagination`, `PaymentCardField`, `PhoneField`, `PriceBreakdown`, `PriceHistogram`, `PriceTrendChart`, `ProgressIndicator`, `QuantityStepper`, `RadioButton`, `RadioGroup`, `RadioButtonGroup`, `RangeSlider`, `ScrollShadow`, `ScrubGallery`, `SearchBar`, `SearchField`, `SearchSummary`, `SegmentedControl`, `Select`, `SelectBox`, `Slider`, `SmartSuggestion`, `SortTab`, `SortSummaryBar`, `Space`, `Splitter`, `Stat`, `StepperRow`, `Steps`, `SuggestionRow`, `TableToggleCell`, `TableSelectCell`, `TableSliderCell`, `TableColorCell`, `TextInput`, `ThemeController`, `ThemeToggle`, `TimeField`, `ToggleGroup`, `Transfer`, `TreeSelect`, `TreeView`, `CabinClassSelector`, `DatePriceCard`, `DatePriceStrip`, `FlightRoute`, `LayoverRow`, `PassengerRow`, `RecentSearchRow`, `SeatLegend`, `TripTypeToggle`

## Organisms (84)

`Accordion`, `AccordionGroup`, `ActionBar`, `Agenda`, `AgentPriceRow`, `AlertHeader`, `AlertFooter`, `AlertDialog`, `AlertToast`, `BlogCard`, `BrowserFrame`, `Callout`, `Card`, `CardStack`, `Carousel`, `ChatBubble`, `ColorPickerPanel`, `Counter`, `Coupon`, `DataTable`, `DestinationCard`, `Diff`, `Drawer`, `EmptyState`, `FilterList`, `FloatingActionButton`, `Footer`, `Gallery`, `Hero`, `HeroSurface`, `HotelResultCard`, `ImageCollage`, `InfoBanner`, `KanbanBoard`, `KeyValueTable`, `ListRow`, `ListSectionHeader`, `ListView`, `LocationCard`, `LoyaltyCard`, `MapCallout`, `MenuCard`, `NavigationBar`, `NotificationCard`, `PageHeader`, `PagingCarousel`, `PhoneFrame`, `PriceAlertCard`, `PromoBanner`, `RatingSummary`, `ResultView`, `ReviewCard`, `RoomCard`, `SegmentedTabBar`, `RadioCard`, `CheckboxCard`, `SheetHeader`, `Sidebar`, `ThemePicker`, `TicketStub`, `Timeline`, `Upload`, `UploadList`, `VideoPlayerView`, `WindowFrame`, `AirportPicker`, `AncillaryCard`, `BoardingPass`, `CheckInFlow`, `FareFamilyCard`, `FareSummary`, `FilterBar`, `FlightCard`, `FlightListItem`, `FlightResultRow`, `FlightTicketCard`, `FlightTracker`, `PassengerForm`, `PaymentMethodSelector`, `SavedCardsList`, `SeatMap`, `StickyBookingBar`, `TransportCrossSellCard`, `TripSearchCard`

## Style protocols (flexibility architecture)

Six component families are style-driven (`ButtonStyle`-shaped — a `Configuration` + `makeBody`):
- `CardStyle` → `.cardStyle(_:)` — cards. Built-ins `.default`, `.outlined`.
- `FieldStyle` → `.fieldStyle(_:)` — text fields. Built-ins `.default`, `.muted`, `.underlined`.
- `ChipStyle` → chips. Built-ins `.tonal`, `.solid`.
- `BarStyle` → `.barStyle(_:)` — bottom/booking bars. Built-ins `.default`, `.floating`.
- `MeterStyle` → `.meterStyle(_:)` — progress/meters. Built-ins `.linear`, `.striped`, `.radial`.
- `ToastStyle` → `.toastStyle(_:)` — toasts. Built-ins `.default`, `.capsule`.

## Chainable modifiers

`.a11yID()` `.a11yLabel()` `.accent()` `.accessory()` `.action()` `.actionButton()` `.actions()` `.adaptive()` `.addLeg()` `.added()` `.addons()` `.adultRange()` `.airline()` `.airlineIcon()` `.airlineLogo()` `.airports()` `.aisleWidth()` `.alertCount()` `.align()` `.alignment()` `.allowClear()` `.allowHalf()` `.allowsCustomTags()` `.altText()` `.amenities()` `.animatesValue()` `.arrow()` `.arrows()` `.aspect()` `.autocorrectionDisabled()` `.autoplay()` `.autosize()` `.avatar()` `.axis()` `.backButton()` `.backTitle()` `.background()` `.badge()` `.badgeColor()` `.badgeShape()` `.badgeStyle()` `.badgeVariant()` `.baggage()` `.barHeight()` `.barWidth()` `.barcode()` `.bezel()` `.birthDateRange()` `.block()` `.board()` `.bookingRef()` `.bookmark()` `.borderColor()` `.bordered()` `.bounds()` `.boxed()` `.brandLogo()` `.buttonSize()` `.buttonTitle()` `.cabin()` `.calloutStyle()` `.canAdvance()` `.cascade()` `.changeOnSelect()` `.characterLimit()` `.characters()` `.cheapest()` `.cheapestTone()` `.checkable()` `.childRange()` `.children()` `.chipColors()` `.chipStyle()` `.chipSurface()` `.chipVariant()` `.chipsWrap()` `.circle()` `.cities()` `.cityNames()` `.classes()` `.clearable()` `.closable()` `.code()` `.codeSize()` `.collapsible()` `.color()` `.colors()` `.columnWidth()` `.columns()` `.compact()` `.components()` `.confirmsSuccess()` `.content()` `.contentMode()` `.contentPadding()` `.control()` `.controlPlacement()` `.controlSurface()` `.copyable()` `.cornerRadius()` `.count()` `.countLabel()` `.countStyle()` `.couponStyle()` `.cta()` `.ctaIcon()` `.ctaTitle()` `.currency()` `.current()` `.curved()` `.customInner()` `.customSize()` `.dark()` `.dashColor()` `.dashboard()` `.dashed()` `.date()` `.dateRange()` `.dates()` `.deal()` `.debounce()` `.deckLabel()` `.deleteStyle()` `.density()` `.departures()` `.description()` `.details()` `.detailsLayout()` `.detents()` `.dialCodes()` `.digitCount()` `.dimension()` `.direction()` `.directions()` `.disabledDates()` `.disabledMethods()` `.discount()` `.discountBadge()` `.distance()` `.divider()` `.dividerColor()` `.dividers()` `.dockLayout()` `.documentRequired()` `.doneTitle()` `.dots()` `.duration()` `.durationText()` `.edge()` `.editable()` `.elevation()` `.emphasis()` `.emptyText()` `.enabled()` `.entry()` `.errorText()` `.excerpt()` `.exists()` `.expandable()` `.expanded()` `.expands()` `.expiredBadge()` `.expiry()` `.externalFocus()` `.extra()` `.extraAction()` `.extraDiscount()` `.eyebrow()` `.fade()` `.fadeColor()` `.fareBrand()` `.fares()` `.favorite()` `.features()` `.fieldIcons()` `.fields()` `.fileName()` `.fill()` `.fillColor()` `.filter()` `.filterSort()` `.firstWeekday()` `.flagsExpired()` `.flightNo()` `.flippable()` `.focused()` `.footer()` `.footerLayout()` `.footerPadding()` `.format()` `.formatsNumber()` `.formatter()` `.fractionDigits()` `.free()` `.from()` `.fullWidth()` `.fuselage()` `.fuselageSurface()` `.gap()` `.gapSpaced()` `.gate()` `.gaugeStyle()` `.genders()` `.glyph()` `.gradient()` `.groupStyle()` `.groups()` `.gutter()` `.hasError()` `.hasInfo()` `.header()` `.headerAlignment()` `.headerPadding()` `.height()` `.helper()` `.helperText()` `.hidesOnError()` `.highlight()` `.highlightCheapest()` `.highlighted()` `.hint()` `.holder()` `.hourCycle()` `.icon()` `.iconBackground()` `.iconCircleSize()` `.iconColor()` `.iconForeground()` `.iconOnly()` `.iconSize()` `.iconTile()` `.icons()` `.image()` `.imageHeight()` `.imageMaxHeight()` `.imageURL()` `.images()` `.indeterminate()` `.indicator()` `.infantRange()` `.infoMessages()` `.infoTooltip()` `.infos()` `.inlineStyle()` `.innerRadius()` `.inputs()` `.installments()` `.intensity()` `.interactive()` `.interestFreeUpTo()` `.interval()` `.itemDisabled()` `.itemEnabled()` `.jumper()` `.justify()` `.keyboard()` `.label()` `.labelPlacement()` `.large()` `.layout()` `.layoverLabel()` `.leading()` `.leadingIcon()` `.leadingIconColor()` `.leadingImage()` `.leadingSelection()` `.leadingShape()` `.legend()` `.legendPlacement()` `.length()` `.level()` `.limit()` `.lineStyle()` `.lineThrough()` `.lineWidth()` `.links()` `.listHeight()` `.listType()` `.loading()` `.locale()` `.location()` `.logo()` `.loop()` `.mapFilter()` `.mapHeight()` `.marks()` `.maxAngle()` `.maxCount()` `.maxDays()` `.maxLength()` `.maxResults()` `.maxSelection()` `.maxTags()` `.maxTotal()` `.maxValue()` `.maxVisible()` `.memberName()` `.membership()` `.menuWidth()` `.message()` `.meta()` `.minHeight()` `.minuteInterval()` `.mode()` `.multilineTitle()` `.muteToggle()` `.muted()` `.nationalities()` `.nativeNames()` `.nearby()` `.nested()` `.nextDay()` `.nextTitle()` `.nodeEnabled()` `.notch()` `.notchRadius()` `.note()` `.number()` `.occupancy()` `.onAddNew()` `.onAirportQuery()` `.onBack()` `.onChange()` `.onChangeEnd()` `.onClear()` `.onClearAll()` `.onClose()` `.onCommit()` `.onComplete()` `.onDelete()` `.onDetails()` `.onDirections()` `.onDismiss()` `.onDownload()` `.onEdit()` `.onFilter()` `.onFinish()` `.onInfo()` `.onMore()` `.onPage()` `.onPhotoTap()` `.onPreview()` `.onPriceTap()` `.onQueryChange()` `.onRate()` `.onRemove()` `.onReviewTap()` `.onRowTap()` `.onSearch()` `.onSelect()` `.onSort()` `.onTap()` `.onValidation()` `.onValueChange()` `.optionContent()` `.optionDescription()` `.optionEnabled()` `.orientation()` `.original()` `.originalBelow()` `.overflowFade()` `.overlayTitle()` `.overline()` `.pageSize()` `.pageTransition()` `.palette()` `.passengerLabel()` `.passengerSheetDetents()` `.passengers()` `.pathColor()` `.peek()` `.peekOffset()` `.pending()` `.perRow()` `.perforation()` `.phaseTitles()` `.photos()` `.pieceCount()` `.pill()` `.pillSize()` `.placeholder()` `.placeholderColor()` `.placeholders()` `.plain()` `.pointer()` `.pois()` `.popular()` `.positiveIsUp()` `.precision()` `.prefix()` `.presence()` `.presentation()` `.price()` `.priceEmphasis()` `.priceFractionDigits()` `.primaryAction()` `.primaryButton()` `.primaryLoading()` `.progress()` `.progressContent()` `.progressDot()` `.progressLabel()` `.progressStyle()` `.promos()` `.prompt()` `.pulse()` `.pulses()` `.qr()` `.quantity()` `.radioStyle()` `.radius()` `.range()` `.rating()` `.ratio()` `.recent()` `.recents()` `.recommended()` `.removable()` `.required()` `.resend()` `.resultCount()` `.returnLeg()` `.reversed()` `.reviews()` `.reviewsSuffix()` `.ribbon()` `.ringColor()` `.roomRange()` `.rooms()` `.rotate()` `.rotation()` `.roundTrip()` `.rowContent()` `.scarcity()` `.score()` `.scrollAlign()` `.scrollable()` `.searchAccent()` `.searchField()` `.searchSummary()` `.searchable()` `.searchablePicker()` `.seat()` `.seatDisplay()` `.seatEnabled()` `.seatShape()` `.seatSize()` `.secondaryAction()` `.sectionHeader()` `.sectionTitles()` `.secure()` `.selectAll()` `.selectable()` `.selected()` `.selectedDeparture()` `.selectedFare()` `.selection()` `.selectionAccent()` `.selectionColor()` `.selectionColumn()` `.selectionMode()` `.selectionStyle()` `.sentiment()` `.separator()` `.shadow()` `.shape()` `.shine()` `.shouldCloseOnSelect()` `.showTitle()` `.showTotal()` `.showsAlpha()` `.showsAxis()` `.showsBounds()` `.showsCabinPicker()` `.showsCloseButton()` `.showsCount()` `.showsDayHeaders()` `.showsDays()` `.showsDivider()` `.showsDividers()` `.showsEstimates()` `.showsFacts()` `.showsFlags()` `.showsGlyphs()` `.showsGrid()` `.showsHandle()` `.showsHeader()` `.showsHexField()` `.showsIcon()` `.showsInfants()` `.showsLabel()` `.showsLabels()` `.showsLegend()` `.showsList()` `.showsName()` `.showsOccupied()` `.showsPageDots()` `.showsPercentage()` `.showsPoints()` `.showsPremium()` `.showsRemoveIcon()` `.showsRooms()` `.showsSeatInfo()` `.showsSelectAll()` `.showsSelected()` `.showsSeparator()` `.showsSeparators()` `.showsShadow()` `.showsSign()` `.showsStepper()` `.showsSwap()` `.showsTimeline()` `.showsTripType()` `.showsValue()` `.showsValueTooltip()` `.showsValues()` `.showsWeekday()` `.showsWeekdayHeader()` `.side()` `.simple()` `.size()` `.skeletonOnly()` `.sliceLabels()` `.small()` `.snapshot()` `.soldOut()` `.solid()` `.spacing()` `.spanMeters()` `.spinnerPlacement()` `.split()` `.stacked()` `.starSize()` `.stars()` `.status()` `.stay()` `.step()` `.stepText()` `.stepper()` `.stepperPlacement()` `.stepperSize()` `.steps()` `.stepsTappable()` `.stops()` `.stopsTone()` `.strip()` `.striped()` `.style()` `.subtitle()` `.subtitleStyle()` `.successSegment()` `.suffix()` `.suggestionEnabled()` `.suggestions()` `.summaryBar()` `.supportsOpacity()` `.surcharge()` `.surface()` `.swapActions()` `.swatchShape()` `.swatchSize()` `.swatches()` `.symbol()` `.symbols()` `.systemImage()` `.tabStyle()` `.tabs()` `.tagStyle()` `.tags()` `.tapToToggle()` `.target()` `.tearStyle()` `.textAlignment()` `.textStyle()` `.tierColors()` `.tiers()` `.tileSize()` `.time()` `.timelineSize()` `.times()` `.tint()` `.tinted()` `.title()` `.titleAlign()` `.titleSize()` `.titleStyle()` `.titleTextStyle()` `.titles()` `.tone()` `.totalEmphasis()` `.totalPrice()` `.totalSize()` `.track()` `.trackHeight()` `.trackSymbols()` `.trailing()` `.trailingIcon()` `.trend()` `.triggerIcon()` `.truncateSubtitle()` `.type()` `.underline()` `.unit()` `.unread()` `.updated()` `.urgency()` `.urgentBelow()` `.validate()` `.validator()` `.value()` `.valueFormat()` `.valueLabel()` `.variant()` `.verified()` `.vertical()` `.via()` `.videoProgress()` `.visibility()` `.warning()` `.warningText()` `.weight()` `.width()` `.window()` `.wrap()` `.yearPicker()` `.zoomable()`

## Theme presets

`default`, `neutral`, `light`, `dark`, `cupcake`, `bumblebee`, `emerald`, `corporate`, `synthwave`, `retro`, `cyberpunk`, `valentine`, `halloween`, `garden`, `forest`, `aqua`, `lofi`, `pastel`, `fantasy`, `wireframe`, `black`, `luxury`, `dracula`, `cmyk`, `autumn`, `business`, `acid`, `lemonade`, `night`, `coffee`, `winter`, `dim`, `nord`, `sunset`

```swift
ThemePreset.named("dracula")?.apply()            // recolor Theme.shared live
Theme.shared.applyGenerated(primaryHex: "7C3AED") // generate a full palette from one accent
ThemePicker(selection: $activeThemeID)            // tappable grid of all presets
```

## AI-native toolchain

- **MCP server** (`@isamercan/themekit-mcp`, 22 tools) — `list_components`, `get_component_api`, `get_design_tokens`, `get_usage_snippet`, `search_components`, `list_themes`, `generate_theme`, `lint_snippet`, `validate_code`, `a11y_audit`, `scaffold_screen`, `compose_screen`, `design_via_figma_mcp`, `export_figma_variables`, `import_figma_variables`, … (full list in llms-full.txt).
- **Agent skill** — `skills/themekit/SKILL.md` (idioms, setup, anti-patterns) + references.
- **Figma round-trip** — `export_figma_variables` / `import_figma_variables` and `design_via_figma_mcp`.

## Localization & accessibility

- **Strings:** bundled String Catalog, English default (`en`); every user-facing string is also overridable via an init/modifier parameter. Add your own localizations in-app.
- **Accessibility:** many components expose `.a11yID(_:)` / `.a11yLabel(_:)` (not global — use SwiftUI's `.accessibilityIdentifier(_:)` where a component lacks it); 44 pt touch targets and RTL-directional mirroring are built in.

## Links

- Docs — https://isamercan.github.io/ThemeKit/
- API reference (DocC) — https://isamercan.github.io/ThemeKit/api/documentation/themekit
- GitHub — https://github.com/isamercan/ThemeKit · Wiki — https://github.com/isamercan/ThemeKit/wiki
- MCP (npm) — https://www.npmjs.com/package/@isamercan/themekit-mcp
- Skill — [skills/themekit/SKILL.md](skills/themekit/SKILL.md) · Components ref — [skills/themekit/references/components.md](skills/themekit/references/components.md)
