Skip to content

Commit

Permalink
refactor: apply new architecture with tokens providers (#79) (#352)
Browse files Browse the repository at this point in the history
- Defines tokens providers embeded in the theme
- Improve documentation (DocC catalogs, Swift doc)

Reviewed-by: Ludovic Pinel <[email protected]>
Acked-by: Ludovic Pinel <[email protected]>
Signed-off-by: Pierre-Yves Lapersonne <[email protected]>
  • Loading branch information
pylapp authored Dec 17, 2024
1 parent eb89600 commit 6b5a3e0
Show file tree
Hide file tree
Showing 160 changed files with 5,743 additions and 4,400 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- [Library] New architecture with tokens provider ([#79](https://github.com/Orange-OpenSource/ouds-ios/issues/79))
- [DemoApp] Prepare new architecture to add components illustration ([#328](https://github.com/Orange-OpenSource/ouds-ios/issues/328))

### Changed
Expand Down
5 changes: 0 additions & 5 deletions OUDS/Core/Components/README.md

This file was deleted.

46 changes: 23 additions & 23 deletions OUDS/Core/Components/Sources/Extensions/View+Typography.swift

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ struct AccessibleNavigationTitleModifier: ViewModifier {

// MARK: - Request Accessible Focus Modifier

/// `ViewModifier` to apply on a a `View` so as to request the focus after a given time.
/// `ViewModifier` to apply on a `View` so as to request the focus after a given time.
struct RequestAccessibleFocusModifier: ViewModifier {

/// Flag to listen saying wether or not the `View` got the focus
Expand All @@ -58,6 +58,18 @@ struct RequestAccessibleFocusModifier: ViewModifier {

// MARK: - Accessibility Focusable

/// Value to use as a `AccessibilityFocusState` to request focus.
///
/// ```swift
/// // In your view, add the following property
/// @AccessibilityFocusState private var requestFocus: AccessibilityFocusable?
///
/// var body: some View {
/// SomeView()
/// .accessibilityFocused($requestFocus, equals: .some(id: element.id))
/// .oudsRequestAccessibleFocus(_requestFocus, for: .some(id: elements[0].id))
/// }
/// ```
public enum AccessibilityFocusable: Hashable {
case none
case some(id: String)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ extension View {

/// Adds a modifier to the current `View` so as to define a navigation title using the current `title`
/// and also send a notification for accessibility layers for a change of screen when appeared.
///
/// ```swift
/// SomeView().oudsNavigationTitle("your title key")
/// ```
///
/// - Parameter title: The navigation title
/// - Returns View: The view with a new modifier
public func oudsNavigationTitle(_ title: String) -> some View {
Expand All @@ -37,6 +42,18 @@ extension View {
}

/// Adds a modifier to the current `View` so as to defer a focus request after the view is displayed
///
/// ```swift
/// YourView: View {
/// @AccessibilityFocusState var requestFocus: Bool
///
/// var body: some View {
/// SomeView()
/// .oudsRequestAccessibleFocus(_requestFocus)
/// }
/// }
/// ```
///
/// - Parameter requestFocus: The boolean binding (e.g. the `AccessibilityFocusState`)
/// - Returns View: The view with a new modifier
public func oudsRequestAccessibleFocus(_ requestFocus: AccessibilityFocusState<Bool>) -> some View {
Expand All @@ -45,6 +62,18 @@ extension View {
}

/// Adds a modifier to the current `View` so as to defer a focus request after the view is displayed for the given element
///
/// ```swift
/// YourView: View {
/// @AccessibilityFocusState var requestFocus: Bool
///
/// var body: some View {
/// SomeView()
/// .oudsRequestAccessibleFocus(_requestFocus, for: .some(id: element.id))
/// }
/// }
/// ```
///
/// - Parameters:
/// - requestFocus: The boolean binding (e.g. the `AccessibilityFocusState`)
/// - target: The item which will get the focus
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,20 @@ import SwiftUI
extension View {

/// Modifies the current `View` to apply a border.
///
///
/// ```swift
/// @Environment(\.theme) private var theme
///
/// var body: some View {
/// SomeView()
/// .oudsBorder(
/// style: theme.borders.borderStyleDefault,
/// width: theme.borders.borderWidthThin,
/// radius: theme.borders.borderRadiusNone,
/// color: theme.colors.colorBorderDefault)
/// }
/// ```
///
/// - Parameters
/// - style: The style to apply on the component
/// - width: The width of the border
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
import OUDSTokensSemantic
import SwiftUI

/// A `ViewModifier` applying a custom font on a `View`
/// Note that `CustomFontModifier` expects to lad a custom external font and not any font embeded in the device.
/// A `ViewModifier` applying a custom font on a `View`.
/// Note that `CustomFontModifier` expects to load a custom external font and not any font embeded in the device.
struct CustomFontModifier: ViewModifier {

// MARK: - Properties
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
import OUDSTokensSemantic
import SwiftUI

/// A `ViewModifier` which will apply the system `Font` in a component `View` using a `MultipleFontCompositeRawTokens`
/// A `ViewModifier` which will apply the system `Font` in a component `View` using a `MultipleFontCompositeRawTokens`.
/// Note that `FontModifier` use default system font but nothing for others fonts embeded in device
struct FontModifier: ViewModifier {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import SwiftUI
struct TypographyModifier: ViewModifier {

/// The name of a possible custom font family, or `nil` if the font is use is _system font_
let customFontFamily: FontFamilyRawToken?
let fontFamily: FontFamilyRawToken?
/// The typography to apply for *compact* or *regular* modes, i.e. font tokens
let font: MultipleFontCompositeRawTokens

Expand Down Expand Up @@ -61,7 +61,7 @@ struct TypographyModifier: ViewModifier {
// using UIFontMetrics to scale the font size, ensuring Dynamic Type support
let scaledFontSize = UIFontMetrics.default.scaledValue(for: fontSize)

if let fontFamilyName = customFontFamily {
if let fontFamilyName = fontFamily {
let composedFontFamily = fontFamilyName.compose(withFont: "\(adaptiveFont.weight.fontWeight)")
let customFont: Font = .custom(composedFontFamily, size: adaptiveFont.size)
return customFont
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,18 @@

The catalog of all components provided by OUDS. It contains also `View` extensions and `ViewModifiers` to apply tokens and styles on components and higher-level views.

@Metadata {
@TechnologyRoot
@SupportedLanguage(objc)
}

## Overview

**More details coming soon.**
❗More details coming soon.❗

## Topics
## Customize components

### Apply shadow effect
Some helpers are provided through this module.

### Apply a specific shadow effect (elevation tokens)

The unified design system implemented by OUDS iOS library allows to apply *elevation effets* on a `View`, i.e. a shadow under the component.
Because the design tool in use is _Figma_ which defines such shadow with a _blur_ and a _spread_ radiuses, and because _SwfitUI_ uses only its own _radius_ definition, an extension of `View` has been implemented to let users apply some effect using an [`ElevationCompositeSemanticToken`](https://ios.unified-design-system.orange.com/documentation/oudstokenssemantic/elevationcompositesemantictoken) from the [OUDSTokensSemantic](https://ios.unified-design-system.orange.com/documentation/oudstokenssemantic/) library thanks to the method `shadow(elevation: ElevationCompositeSemanticToken)`.
Because the design tool in use is _Figma_ which defines such shadow with a _blur_ and a _spread_ radiuses, and because _SwiftUI_ uses only its own _radius_ definition, an extension of `View` has been implemented to let users apply some effect using an [`ElevationCompositeSemanticToken`](https://ios.unified-design-system.orange.com/documentation/oudstokenssemantic/elevationcompositesemantictoken) from the [OUDSTokensSemantic](https://ios.unified-design-system.orange.com/documentation/oudstokenssemantic/) library thanks to the method `shadow(elevation: ElevationCompositeSemanticToken)`.

```swift
// For example, apply the elevation effect "elevationDragLight" from your theme:
Expand All @@ -32,7 +29,7 @@ public static let elevationBottom_3_500 = ElevationCompositeRawToken(x: 0, y: 4,
// Blur will be used to compute the radius value
```

### Apply a specific typography
### Apply a specific typography (font tokens)

Your application identity can be strongly based on the *typography* you use, i.e. the font family you choose and other configuration details like the font size or the font weight.

Expand All @@ -53,7 +50,7 @@ public static let typeBold1050 = FontCompositeRawToken(size: fontSize1050, lineH
```

However the _theme_ must know which _font family_ to apply, and this font family can be a _custom one_ or the _system one_.
Thus, we let the users define the font family they want by overriding the `customFontFamily` property. This value will be used to compute the typography, if not defined the systme font will be used.
Thus, we let the users define the font family they want by overriding the `fontFamily` property. This value will be used to compute the typography, if not defined the systme font will be used.

Thus, if you want to apply a specific typography to a `View`, supposing you defined previously the semantic tokens, just call the method you want and gives as parameter the theme (to get the custom font if defined):

Expand All @@ -67,5 +64,24 @@ myView.typeLabelStrongXLarge(theme)
// Etc.
```

### Group
### Apply a specific border (border tokens)

This module exposes the helper `oudsBorder(style:width:radius:color)` so as to apply border semantic tokens on a view in order to define a border effect.
The helper is available through `View`, and tokens through the provider of the theme.

```swift
@Environment(\.theme) private var theme

var body: some View {
SomeView()
.oudsBorder(
style: theme.borders.borderStyleDefault,
width: theme.borders.borderWidthThin,
radius: theme.borders.borderRadiusNone,
color: theme.colors.colorBorderDefault)
}
```

## Topics

### Group
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import Foundation
import OUDSTokensRaw
import OUDSTokensSemantic

extension OUDSTheme: BorderSemanticTokens {
extension OUDSBorderSemanticTokensProvider: BorderSemanticTokens {
@objc open var borderRadiusDefault: BorderRadiusSemanticToken { BorderRawTokens.borderRadius0 }
@objc open var borderRadiusMedium: BorderRadiusSemanticToken { BorderRawTokens.borderRadius150 }
@objc open var borderRadiusNone: BorderRadiusSemanticToken { BorderRawTokens.borderRadius0 }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@ import OUDSTokensSemantic

// swiftlint:disable line_length

/// Defines wrapper objects for `ColorSemanticToken`.
/// These values can be overriden inside `OUDSTheme` subclasses (in extensions or not, in the same module or not) thanks to the `@objc open` combination.
/// Defines provider objects for `ColorSemanticTokens` so as to pack them as light and dark mode colors.
/// These values can be overriden inside `OUDSColorSemanticTokensProvider` subclasses (in extensions or not, in the same module or not) thanks to the `@objc open` combination.
/// Some tokens do not have values assigned in the design system, and must be overriden.
/// Some tokens must be overiden in `OrangeTheme` side because they rely on Orange brand colors.
/// Some tokens must be overriden in `OrangeTheme` side because they rely on Orange brand colors.
/// Helps to expose color semantic tokens with two values to use depending to the color scheme (*Figma* cannot manage such tokens and generate them).
extension OUDSTheme: ColorMultipleSemanticTokens {
extension OUDSColorSemanticTokensProvider: ColorMultipleSemanticTokens {

// MARK: - Color - Opacity - Invisible

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import OUDSTokensSemantic

// swiftlint:disable identifier_name

extension OUDSTheme: ColorSemanticTokens {
extension OUDSColorSemanticTokensProvider: ColorSemanticTokens {
@objc open var colorOpacityInvisibleBlackLight: ColorSemanticToken { ColorRawTokens.colorOpacityBlack0 }
@objc open var colorOpacityInvisibleWhiteLight: ColorSemanticToken { ColorRawTokens.colorOpacityWhite0 }
@objc open var colorOpacityInvisibleBlackDark: ColorSemanticToken { ColorRawTokens.colorOpacityWhite0 }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,13 @@ import OUDSTokensSemantic
// WARNING: Not synchronized anymore with the Figjam / Figma by developers team
// Create an issue for update https://github.com/Orange-OpenSource/ouds-ios/issues/new?template=token_update.yml

/// Defines basic values common to all themes for ``ElevationCompositeSemanticTokens``.
/// These values can be overriden inside ``OUDSTheme`` subclasses (in extensions or not, in the same module or not) thanks to the `@objc open` combination.
/// The aim of this extensions is to make relationships between all semantic tokens for elevations and associated raw tokens.
/// `OUDSTheme`` can be seen as a kind of "abstract class" in _object oriented paradigm_.
/// The *tokenator* is not able to provide code for such "composite" objects because the *Figma* tool itself cannot manage that and does not output anything in its JSON to process/
/// Defines basic values common to all themes for `ElevationCompositeSemanticTokens``.
/// These values can be overriden inside ``OUDSElevationSemanticTokensProvider`` subclasses (in extensions or not, in the same module or not) t
/// hanks to the `@objc open` combination.
/// The aim of this extension is to make relationships between all semantic tokens for elevations and associated raw tokens.
/// The *tokenator* is not able to provide code for such "composite" objects because the *Figma* tool itself cannot manage that and does not output anything in its JSON to process.
/// It defines in fact box shadows effects.
extension OUDSTheme: ElevationCompositeSemanticTokens {
extension OUDSElevationSemanticTokensProvider: ElevationCompositeSemanticTokens {

// MARK: Semantic token - Elevation - Box shadow

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ import OUDSTokensSemantic

// swiftlint:disable line_length

/// Defines wrapper objects for eelvation color semantic tokens.
/// These values can be overriden inside ``OUDSTheme`` subclasses (in extensions or not, in the same module or not) thanks to the `@objc open` combination.
extension OUDSTheme: ElevationMultipleSemanticTokens {
/// Defines provider objects for elevation color semantic tokens using ``MultipleColorSemanticTokens`` so as to exposed colors for light and dark color schemes.
/// These values can be overriden inside `OUDSElevationSemanticTokensProvider` subclasses (in extensions or not, in the same module or not) thanks to the `@objc open` combination.
extension OUDSElevationSemanticTokensProvider: ElevationMultipleSemanticTokens {

@objc open var elevationColorDefault: MultipleColorSemanticTokens { MultipleColorSemanticTokens(light: elevationColorDefaultLight, dark: elevationColorDefaultDark) }
@objc open var elevationColorDrag: MultipleColorSemanticTokens { MultipleColorSemanticTokens(light: elevationColorDragLight, dark: elevationColorDragDark) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import OUDSTokensSemantic

// swiftlint:disable identifier_name

extension OUDSTheme: ElevationSemanticTokens {
extension OUDSElevationSemanticTokensProvider: ElevationSemanticTokens {
@objc open var elevationBlurDefault: ElevationBlurSemanticToken { ElevationRawTokens.elevationBlur300 }
@objc open var elevationBlurDrag: ElevationBlurSemanticToken { ElevationRawTokens.elevationBlur400 }
@objc open var elevationBlurEmphasized: ElevationBlurSemanticToken { ElevationRawTokens.elevationBlur600 }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@ import OUDSTokensSemantic

// swiftlint:disable line_length

/// Defines basic values common to all themes for ``FontCompositeSemanticTokens``.
/// These values can be overriden inside ``OUDSTheme`` subclasses (in extensions or not, in the same module or not) thanks to the `@objc open` combination.
/// Defines basic values common to all themes for `FontCompositeSemanticToken`.
/// These values can be overriden inside ``OUDSFontSemanticTokensProvider`` subclasses (in extensions or not, in the same module or not) thanks to the `@objc open` combination.
/// The aim of this extensions is to make relationships between all composite semantic tokens for typography / fonts and associated composite raw tokens.
/// `OUDSTheme` can be seen as a kind of "abstract class" in _object oriented paradigm_.
extension OUDSTheme: FontCompositeSemanticTokens {
/// The *tokenator* is not able to provide code for such "composite" objects because the *Figma* tool itself cannot manage that and does not output anything in its JSON to process.
extension OUDSFontSemanticTokensProvider: FontCompositeSemanticTokens {

// MARK: - Semantic tokens - Typography - Composites - Display

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ import OUDSTokensSemantic

// swiftlint:disable line_length

/// Defines wrapper objects for typography semantic tokens but "multiple", i.e. tokens with values depending to size classes or color schemes.
/// These values can be overriden inside ``OUDSTheme`` subclasses (in extensions or not, in the same module or not) thanks to the `@objc open` combination.
extension OUDSTheme: FontMultipleSemanticTokens {
/// Defines provider objects for font semantic tokens but "multiple", i.e. tokens with values depending to size classes or color schemes.
/// These values can be overriden inside `OUDSFontSemanticTokensProvider` subclasses (in extensions or not, in the same module or not) thanks to the `@objc open` combination.
extension OUDSFontSemanticTokensProvider: FontMultipleSemanticTokens {

// MARK: - Semantic token - Typography - Font - Size

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import Foundation
import OUDSTokensRaw
import OUDSTokensSemantic

extension OUDSTheme: FontSemanticTokens {
extension OUDSFontSemanticTokensProvider: FontSemanticTokens {
@objc open var fontFamily: FontFamilySemanticToken { FontRawTokens.fontFamilySystemSfPro }
@objc open var fontLetterSpacingBodyLargeMobile: FontLetterSpacingSemanticToken { FontRawTokens.fontLetterSpacing250 }
@objc open var fontLetterSpacingBodyLargeTablet: FontLetterSpacingSemanticToken { FontRawTokens.fontLetterSpacing250 }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import Foundation
import OUDSTokensRaw
import OUDSTokensSemantic

extension OUDSTheme: GridSemanticTokens {
extension OUDSGridSemanticTokensProvider: GridSemanticTokens {
@objc open var gridCompactColumnGap: GridSemanticToken { GridRawTokens.gridColumnGap100 }
@objc open var gridCompactMargin: GridSemanticToken { GridRawTokens.gridMargin300 }
@objc open var gridCompactMaxWidth: GridSemanticToken { GridRawTokens.gridMaxWidthCompact }
Expand Down
Loading

0 comments on commit 6b5a3e0

Please sign in to comment.