Upgrade to Pro — share decks privately, control downloads, hide ads and more …

What we've learnt building a Design System in S...

What we've learnt building a Design System in SwiftUI

This is not a talk about SwiftUI or any particular technology.
This is a story of our journey. A journey, that is packed with twists and turns; tests, allies, and enums.
I will talk about how we navigated this large project, what helped us succeed, what held us back and how our approach kept on evolving as we progressed.

Lucy Galik is a Software Engineer at Monzo working in growth.
Previously she worked at Delli and Farmdrop where she built delightful apps focusing on first class user experience. She likes learning new technologies, solving problems and helping others.
Outside of work, Lucy enjoys cold water swimming. She is also an avid operagoer.

Leeds Mobile

November 06, 2024
Tweet

More Decks by Leeds Mobile

Other Decks in Technology

Transcript

  1. GUIDING PRINCIPLES • Discoverability • Keep the good stu ff

    • no UIKit • Accessibility fi rst • Keep it simple
  2. GUIDING PRINCIPLES • Discoverability • Keep the good stu ff

    • no UIKit • Accessibility fi rst • Keep it simple • Limited API
  3. Keep the good stuff Theme class HostingController: UIHostingController { init(

    rootView: Content, theme: Theme ) { super.init( rootView: HostingView( content: rootView, theme: theme ) ) } } struct HostingView: View { let theme: Theme let content: Content var body: some View { content .environment(\.theme, theme) } }
  4. no UIKit struct CustomButton: View { let title: String let

    isEnabled: Bool let isLoading: Bool let action: () -> Void init( title: String, isEnabled: Bool, isLoading: Bool, action: @escaping () -> Void ) { // ... } }
  5. no UIKit @Environment struct CustomButton: View { let title: String

    let isEnabled: Bool let isLoading: Bool let action: () -> Void init( title: String, isEnabled: Bool, isLoading: Bool, action: @escaping () -> Void ) { // ... } } struct CustomButton: View { let title: String @Environment(\.isEnabled) var isEnabled @Environment(\.isLoading) var isLoading let action: () -> Void init( title: String, action: @escaping () -> Void ) { // … } }
  6. no UIKit ViewModel struct CardViewModel { let icon: String let

    title: String let subtitle: String let action: () -> Void } struct Card: View { let viewModel: CardViewModel var body: some View { // ... } }
  7. no UIKit ViewModel struct CardViewModel { let icon: String let

    title: String let subtitle: String let action: () -> Void } struct Card: View { let viewModel: CardViewModel var body: some View { // ... } } struct CardViewModel { let icon: String let title: String let subtitle: String let action: () -> Void } extension CardViewModel: View { var body: some View { // ... } }
  8. no UIKit ViewModel struct CardViewModel { let icon: String let

    title: String let subtitle: String let action: () -> Void } struct Card: View { let viewModel: CardViewModel var body: some View { // ... } } struct Card: View { let icon: String let title: String let subtitle: String let action: () -> Void var body: some View { // ... } }
  9. no UIKit Styles struct AnotherButton: View { enum Style {

    case primary case secondary case destructive } let style: Style // ... var body: some View { // ... } var foregroundColor: Color { switch style { // ... } } var backgroundColor: Color { switch style { // ... } }
  10. no UIKit Styles struct AnotherButton: View { enum Style {

    case primary case secondary case destructive } let style: Style // ... var body: some View { // ... } var foregroundColor: Color { switch style { // ... } } var backgroundColor: Color { switch style { // ... } } struct AnotherButton: View { let style: AnotherButtonStyle // ... var body: some View { Button( // ... ) .buttonStyle(style) } } struct AnotherButtonStyle: ButtonStyle { let foregroundColor: Color let backgroundColor: Color func makeBody( configuration: Configuration ) -> some View { // ... } }
  11. no UIKit Styles struct AnotherButton: View { let style: AnotherButtonStyle

    // ... var body: some View { Button( // ... ) .buttonStyle(style) } } struct AnotherButtonStyle: ButtonStyle { let foregroundColor: Color let backgroundColor: Color func makeBody( configuration: Configuration ) -> some View { // ... } }
  12. no UIKit Styles struct AnotherButton: View { let style: AnotherButtonStyle

    // ... var body: some View { Button( // ... ) .buttonStyle(style) } } struct AnotherButtonStyle: ButtonStyle { let foregroundColor: Color let backgroundColor: Color func makeBody( configuration: Configuration ) -> some View { // ... } }
  13. no UIKit Styles struct AnotherButton: View { let style: AnotherButtonStyle

    // ... var body: some View { Button( // ... ) .buttonStyle(style) } } struct AnotherButtonStyle: ButtonStyle { let foregroundColor: Color let backgroundColor: Color func makeBody( configuration: Configuration ) -> some View { // ... } } extension AnotherButtonStyle { static let primary = AnotherButtonStyle( // ...) static let secondary = AnotherButtonStyle( // ... ) static let destructive = AnotherButtonStyle( // ... ) }
  14. Accessibility accessibilityRepresentation struct CustomSlider: View { // ... var body:

    some View { slider() .accessibilityRepresentation { Slider(value: $value, in: range, step: step) } } }
  15. Accessibility var body: some View { HStack { Image(illustration) Text(title)

    Text(subtitle) } .accessibilityLabel(accessibilityLabel) }
  16. Keep it simple struct Footer: View { let prompt: Text?

    let callout: Callout? let primary: LargeButton let secondary: LargeButton? let axis: Axis var body: some View { // ... } public init( button: LargeButton ) { // ... } public init( prompt: Text, top: LargeButton, bottom: LargeButton ) { // ... } }
  17. Keep it simple struct Footer: View { let prompt: Text?

    let callout: Callout? let primary: LargeButton let secondary: LargeButton? let axis: Axis var body: some View { // ... } public init( button: LargeButton ) { // ... } public init( prompt: Text, top: LargeButton, bottom: LargeButton ) { // ... } }
  18. Limited API struct Footer: View { // ... init( prompt:

    Text, top: LargeButton, bottom: LargeButton ) { // ... } }
  19. Limited API struct Footer: View { // ... init( prompt:

    Text, top: LargeButton, bottom: LargeButton ) { // ... } } struct Footer<Primary: View, Secondary: View>: View { // ... init( prompt: Text, @ViewBuilder top: () -> Primary, @ViewBuilder bottom: () -> Secondary ) { // ... } }