-
Notifications
You must be signed in to change notification settings - Fork 1
34 ‐ About the tokens
Tokens can be seen as atomic elements (but not with the same definition as in atomic design like the Orange Design System implementation).
A "component token" can be defined so as to be used in components and make the glue with semantic tokens. They must be overridable by themes. For example, a component token "button background" can point to a "danger information color" semantic token, pointing finaly to a "red color" raw tokens with a "#FF0000FF" String raw value.
A semantic token points to a raw token, and is used by components. A semantic token brings meanings, higher level notions. For example, a raw token can be a "red color", and a semantic token pointing to it can be a "danger information color". Semantic tokens are used by components tokens and shared definition of themes. They are splitted in kind of families, i.e. borders, dimensions, colors, spacings, elevations, sizings, opacities, grids and fonts. For some of theses tokens, like for borders, subfamilies can be defined likes width, radius and style. Finally, any of these raw tokens is associated to a raw value which will be - in the end - applied to SwiftUI views inside components. Type aliases will help to make a simple math between any semantic tokens and raw tokens.
A raw token contains a raw value, like a dimension, a color, a size. We use here the smallest primitive type possible for several reasons. First, they will have a lower memory fingerprint (much better to save hunderds of hexadecimal strings compared to SwiftUI Color obbjects). In addition, because we splitted tokens in protocols / enums, and make implemention in extensions, and allow overriding, we are constrained to use @objc runtime which force us to use Objective-C compatible types. Having less code, not complex, will help the tokenator (the tool generated Swift source code from Figma JSON) to provide Swift sources in the near future.
To avoid to define data structures which can be heavy in the end like class or structs, only primitives types are used for raw tokens (thus indirectly for higher level tokens like semantics and components ones). Use each time type aliases will help developers to find easily which type of tokens they want without using bigger objects.
There are some particular cases in the definition of tokens. In fact, the design team relies on Figma to define the design kits for all projects. These kits are based on tokens, i.e. kind of variables, any designer can user. However there are some specific needs for OUDS where notions are not available in Figma.
In Figma, as defined in OUDS, it is possible for a token to have several values depending to what the color scheme or the size class are. For example, a color semantic token can be different wether the device is in light mode or dark mode. A dimension semantic token can be different wether the device is in compact or regular mode. The tokenator is only able to generate tokens without to much logic because it relies a lot on the JSON given by Figma. Even if Figma is not abale to ma,age composite tokens and mutiple tokens, the design team stil tinkers such tokens. Thus they exist in Figma but do not appear in the JSON. Si the tokenator cannot process them and they must be defined manualy by the development team.
We choose to expose these particular tokens wrapped in Multiple*
object. Thus, in the component, module or themes levels, users will only manage one variable containing the values for the specific cases. It will prevent users to use bad tokens because too many of them are provided. It will be also easier to test the combinations (i.e. ensure for InverseTheme
the colors remain the same for light and dark scheme) and ensure the values are the expected ones.
Today we have tokens depending to size class:
MultipleSpaceSemanticTokens
MultipleSizeSemanticTokens
MultipleFontLetterSpacingSemanticTokens
MultipleFontSizeSemanticTokens
MultipleFontLineHeightSemanticTokens
MultipleFontCompositeRawTokens
MultipleSpaceTokens
We have also tokens depending to color schemes:
MultipleColorSemanticTokens
-
MultipleElevationSmenaticTokens
(because of box shadow)
// MARK: - For colors
// The color raw token colorFunctionalDodgerBlue500 is assigned for light and dark modes
var colorBgStatusInfoEmphasized: ColorSemanticToken { MultipleColorTokens(ColorRawTokens.colorFunctionalDodgerBlue500) }
// The color raw token colorFunctionalSun100 is for light mode, and colorFunctionalSun900 for dark mode
var colorBgStatusWarningMuted: ColorSemanticToken { MultipleColorTokens(light: ColorRawTokens.colorFunctionalSun100, dark: ColorRawTokens.colorFunctionalSun900) }
// MARK: - For elevations
// This elevation as for value elevationBottom_3_300 for both light and dark modes
// ElevationCompositeSemanticToken is a typealias for MultipleElevationTokens used for consistency in the code
var elevationStickyDefault: ElevationCompositeSemanticToken {
ElevationCompositeSemanticToken(ElevationRawTokens.elevationBottom_3_300) }
// MARK: - For font letter spacing
// The semantic token fontLetterSpacingDisplayLarge as the value fontLetterSpacing850 for compact mode and fontLetterSpacing1450 for regular mode
var fontLetterSpacingDisplayLarge: MultipleFontLetterSpacingTokens { MultipleFontLetterSpacingTokens(compact: FontRawTokens.fontLetterSpacing850, regular: FontRawTokens.fontLetterSpacing1450) }
// MARK: - For font line height
// The font semantic token fontLineHeightLabelLarge as the valeu fontLineHeight450 for both comapct and regular size classes
var fontLineHeightLabelLarge: MultipleFontLineHeightTokens { MultipleFontLineHeightTokens(FontRawTokens.fontLineHeight450) }
// MARK: - For font size
// The font semantic token fontSizeBodyMedium has the value fontSize200 for both size classes
var fontSizeBodyMedium: MultipleFontSizeTokens { MultipleFontSizeTokens(FontRawTokens.fontSize200) }
// MARK: - For size
// The size semantic token sizeIconWithHeadingXLargeShort contains the value dimension550 to use for compact mode and dimension650 for regular
var sizeIconWithHeadingXLargeShort: MultipleSizeTokens { MultipleSizeTokens(compact: DimensionRawTokens.dimension550, regular: DimensionRawTokens.dimension650) }
// MARK: - For space
// The space semantic token spaceScaledTall has the value dimension300 for compact mode and dimension400 for regular mode
var spaceScaledTall: MultipleSpaceTokens { MultipleSpaceTokens(compact: DimensionRawTokens.dimension300, regular: DimensionRawTokens.dimension400) }
// MARK: - For font
//The font semantic token (which here is a composite) as typeBold650 value for compact size class and typeBold850 for regular size class
var typeDisplaySmall: MultipleFontTokens { MultipleFontTokens(compact: FontRawTokens.typeBold650, regular: FontRawTokens.typeBold850) }
Note the Multiple*
contains only the values with some helpers, but it is the duty of the theme or users to use the suitable value.
Note also because the tokenator cannot generate "multiple" tokens they are defined in sepaated files and must be update manualy.
A composite token is a specific token which is defined by several tokens values.
For example, FontRawTokens
contain a token named typeBold850
. This token is defined as is:
public static let typeBold850 = FontCompositeRawToken(size: fontSize850, lineHeight: fontLineHeight1050, weight: fontWeight700, letterSpacing: fontLetterSpacing850)
In fact, for the font tokens, some raw tokens are composite because their definition rely on other tokens (here font size, font line height, font line weight, font letter spacing).
ElevationRawTokens
contain also such composites tokens because some of these raw tokens are designed for box shadow effects, for example:
public static let elevationBottom_1_100 = ElevationCompositeRawToken(x: elevationX0, y: elevationY100, blur: elevationBlur200, color: ColorRawTokens.colorTransparentBlack100)
Today FontRawTokens
and ElevationRawTokens
are the raw tokens types which contain composite tokens. There values are defined in dedicated files because the tokenator is not able to generate theme (the Figma tool does not handle composite tokens, so does not provide them in its JSON).
Because some raw tokens are composite which cannot be generated by the tokenator, the semantic tokens based on these particular raw tokens are defined beside the "common" semantic tokens.
Thus, all elevation semantic tokens not using composite raw tokens are declared in ElevationSemanticTokens
, and composite tokens are declared in ElevationCompositeSemanticTokens
.
In addition, all font semantic tokens not using composite raw tokens are declared in FontSemanticTokens
, and composite tokens are declared in FontCompositeSemanticTokens
.
Semantic tokens below are provided by the library:
- borders (
BorderSemanticTokens
) - colors (
ColorSemanticTokens
) - colors multiple (
ColorMultipleSemanticTokens
) - elevation (
ElevationSemanticTokens
) - elevation composite (
ElevationCompositeSemanticTokens
) - elevation multiple (
ElevationMultipleSemanticTokens
) - grid (
GridSemanticTokens
) - opacity (
OpacitySemanticTokens
) - size (
SizeSemanticTokens
) - multiple size (
SizeMultipleSemanticTokens
) - space (
SpaceSemanticTokens
) - space multiple (
SpaceMultipleSemanticTokens
) - font (
FontSemanticTokens
) - font composite (
FontCompositeSemanticTokens
) - font multiple (
FontMultipleSemanticTokens
)
Raw tokens below are provided by the library:
- borders (
BorderRawTokens
) - colors (
ColorRawTokens
) - dimensions (
DimensionRawTokens
) - elevation (
ElevationRawTokens
) - grid (
GridRawTokens
) - opacity (
OpactityRawTokens
) - font (
FontRawTokens
)