360 lines
13 KiB
Markdown
360 lines
13 KiB
Markdown
---
|
|
source: ~/DuckDuckGo/apple-browsers.git/main/.cursor/rules/design-system-designresourceskit.mdc
|
|
confidence: 0.9
|
|
namespace: work
|
|
last_synced: 2026-04-28
|
|
alwaysApply: true
|
|
---
|
|
|
|
# DuckDuckGo iOS Design System & DesignResourcesKit (DRK)
|
|
|
|
## Overview
|
|
|
|
The DuckDuckGo iOS design system is implemented through **DesignResourcesKit (DRK)**, a shared Swift package that contains our design tokens, type styles, colors, and design system elements.
|
|
|
|
**Repository**: [https://github.com/duckduckgo/DesignResourcesKit](https://github.com/duckduckgo/DesignResourcesKit)
|
|
|
|
**Figma Designs**: [🖱️ iOS & iPadOS Components](https://www.figma.com/file/GzGKD6gR24AHoUqVykX1ah/%F0%9F%93%B1-iOS-%26-iPadOS-Components?type=design&node-id=3938%3A23329&mode=design&t=0fuiNF84nnV5zExC-1)
|
|
|
|
### What DRK Contains
|
|
|
|
✅ **Currently Included**:
|
|
- **Type styles and typography** (based on system styles)
|
|
- **Semantic color system** (with light/dark mode support)
|
|
- **Design tokens and foundations**
|
|
|
|
🔄 **Future Expansion**:
|
|
- **Reusable components** (when patterns emerge)
|
|
- **Advanced interaction patterns**
|
|
|
|
❌ **Not Included**:
|
|
- **Icons** (remain in iOS app directly for now)
|
|
|
|
## ⚠️ Critical Rule: Don't Break the Design System
|
|
|
|
> **If you take only one thing away from this documentation**:
|
|
> **Don't add new colors or type styles outside of the design system without reading the guidelines below.**
|
|
|
|
Breaking the design system:
|
|
- **Undermines consistency** across the app
|
|
- **Creates maintenance debt** with scattered styles
|
|
- **Breaks accessibility** features like dynamic type
|
|
- **Fragments the user experience**
|
|
|
|
## Typography System
|
|
|
|
### Philosophy
|
|
|
|
Our typography system is **based on system styles** rather than hardcoded sizes. This ensures:
|
|
- **Automatic dynamic type support** for accessibility
|
|
- **Consistent scaling** across different user preferences
|
|
- **Platform-appropriate styling** that feels native
|
|
|
|
### UIKit Usage
|
|
|
|
DRK defines **static functions on UIFont** for all typography.
|
|
|
|
**Example:** See [uikit-typography-usage.swift](design-system-designresourceskit/uikit-typography-usage.swift)
|
|
|
|
#### Available Typography Styles
|
|
|
|
**Example:** See [uikit-typography-styles.swift](design-system-designresourceskit/uikit-typography-styles.swift)
|
|
|
|
#### Best Practices for UIKit
|
|
|
|
**Example:** See [uikit-typography-best-practices.swift](design-system-designresourceskit/uikit-typography-best-practices.swift)
|
|
|
|
### SwiftUI Usage
|
|
|
|
DRK provides **view modifiers and extensions** for SwiftUI that should be used instead of direct font access.
|
|
|
|
**Example:** See [swiftui-typography-usage.swift](design-system-designresourceskit/swiftui-typography-usage.swift)
|
|
|
|
#### Available SwiftUI Typography Modifiers
|
|
|
|
**Example:** See [swiftui-typography-modifiers.swift](design-system-designresourceskit/swiftui-typography-modifiers.swift)
|
|
|
|
#### SwiftUI Code Review Guidelines
|
|
|
|
**When reviewing PRs**: Look for `.font()` usage as a red flag.
|
|
|
|
**Example:** See [swiftui-code-review-red-flags.swift](design-system-designresourceskit/swiftui-code-review-red-flags.swift)
|
|
|
|
### Emergency Escape Hatch (Avoid!)
|
|
|
|
**For legacy layout fixes only**: If you absolutely must disable dynamic type, there's a deliberately obtusely named function:
|
|
|
|
```swift
|
|
// ❌ LAST RESORT: Only for fixing legacy layouts
|
|
let fixedFont = UIFont.daxFontOutsideOfTheDesignSystemToFixLegacyLayoutBreakage()
|
|
```
|
|
|
|
**Important Notes**:
|
|
- This function **may not exist** in current DRK versions
|
|
- If you need it, you must **revert the commit** that removed it: [Commit 971979d](https://github.com/duckduckgo/DesignResourcesKit/pull/1/commits/971979d3dcd95567b9812b800eb22ab1611ce3a5)
|
|
- This is **deliberately annoying** to discourage usage
|
|
- **Always prefer** fixing the layout to support dynamic type instead
|
|
|
|
## Color System
|
|
|
|
### Semantic Color Approach
|
|
|
|
Our color system uses **semantic naming** rather than literal colors (e.g., "primary text" instead of "black"). This enables:
|
|
- **Automatic dark mode support**
|
|
- **Future theme flexibility**
|
|
- **Accessibility compliance**
|
|
- **Consistent visual hierarchy**
|
|
|
|
### Color Categories
|
|
|
|
#### Text Colors
|
|
**UIKit Example:** See [colors-text-uikit.swift](design-system-designresourceskit/colors-text-uikit.swift)
|
|
|
|
**SwiftUI Example:** See [colors-text-swiftui.swift](design-system-designresourceskit/colors-text-swiftui.swift)
|
|
|
|
#### Background Colors
|
|
**Example:** See [colors-background.swift](design-system-designresourceskit/colors-background.swift)
|
|
|
|
#### Control Colors
|
|
```swift
|
|
// UIKit
|
|
button.backgroundColor = UIColor(designSystemColor: .controlsFillPrimary)
|
|
button.backgroundColor = UIColor(designSystemColor: .controlsFillSecondary)
|
|
|
|
// SwiftUI
|
|
Button("Action") { }
|
|
.foregroundColor(Color(designSystemColor: .controlsFillPrimary))
|
|
.background(Color(designSystemColor: .controlsFillSecondary))
|
|
```
|
|
|
|
#### Button-Specific Colors
|
|
```swift
|
|
// UIKit
|
|
primaryButton.backgroundColor = UIColor(designSystemColor: .buttonPrimaryBackground)
|
|
primaryButton.setTitleColor(UIColor(designSystemColor: .buttonPrimaryText), for: .normal)
|
|
|
|
secondaryButton.backgroundColor = UIColor(designSystemColor: .buttonSecondaryBackground)
|
|
secondaryButton.setTitleColor(UIColor(designSystemColor: .buttonSecondaryText), for: .normal)
|
|
|
|
// SwiftUI
|
|
Button("Primary Action") { }
|
|
.foregroundColor(Color(designSystemColor: .buttonPrimaryText))
|
|
.background(Color(designSystemColor: .buttonPrimaryBackground))
|
|
|
|
Button("Secondary Action") { }
|
|
.foregroundColor(Color(designSystemColor: .buttonSecondaryText))
|
|
.background(Color(designSystemColor: .buttonSecondaryBackground))
|
|
```
|
|
|
|
#### Accent Colors
|
|
```swift
|
|
// UIKit
|
|
view.tintColor = UIColor(designSystemColor: .accent)
|
|
|
|
// SwiftUI
|
|
Image(systemName: "heart.fill")
|
|
.foregroundColor(Color(designSystemColor: .accent))
|
|
```
|
|
|
|
### Anti-patterns: What NOT to Do
|
|
|
|
**Example:** See [colors-anti-patterns.swift](design-system-designresourceskit/colors-anti-patterns.swift)
|
|
|
|
## Enforcement and Code Review
|
|
|
|
### Automated Enforcement
|
|
|
|
#### Danger Integration
|
|
**Asset catalog enforcement**: We use [Danger](https://danger.systems/) to prevent new colors being added directly to iOS app asset catalogs.
|
|
|
|
**Example:** See [danger-integration.rb](design-system-designresourceskit/danger-integration.rb)
|
|
|
|
### Manual Code Review Checklist
|
|
|
|
#### ✅ Look for in PRs:
|
|
- **DRK typography usage**: `UIFont.daxTitle1()`, `.daxBody()` modifiers
|
|
- **DRK color usage**: `UIColor(designSystemColor: .textPrimary)`
|
|
- **No hardcoded colors**: No hex values, RGB tuples, or named colors
|
|
- **No `.font()` modifiers** in SwiftUI (red flag for design system violations)
|
|
- **Semantic naming**: Colors described by purpose, not appearance
|
|
|
|
#### Code Review Examples
|
|
|
|
**Example:** See [code-review-checklist.swift](design-system-designresourceskit/code-review-checklist.swift)
|
|
|
|
### Opportunistic Improvements
|
|
|
|
**Most of the iOS app currently does not use the design system**, so you're encouraged to:
|
|
|
|
1. **Opportunistically refactor** old code to use DRK when you encounter it
|
|
2. **Update hardcoded colors** to semantic colors when working in an area
|
|
3. **Replace system fonts** with DRK typography when touching text styling
|
|
4. **File follow-up tickets** for systematic cleanup when you notice patterns
|
|
|
|
#### Example: Opportunistic Refactoring
|
|
|
|
**Example:** See [opportunistic-refactoring.swift](design-system-designresourceskit/opportunistic-refactoring.swift)
|
|
|
|
## Components
|
|
|
|
### Current State: Minimal Component Library
|
|
|
|
We primarily use **system components** rather than custom ones, following iOS design guidelines. This is different from our Android app which has more custom components.
|
|
|
|
**Philosophy**:
|
|
- **System components first** - leverages platform conventions
|
|
- **Custom components only when needed** - avoid overengineering
|
|
- **Reusable when patterns emerge** - extract when used in multiple places
|
|
|
|
### Existing Custom Components
|
|
|
|
#### Blue Button (Reusable)
|
|
Our primary custom component used across multiple screens.
|
|
|
|
**Example:** See [blue-button-component.swift](design-system-designresourceskit/blue-button-component.swift)
|
|
|
|
**Candidate for DRK**: This button is used in multiple places and should be extracted into DesignResourcesKit as a reusable component.
|
|
|
|
### Future Component Strategy
|
|
|
|
#### When to Create Components
|
|
|
|
**✅ Create a component when**:
|
|
- Pattern is used in **3+ different contexts**
|
|
- Styling is **complex or specialized**
|
|
- Behavior needs to be **consistent across usage**
|
|
- Component **encapsulates design system tokens**
|
|
|
|
**❌ Don't create a component when**:
|
|
- Used in only **one place** (keep it local)
|
|
- **System component exists** that meets needs
|
|
- Component would be **overly generic** or complex
|
|
|
|
#### Emerging Patterns to Watch
|
|
|
|
Look for these patterns that might become components:
|
|
|
|
```swift
|
|
// Bottom sheets - if format becomes consistent
|
|
struct BottomSheetView: View {
|
|
// Consistent styling, behavior, animation
|
|
// Could become reusable component
|
|
}
|
|
|
|
// Info cards/panels - if layout patterns emerge
|
|
struct InfoCardView: View {
|
|
// Standard card styling with DRK colors
|
|
// Could be extracted if reused
|
|
}
|
|
|
|
// Form elements - if custom styling is needed
|
|
struct FormFieldView: View {
|
|
// Consistent form field styling
|
|
// Could become component library
|
|
}
|
|
```
|
|
|
|
#### Component Creation Process
|
|
|
|
1. **Identify the pattern** in your current work
|
|
2. **Check if existing implementations** could be generalized
|
|
3. **Design the API** to be flexible but opinionated
|
|
4. **Implement using DRK tokens** for colors, typography, spacing
|
|
5. **Add to DesignResourcesKit** package
|
|
6. **Update existing usages** to use the new component
|
|
7. **Document the component** with usage examples
|
|
|
|
**Example:** See [component-creation-example.swift](design-system-designresourceskit/component-creation-example.swift)
|
|
|
|
## Modularization Strategy
|
|
|
|
### Why DRK is a Separate Package
|
|
|
|
**High friction is a feature**: Making DRK a separate module provides beneficial constraints:
|
|
|
|
1. **Immutability encouragement**: Changes require more thought and process
|
|
2. **API stability**: Forces consideration of breaking changes
|
|
3. **Reusability**: Can be shared across iOS/macOS if needed
|
|
4. **Clear boundaries**: Separates design tokens from app logic
|
|
5. **Version control**: Can be tagged and versioned independently
|
|
|
|
### Design System Evolution
|
|
|
|
**Original Discussion**: [Tech Design: How to modularise iOS/macOS design system elements](✓ Tech Design: How to modularise iOS/macOS design system elements)
|
|
|
|
**Guiding Principles**:
|
|
- **Start minimal**: Don't over-engineer early
|
|
- **Evolve based on usage**: Add components when patterns emerge
|
|
- **Maintain consistency**: All additions should follow established patterns
|
|
- **Document decisions**: Keep rationale for future developers
|
|
|
|
## Working with DesignResourcesKit
|
|
|
|
### Adding New Design Tokens
|
|
|
|
**Process for adding colors/typography**:
|
|
|
|
1. **Design system first**: Ensure token is defined in Figma
|
|
2. **Semantic naming**: Use purpose-based names (`textPrimary` not `black`)
|
|
3. **Light/dark variants**: Define both light and dark mode values
|
|
4. **PR to DRK**: Add to DesignResourcesKit repository
|
|
5. **Update app**: Use new tokens in consuming apps
|
|
6. **Documentation**: Update usage examples and guidelines
|
|
|
|
### Updating DRK Version
|
|
|
|
**In consuming app (iOS/macOS):**
|
|
|
|
**Example:** See [updating-drk-version.swift](design-system-designresourceskit/updating-drk-version.swift)
|
|
|
|
**Testing DRK changes**:
|
|
- Test in both **light and dark modes**
|
|
- Verify **dynamic type scaling** works correctly
|
|
- Check **accessibility** with larger text sizes
|
|
- Test on **different device sizes**
|
|
|
|
### Local Development
|
|
|
|
**For iterating on DRK:**
|
|
|
|
**Example:** See [local-development.sh](design-system-designresourceskit/local-development.sh)
|
|
|
|
## Resources and References
|
|
|
|
### Official Resources
|
|
|
|
- **GitHub Repository**: [duckduckgo/DesignResourcesKit](https://github.com/duckduckgo/DesignResourcesKit)
|
|
- **Figma Designs**: [iOS & iPadOS Components](https://www.figma.com/file/GzGKD6gR24AHoUqVykX1ah/%F0%9F%93%B1-iOS-%26-iPadOS-Components?type=design&node-id=3938%3A23329&mode=design&t=0fuiNF84nnV5zExC-1)
|
|
|
|
### Related Documentation
|
|
|
|
- **Colors**: [Tech Design: How to organise colors and icons in iOS and macOS wrt the design system](✓ Tech Design: How to organise colors and icons in iOS and macOS wrt the design system)
|
|
- **Colors Update**: [Tech Design: Redefine design system colors in DesignResourcesKit](✓ Tech Design: Redefine design system colors in DesignResourcesKit)
|
|
- **Typography**: [Tech Design: How to organise typography/label styles in iOS and macOS wrt the design system](✓ Tech Design: How to organise typography/label styles in iOS and macOS wrt the design system)
|
|
- **Enforcement**: [Use danger to stop new colors being added to the iOS app](✓ Use danger to stop new colors being added to the iOS app)
|
|
|
|
### Quick Reference
|
|
|
|
#### UIKit Checklist
|
|
- [ ] Use `UIFont.daxTitle1()`, `UIFont.daxBody()`, etc.
|
|
- [ ] Use `UIColor(designSystemColor: .textPrimary)` etc.
|
|
- [ ] No hardcoded colors or fonts
|
|
- [ ] No system colors for app content
|
|
|
|
#### SwiftUI Checklist
|
|
- [ ] Use `.daxTitle1()`, `.daxBody()` modifiers
|
|
- [ ] Use `Color(designSystemColor: .textPrimary)` etc.
|
|
- [ ] Avoid `.font()` modifier (red flag in reviews)
|
|
- [ ] No hardcoded colors
|
|
|
|
#### Code Review Checklist
|
|
- [ ] No new colors in asset catalogs
|
|
- [ ] DRK typography used consistently
|
|
- [ ] Semantic color naming
|
|
- [ ] No hardcoded styling
|
|
- [ ] Opportunistic improvements to legacy code
|
|
|
|
---
|
|
|
|
**Remember**: The design system is only as strong as our commitment to using it. Every PR is an opportunity to improve consistency and user experience.
|