swiftui-style-driven-components
13
总安装量
7
周安装量
#25107
全站排名
安装命令
npx skills add https://github.com/ahmadbrkt/swiftui-style-driven-components-skill --skill swiftui-style-driven-components
Agent 安装分布
cursor
7
mcpjam
4
qwen-code
4
antigravity
4
windsurf
4
zencoder
4
Skill 文档
SwiftUI Style-Driven Components
Overview
This skill provides expert guidance on building, reviewing, and extending SwiftUI components following the style-driven architecture pattern. This pattern emphasizes extensibility, maintainability, and Apple-style API design, making it ideal for building reusable component libraries.
Agent Behavior Contract
- Before creating a new component, verify it needs 2+ meaningfully different styles. If not, skip the style protocol.
- Follow Apple’s patterns (
ButtonStyle,LabelStyle) as the gold standard. - Use nested type-erased views in configuration (like
LabelStyleConfiguration.Title). - Never expose configuration initializers as
public. - Wrap
style.makeBodyinAnyViewfor type erasure. - Use
DynamicPropertyfor style protocols, notSendable. - Read styles from environment using existential type (
any [Component]Style).
Core Architecture Principles
- Protocol:
[Component]Styleâ defines HOW to render - Configuration:
[Component]StyleConfigurationâ contains WHAT to render - Component: Creates configuration internally, delegates rendering to style
- Environment: Enables subtree styling without modifying components
When to Use Style Protocol
Use style protocol when:
- 2+ meaningfully different visual styles needed
- Environment-based style cascading desired
- Building reusable component library
- Styles need environment access (
@Environment)
Skip style protocol when:
- Single visual representation
- Simple, static appearance
- One-off internal component
- No style customization needed
Quick Decision Tree
Building a new component?
- Needs multiple styles? â If no, skip style protocol
- Create structure â See
references/component-structure.md - Define protocol â See
references/style-protocol.md - Create configuration â Nested type-erased views pattern
- Implement default style â Basic rendering
- Add environment key â See
references/environment-keys.md - Add convenience accessors â See
references/common-patterns.md
Adding a new style?
- Create struct conforming to
[Component]Style - Implement
makeBody(configuration:) - Add convenience accessor (
.myStyle) - No component changes needed!
Reviewing component architecture?
- Check protocol uses
DynamicProperty,@ViewBuilder @MainActor - Verify configuration uses nested type-erased views
- Confirm configuration init is
internal - Check component wraps
style.makeBodyinAnyView - Validate environment key uses existential (
any [Component]Style) - Ensure new styles don’t require component changes
Triage Playbook
- Creating component file structure â
references/component-structure.md - Defining style protocol â
references/style-protocol.md - Creating configuration with content â
references/style-protocol.md - Setting up environment keys â
references/environment-keys.md - Adding convenience initializers â
references/common-patterns.md - Parameterized or adaptive styles â
references/common-patterns.md - Using design tokens â
references/design-system.md - Writing snapshot tests â
references/testing.md - Organizing previews â
references/previews.md - Accessibility requirements â
references/accessibility.md
Quick Reference
Component Structure
[Component]/
âââ EnvironmentKeys/[Component]StyleKey.swift
âââ Styles/
â âââ [Component]Style.swift
â âââ [Component]StyleConfiguration.swift
â âââ Default[Component]Style.swift
âââ [Component].swift
Pattern Summary
- Style Protocol:
DynamicProperty,@ViewBuilder @MainActor func makeBody - Configuration: Nested
struct Content: Viewwithprivate let _body: () -> AnyView - Configuration Init:
internal(notpublic) - Component Body:
AnyView(style.makeBody(configuration: .init(...))) - Environment Key:
@Entry public var style: any [Component]Style = .automatic - View Modifier:
func style(_ style: some [Component]Style) -> some View
Best Practices
DO
- Use
DynamicPropertyfor style protocols - Use nested type-erased views in configuration
- Make configuration initializers
internal - Wrap
style.makeBodyinAnyView - Use design tokens, not magic numbers
- Provide convenience accessors (
.compact,.outlined)
DON’T
- Add explicit
Sendableto protocols - Make configuration initializers
public - Pass configuration to component initializer
- Put content properties in style protocol
- Use style protocol for single-variant components
- Use
AnyViewdirectly as configuration property type
Review Checklist
Architecture
- Style protocol uses
DynamicProperty -
makeBodyhas@ViewBuilder @MainActor - Configuration uses nested type-erased views
- Configuration init is
internal - Component wraps
style.makeBodyinAnyView - New styles don’t require component changes
Environment
- Uses
@Entrymacro - Stores as existential (
any [Component]Style) - Modifier uses opaque parameter (
some [Component]Style) - Default value provided (
.automatic)
Quality
- Previews cover all styles (see
references/previews.md) - Snapshot tests exist (see
references/testing.md) - Accessibility supported (see
references/accessibility.md) - Design tokens used (see
references/design-system.md)
Reference Files
references/component-structure.mdâ Creating new component, file organizationreferences/style-protocol.mdâ Protocol definition, configuration pattern, adding stylesreferences/environment-keys.mdâ Environment injection, usage patternsreferences/common-patterns.mdâ Convenience initializers/accessors, parameterized stylesreferences/testing.mdâ Snapshot tests, test organizationreferences/previews.mdâ Preview structure, checklistreferences/design-system.mdâ Design tokens, typography, colorsreferences/accessibility.mdâ Labels, identifiers, Dynamic Type
Philosophy
Style-driven components prioritize:
- Extensibility â Add styles without modifying components
- Apple Patterns â Follow
ButtonStyle,LabelStyleconventions - Simplicity â Skip style protocol for single-variant components
- Type Safety â Generic APIs with internal type erasure
- Consistency â All components follow same patterns