Orange-OpenSource / ouds-ios

A SwiftUI components library with code examples for Orange Unified Design System
https://ios.unified-design-system.orange.com/
MIT License
5 stars 1 forks source link

Refactoring of theme with wrappers #79

Open pylapp opened 2 weeks ago

pylapp commented 2 weeks ago

Today, it is the duty of a theme to embed, override and provide any raw tokens, semantic tokens and future component tokens. It implies to have finaly a class with thousands of objects.

Indeed this is acceptable because the logic behing OUDS is based on themes which are in fact combinations of values for any tokens.

Today a theme is a Swift class which is not a singleton because we don't want to instanciate such massive objects if we don't use it. Using a singleton won't help to override classes so as to have subthemes.

Howeer we can agree that having thousands properties in one object does not bring a good developer experience (DX), and we may implement another solution with wrappers.

We may in fact define as many wrappers as "family" of tokens, i.e. ColorsWrapper, BorderWrapper, TypographiesWrapper, DimensionsWrapper etc. Each wrapper must implement (in the same way as the actual implementation of a theme) a protocol to embed specific items of tokens which will be still overridable. Thus a theme won't implement such protocols anymore but will have inside it all wrappers. If a theme must be subclasses, it should only create a subclass of a wrapper and add it to the theme.

If could result to something like:


// Basic use

open class MyTheme {

    let colors: ColorsWrapper
    let borders: BordersWrapper
    ...

    init(colors: ColorsWrapper, borders: BordersWrapper() {
        self.colors = colors
        sef.borders = borders
    }
}

open class ColorsWrapper: ColorsSemanticTokens {
    // Implement tokens
}

// Alternative use

final class CustomTheme: MyTheme {

    // Init super
    init() {
        super.init(colors: MyColorsWrapper(), borders: BordersWrapper())
    }
}

final class MyColorsWrapper: ColorsWrapper {
    // Override the semantic token we want
}

Then the old line may move to something else:

// Before
theme.buttonBackgroundColorEmphasisHigh
// After
theme.colors.buttonBackgroundEmphasisHigh // If we suppose we wrap it in a "ColorsWrappers" and not a component token

Way may focus to this topic later when we'll have components tokens and tokens to implement. This solution is quite elgant and may improve DX buy we may face isues with memory and performances because we keep using plenty of Swift classes in the end.

pylapp commented 2 weeks ago

cc @ludovic35