| | | 1 | | namespace Allyaria.Theming.Helpers; |
| | | 2 | | |
| | | 3 | | /// <summary> |
| | | 4 | | /// Provides mapping utilities between <see cref="Brand" /> configurations and Allyaria theming constructs, producing |
| | | 5 | | /// <see cref="ThemeUpdater" /> instances used to construct theme components. |
| | | 6 | | /// </summary> |
| | | 7 | | /// <remarks> |
| | | 8 | | /// <para> |
| | | 9 | | /// The <see cref="ThemeMapper" /> acts as the bridge between brand-level definitions (fonts, palettes, variants) an |
| | | 10 | | /// runtime theme generation. |
| | | 11 | | /// </para> |
| | | 12 | | /// <para> |
| | | 13 | | /// It handles color palette resolution, font face selection, and state-based color derivation for light, dark, and |
| | | 14 | | /// high-contrast variants. |
| | | 15 | | /// </para> |
| | | 16 | | /// </remarks> |
| | | 17 | | internal sealed class ThemeMapper |
| | | 18 | | { |
| | | 19 | | /// <summary>The primary <see cref="Brand" /> definition used for standard light and dark modes.</summary> |
| | | 20 | | private readonly Brand _brand; |
| | | 21 | | |
| | | 22 | | /// <summary>The dedicated high-contrast <see cref="Brand" /> variant used when accessibility modes are enabled.</su |
| | | 23 | | private readonly Brand _highContrast; |
| | | 24 | | |
| | | 25 | | /// <summary>Initializes a new instance of the <see cref="ThemeMapper" /> class.</summary> |
| | | 26 | | /// <param name="brand">An optional <see cref="Brand" /> instance. If omitted, a default <see cref="Brand" /> is cre |
| | 72 | 27 | | public ThemeMapper(Brand? brand = null) |
| | | 28 | | { |
| | 72 | 29 | | _brand = brand ?? new Brand(); |
| | 72 | 30 | | _highContrast = Brand.CreateHighContrastBrand(); |
| | 72 | 31 | | } |
| | | 32 | | |
| | | 33 | | /// <summary> |
| | | 34 | | /// Builds a mapping between <see cref="BrandPalette" /> instances and <see cref="ComponentState" /> values. |
| | | 35 | | /// </summary> |
| | | 36 | | /// <param name="state">The <see cref="BrandState" /> defining the palette states.</param> |
| | | 37 | | /// <returns> |
| | | 38 | | /// An array of tuples pairing <see cref="BrandPalette" /> with its associated <see cref="ComponentState" />. |
| | | 39 | | /// </returns> |
| | | 40 | | private static (BrandPalette Palette, ComponentState ComponentState)[] BuildPaletteMap(BrandState state) |
| | | 41 | | => |
| | 784 | 42 | | [ |
| | 784 | 43 | | (state.Default, ComponentState.Default), |
| | 784 | 44 | | (state.Disabled, ComponentState.Disabled), |
| | 784 | 45 | | (state.Dragged, ComponentState.Dragged), |
| | 784 | 46 | | (state.Focused, ComponentState.Focused), |
| | 784 | 47 | | (state.Hovered, ComponentState.Hovered), |
| | 784 | 48 | | (state.Pressed, ComponentState.Pressed), |
| | 784 | 49 | | (state.Visited, ComponentState.Visited) |
| | 784 | 50 | | ]; |
| | | 51 | | |
| | | 52 | | /// <summary>Builds a mapping of light and dark theme variants from the given <see cref="Brand" />.</summary> |
| | | 53 | | /// <param name="brand">The <see cref="Brand" /> from which to derive color themes.</param> |
| | | 54 | | /// <param name="isHighContrast">Indicates whether high-contrast variants should be mapped.</param> |
| | | 55 | | /// <returns> |
| | | 56 | | /// An array of tuples pairing <see cref="BrandTheme" /> with its corresponding <see cref="ThemeType" />. |
| | | 57 | | /// </returns> |
| | | 58 | | private static (BrandTheme Theme, ThemeType ThemeType)[] BuildThemeMap(Brand brand, bool isHighContrast) |
| | | 59 | | => |
| | 251 | 60 | | [ |
| | 251 | 61 | | (brand.Variant.Dark, isHighContrast |
| | 251 | 62 | | ? ThemeType.HighContrastDark |
| | 251 | 63 | | : ThemeType.Dark), |
| | 251 | 64 | | (brand.Variant.Light, isHighContrast |
| | 251 | 65 | | ? ThemeType.HighContrastLight |
| | 251 | 66 | | : ThemeType.Light) |
| | 251 | 67 | | ]; |
| | | 68 | | |
| | | 69 | | /// <summary> |
| | | 70 | | /// Builds a mapping for light and dark theme <em>variants</em> derived from the base <see cref="Brand" />. |
| | | 71 | | /// </summary> |
| | | 72 | | /// <param name="brand">The <see cref="Brand" /> used for variant mapping.</param> |
| | | 73 | | /// <param name="isHighContrast">Specifies whether high-contrast mappings should be included.</param> |
| | | 74 | | /// <returns>An array of tuples mapping <see cref="BrandTheme" /> variants to <see cref="ThemeType" /> values.</retu |
| | | 75 | | private static (BrandTheme Theme, ThemeType ThemeType)[] BuildThemeVariantMap(Brand brand, bool isHighContrast) |
| | | 76 | | => |
| | 141 | 77 | | [ |
| | 141 | 78 | | (brand.Variant.DarkVariant, isHighContrast |
| | 141 | 79 | | ? ThemeType.HighContrastDark |
| | 141 | 80 | | : ThemeType.Dark), |
| | 141 | 81 | | (brand.Variant.LightVariant, isHighContrast |
| | 141 | 82 | | ? ThemeType.HighContrastLight |
| | 141 | 83 | | : ThemeType.Light) |
| | 141 | 84 | | ]; |
| | | 85 | | |
| | | 86 | | /// <summary> |
| | | 87 | | /// Retrieves a <see cref="BrandState" /> from a <see cref="BrandTheme" /> based on the specified |
| | | 88 | | /// <see cref="PaletteType" />. |
| | | 89 | | /// </summary> |
| | | 90 | | /// <param name="theme">The <see cref="BrandTheme" /> to search.</param> |
| | | 91 | | /// <param name="paletteType">The <see cref="PaletteType" /> indicating which palette to return.</param> |
| | | 92 | | /// <returns>A <see cref="BrandState" /> corresponding to the given palette type.</returns> |
| | | 93 | | private static BrandState GetBrandState(BrandTheme theme, PaletteType paletteType) |
| | 784 | 94 | | => paletteType switch |
| | 784 | 95 | | { |
| | 226 | 96 | | PaletteType.Elevation1 => theme.Elevation1, |
| | 2 | 97 | | PaletteType.Elevation2 => theme.Elevation2, |
| | 2 | 98 | | PaletteType.Elevation3 => theme.Elevation3, |
| | 2 | 99 | | PaletteType.Elevation4 => theme.Elevation4, |
| | 2 | 100 | | PaletteType.Elevation5 => theme.Elevation5, |
| | 14 | 101 | | PaletteType.Error => theme.Error, |
| | 2 | 102 | | PaletteType.Info => theme.Info, |
| | 226 | 103 | | PaletteType.Primary => theme.Primary, |
| | 30 | 104 | | PaletteType.Secondary => theme.Secondary, |
| | 2 | 105 | | PaletteType.Success => theme.Success, |
| | 270 | 106 | | PaletteType.Surface => theme.Surface, |
| | 2 | 107 | | PaletteType.Tertiary => theme.Tertiary, |
| | 2 | 108 | | PaletteType.Warning => theme.Warning, |
| | 2 | 109 | | _ => theme.Surface |
| | 784 | 110 | | }; |
| | | 111 | | |
| | | 112 | | /// <summary> |
| | | 113 | | /// Generates a list of <see cref="ThemeUpdater" /> instances representing color mappings for a component type. |
| | | 114 | | /// </summary> |
| | | 115 | | /// <param name="isHighContrast">Indicates whether high-contrast colors should be used.</param> |
| | | 116 | | /// <param name="isVariant">Specifies whether to use variant color mappings.</param> |
| | | 117 | | /// <param name="paletteType">The <see cref="PaletteType" /> indicating which color family to map.</param> |
| | | 118 | | /// <param name="componentType">The <see cref="ComponentType" /> representing the styled component.</param> |
| | | 119 | | /// <param name="styleType">The <see cref="StyleType" /> to which the color applies.</param> |
| | | 120 | | /// <param name="getColor"> |
| | | 121 | | /// A delegate selecting which <see cref="HexColor" /> to extract from a <see cref="BrandPalette" /> |
| | | 122 | | /// . |
| | | 123 | | /// </param> |
| | | 124 | | /// <returns>A list of <see cref="ThemeUpdater" /> instances for applying the derived colors.</returns> |
| | | 125 | | public IReadOnlyList<ThemeUpdater> GetColors(bool isHighContrast, |
| | | 126 | | bool isVariant, |
| | | 127 | | PaletteType paletteType, |
| | | 128 | | ComponentType componentType, |
| | | 129 | | StyleType styleType, |
| | | 130 | | Func<BrandPalette, HexColor?> getColor) |
| | | 131 | | { |
| | 392 | 132 | | var list = new List<ThemeUpdater>(); |
| | | 133 | | |
| | 392 | 134 | | var brand = isHighContrast |
| | 392 | 135 | | ? _highContrast |
| | 392 | 136 | | : _brand; |
| | | 137 | | |
| | 392 | 138 | | var themeMap = isVariant |
| | 392 | 139 | | ? BuildThemeVariantMap(brand: brand, isHighContrast: isHighContrast) |
| | 392 | 140 | | : BuildThemeMap(brand: brand, isHighContrast: isHighContrast); |
| | | 141 | | |
| | 2352 | 142 | | foreach ((var themeItem, var themeType) in themeMap) |
| | | 143 | | { |
| | 784 | 144 | | var brandState = GetBrandState(theme: themeItem, paletteType: paletteType); |
| | 784 | 145 | | var paletteMap = BuildPaletteMap(state: brandState); |
| | | 146 | | |
| | 12544 | 147 | | foreach ((var palette, var state) in paletteMap) |
| | | 148 | | { |
| | 5488 | 149 | | var color = getColor(arg: palette); |
| | | 150 | | |
| | 5488 | 151 | | if (color is not null) |
| | | 152 | | { |
| | 5474 | 153 | | list.Add( |
| | 5474 | 154 | | item: new ThemeUpdater( |
| | 5474 | 155 | | Navigator: ThemeNavigator.Initialize |
| | 5474 | 156 | | .SetComponentTypes(componentType) |
| | 5474 | 157 | | .SetThemeTypes(themeType) |
| | 5474 | 158 | | .SetComponentStates(state) |
| | 5474 | 159 | | .SetStyleTypes(styleType), |
| | 5474 | 160 | | Value: new StyleColor(color: color.Value) |
| | 5474 | 161 | | ) |
| | 5474 | 162 | | ); |
| | | 163 | | } |
| | | 164 | | } |
| | | 165 | | } |
| | | 166 | | |
| | 392 | 167 | | return list; |
| | | 168 | | } |
| | | 169 | | |
| | | 170 | | /// <summary> |
| | | 171 | | /// Creates a <see cref="ThemeUpdater" /> that maps the appropriate font family from the current <see cref="Brand" / |
| | | 172 | | /// its high-contrast counterpart. |
| | | 173 | | /// </summary> |
| | | 174 | | /// <param name="isHighContrast">Specifies whether to use high-contrast font mapping.</param> |
| | | 175 | | /// <param name="componentType">The <see cref="ComponentType" /> for which the font applies.</param> |
| | | 176 | | /// <param name="fontType">The <see cref="FontFaceType" /> defining which font family to use.</param> |
| | | 177 | | /// <returns>A <see cref="ThemeUpdater" /> containing a <see cref="StyleString" /> with the selected font family.</r |
| | | 178 | | public ThemeUpdater GetFont(bool isHighContrast, ComponentType componentType, FontFaceType fontType) |
| | | 179 | | { |
| | 24 | 180 | | var brand = isHighContrast |
| | 24 | 181 | | ? _highContrast |
| | 24 | 182 | | : _brand; |
| | | 183 | | |
| | 24 | 184 | | var fontFace = fontType switch |
| | 24 | 185 | | { |
| | 1 | 186 | | FontFaceType.Monospace => brand.Font.Monospace, |
| | 21 | 187 | | FontFaceType.SansSerif => brand.Font.SansSerif, |
| | 1 | 188 | | FontFaceType.Serif => brand.Font.Serif, |
| | 1 | 189 | | _ => brand.Font.SansSerif |
| | 24 | 190 | | }; |
| | | 191 | | |
| | 24 | 192 | | return new ThemeUpdater( |
| | 24 | 193 | | Navigator: ThemeNavigator.Initialize |
| | 24 | 194 | | .SetComponentTypes(componentType) |
| | 24 | 195 | | .SetContrastThemeTypes(isHighContrast: isHighContrast) |
| | 24 | 196 | | .SetAllComponentStates() |
| | 24 | 197 | | .SetStyleTypes(StyleType.FontFamily), |
| | 24 | 198 | | Value: new StyleString(value: fontFace) |
| | 24 | 199 | | ); |
| | | 200 | | } |
| | | 201 | | } |