| | | 1 | | namespace Allyaria.Theming.ThemeTypes; |
| | | 2 | | |
| | | 3 | | /// <summary> |
| | | 4 | | /// Represents the state-level layer of the Allyaria theming hierarchy, managing <see cref="ThemeStyle" /> instances for |
| | | 5 | | /// each <see cref="ComponentState" />. |
| | | 6 | | /// </summary> |
| | | 7 | | /// <remarks> |
| | | 8 | | /// <para> |
| | | 9 | | /// Each <see cref="ThemeState" /> corresponds to a single <see cref="ThemeType" /> variant and contains one or more |
| | | 10 | | /// <see cref="ThemeStyle" /> objects, each mapped to a specific <see cref="ComponentState" /> such as <c>Default</c |
| | | 11 | | /// <c>Hovered</c>, or <c>Focused</c>. |
| | | 12 | | /// </para> |
| | | 13 | | /// <para> |
| | | 14 | | /// The class is responsible for building CSS rules at the component-state level and propagating updates via |
| | | 15 | | /// <see cref="ThemeUpdater" /> through the theming hierarchy. |
| | | 16 | | /// </para> |
| | | 17 | | /// </remarks> |
| | | 18 | | internal sealed class ThemeState |
| | | 19 | | { |
| | | 20 | | /// <summary> |
| | | 21 | | /// A mapping of <see cref="ComponentState" /> values to their respective <see cref="ThemeStyle" /> definitions. |
| | | 22 | | /// </summary> |
| | 408 | 23 | | private readonly Dictionary<ComponentState, ThemeStyle> _children = new(); |
| | | 24 | | |
| | | 25 | | /// <summary> |
| | | 26 | | /// Builds the CSS representation of this theme state and its associated <see cref="ThemeStyle" /> instances. |
| | | 27 | | /// </summary> |
| | | 28 | | /// <param name="builder">The <see cref="CssBuilder" /> used to accumulate CSS output.</param> |
| | | 29 | | /// <param name="navigator"> |
| | | 30 | | /// The <see cref="ThemeNavigator" /> defining the current traversal scope (components, themes, states, styles). |
| | | 31 | | /// </param> |
| | | 32 | | /// <param name="varPrefix">An optional variable prefix used to build scoped CSS variable names.</param> |
| | | 33 | | /// <returns>A <see cref="CssBuilder" /> containing the merged CSS for all applicable component states.</returns> |
| | | 34 | | internal CssBuilder BuildCss(CssBuilder builder, ThemeNavigator navigator, string? varPrefix = "") |
| | | 35 | | { |
| | 41 | 36 | | if (navigator.ComponentStates.Count is 0) |
| | | 37 | | { |
| | 36 | 38 | | foreach (var child in _children) |
| | | 39 | | { |
| | 9 | 40 | | builder = child.Value.BuildCss( |
| | 9 | 41 | | builder: builder, |
| | 9 | 42 | | navigator: navigator, |
| | 9 | 43 | | varPrefix: SetPrefix(varPrefix: varPrefix, type: child.Key) |
| | 9 | 44 | | ); |
| | | 45 | | } |
| | | 46 | | } |
| | | 47 | | else |
| | | 48 | | { |
| | 130 | 49 | | foreach (var key in navigator.ComponentStates) |
| | | 50 | | { |
| | 33 | 51 | | builder = Get(key: key)?.BuildCss( |
| | 33 | 52 | | builder: builder, |
| | 33 | 53 | | navigator: navigator, |
| | 33 | 54 | | varPrefix: SetPrefix(varPrefix: varPrefix, type: key) |
| | 33 | 55 | | ) ?? builder; |
| | | 56 | | } |
| | | 57 | | } |
| | | 58 | | |
| | 41 | 59 | | return builder; |
| | | 60 | | } |
| | | 61 | | |
| | | 62 | | /// <summary> |
| | | 63 | | /// Retrieves the <see cref="ThemeStyle" /> associated with a given <see cref="ComponentState" />, if available. |
| | | 64 | | /// </summary> |
| | | 65 | | /// <param name="key">The <see cref="ComponentState" /> to retrieve.</param> |
| | | 66 | | /// <returns>The corresponding <see cref="ThemeStyle" /> if found; otherwise, <see langword="null" />.</returns> |
| | 17534 | 67 | | private ThemeStyle? Get(ComponentState key) => _children.GetValueOrDefault(key: key); |
| | | 68 | | |
| | | 69 | | /// <summary> |
| | | 70 | | /// Applies a <see cref="ThemeUpdater" /> to modify or add <see cref="ThemeStyle" /> entries associated with the spe |
| | | 71 | | /// <see cref="ComponentState" /> values. |
| | | 72 | | /// </summary> |
| | | 73 | | /// <param name="updater">The <see cref="ThemeUpdater" /> defining the update operation.</param> |
| | | 74 | | /// <returns>The same <see cref="ThemeState" /> instance, enabling fluent configuration.</returns> |
| | | 75 | | internal ThemeState Set(ThemeUpdater updater) |
| | | 76 | | { |
| | 48114 | 77 | | foreach (var key in updater.Navigator.ComponentStates) |
| | | 78 | | { |
| | 17501 | 79 | | if (!_children.ContainsKey(key: key)) |
| | | 80 | | { |
| | 2713 | 81 | | _children.Add(key: key, value: new ThemeStyle()); |
| | | 82 | | } |
| | | 83 | | |
| | 17501 | 84 | | Get(key: key)?.Set(updater: updater); |
| | | 85 | | } |
| | | 86 | | |
| | 6556 | 87 | | return this; |
| | | 88 | | } |
| | | 89 | | |
| | | 90 | | /// <summary>Constructs a hierarchical CSS variable prefix combining the provided prefix and component state.</summa |
| | | 91 | | /// <param name="varPrefix">The current prefix string, if any.</param> |
| | | 92 | | /// <param name="type">The <see cref="ComponentState" /> to append.</param> |
| | | 93 | | /// <returns>A CSS-safe prefix string used for scoped variable naming.</returns> |
| | | 94 | | private static string SetPrefix(string? varPrefix, ComponentState type) |
| | | 95 | | { |
| | 32 | 96 | | var prefix = varPrefix?.ToCssName() ?? string.Empty; |
| | | 97 | | |
| | 32 | 98 | | return string.IsNullOrWhiteSpace(value: prefix) |
| | 32 | 99 | | ? string.Empty |
| | 32 | 100 | | : $"{prefix}-{type}".ToCssName(); |
| | | 101 | | } |
| | | 102 | | } |