From 9694f15b1cb174fb3372871beb2a35284529eb76 Mon Sep 17 00:00:00 2001 From: Cody Mullins <joshua.c.mullins@gmail.com> Date: Sat, 4 May 2024 14:54:11 -0400 Subject: [PATCH 1/2] Fix theme customization issues --- .../HostApplicationBuilderExtensions.cs | 4 +- .../ComponentStyle.cs | 22 +++--- .../IPureTheme.cs | 19 ----- .../PureComponent.cs | 2 +- .../PureTheme.cs | 51 ++++++++++++ .../Common/DefaultTheme.cs | 77 +++++++++---------- .../WebAssemblyHostBuilderExtensions.cs | 4 +- 7 files changed, 105 insertions(+), 74 deletions(-) delete mode 100644 src/Pure.Blazor.Components.Primitives/IPureTheme.cs create mode 100644 src/Pure.Blazor.Components.Primitives/PureTheme.cs diff --git a/src/Pure.Blazor.Components.AspNetCore/HostApplicationBuilderExtensions.cs b/src/Pure.Blazor.Components.AspNetCore/HostApplicationBuilderExtensions.cs index b42d734..44d9954 100644 --- a/src/Pure.Blazor.Components.AspNetCore/HostApplicationBuilderExtensions.cs +++ b/src/Pure.Blazor.Components.AspNetCore/HostApplicationBuilderExtensions.cs @@ -12,7 +12,7 @@ namespace Pure.Blazor.Components.AspNetCore; public static class HostApplicationBuilderExtensions { public static IHostApplicationBuilder AddPureBlazorComponents(this IHostApplicationBuilder builder, - IPureTheme? theme = null) + PureTheme? theme = null) { // javascript builder.Services.AddScoped<IElementUtils, ElementUtils>(); @@ -24,7 +24,7 @@ public static IHostApplicationBuilder AddPureBlazorComponents(this IHostApplicat builder.Services.AddCascadingValue(sp => { theme ??= new DefaultTheme(); - var source = new CascadingValueSource<IPureTheme>(theme, isFixed: true); + var source = new CascadingValueSource<PureTheme>(theme, isFixed: true); return source; }); diff --git a/src/Pure.Blazor.Components.Primitives/ComponentStyle.cs b/src/Pure.Blazor.Components.Primitives/ComponentStyle.cs index 032bb8a..fed06b5 100644 --- a/src/Pure.Blazor.Components.Primitives/ComponentStyle.cs +++ b/src/Pure.Blazor.Components.Primitives/ComponentStyle.cs @@ -1,19 +1,19 @@ namespace Pure.Blazor.Components.Primitives; -public class ComponentStyle +public record ComponentStyle { - private readonly IReadOnlyDictionary<Accent, string> accents; - private readonly IReadOnlyDictionary<PureVariant, Dictionary<Accent, string>> variants; - private readonly IReadOnlyDictionary<PureSize, string> sizes; + public readonly IReadOnlyDictionary<Accent, string> Accents; + public readonly IReadOnlyDictionary<PureVariant, Dictionary<Accent, string>> Variants; + public readonly IReadOnlyDictionary<PureSize, string> Sizes; public ComponentStyle(string baseStyle, IReadOnlyDictionary<Accent, string>? accents, IReadOnlyDictionary<PureVariant, Dictionary<Accent, string>>? variants, IReadOnlyDictionary<PureSize, string>? sizes) { - this.accents = accents ?? new Dictionary<Accent, string>(); - this.variants = variants ?? new Dictionary<PureVariant, Dictionary<Accent, string>>(); - this.sizes = sizes ?? new Dictionary<PureSize, string>(); + this.Accents = accents ?? new Dictionary<Accent, string>(); + this.Variants = variants ?? new Dictionary<PureVariant, Dictionary<Accent, string>>(); + this.Sizes = sizes ?? new Dictionary<PureSize, string>(); Base = baseStyle; } @@ -36,12 +36,12 @@ public ComponentStyle(string baseStyle, public string Accent(Accent accent) { - return accents.TryGetValue(accent, out var value) ? value : string.Empty; + return Accents.TryGetValue(accent, out var value) ? value : string.Empty; } public string Variant(PureVariant variant, Accent accent) { - if (variants.TryGetValue(variant, out var value) && value.TryGetValue(accent, out var style)) + if (Variants.TryGetValue(variant, out var value) && value.TryGetValue(accent, out var style)) { return style; } @@ -51,6 +51,6 @@ public string Variant(PureVariant variant, Accent accent) public string Size(PureSize size) { - return sizes.TryGetValue(size, out var value) ? value : string.Empty; + return Sizes.TryGetValue(size, out var value) ? value : string.Empty; } -} \ No newline at end of file +} diff --git a/src/Pure.Blazor.Components.Primitives/IPureTheme.cs b/src/Pure.Blazor.Components.Primitives/IPureTheme.cs deleted file mode 100644 index 6715625..0000000 --- a/src/Pure.Blazor.Components.Primitives/IPureTheme.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace Pure.Blazor.Components.Primitives; - -public interface IPureTheme -{ - public ButtonDefaults ButtonDefaults { get; set; } - public IStylePrioritizer StylePrioritizer { get; set; } - public Dictionary<string, ComponentStyle> Styles { get; set; } - - public ComponentStyle GetStyle(Type type) - { - return GetStyleByName(type.Name); - } - - public ComponentStyle GetStyleByName(string name) - { - // TODO: decide if we want this to be an exceptional event - return Styles.GetValueOrDefault(name) ?? new ComponentStyle("", null, null, null); - } -} diff --git a/src/Pure.Blazor.Components.Primitives/PureComponent.cs b/src/Pure.Blazor.Components.Primitives/PureComponent.cs index 99f8229..1f6e73d 100644 --- a/src/Pure.Blazor.Components.Primitives/PureComponent.cs +++ b/src/Pure.Blazor.Components.Primitives/PureComponent.cs @@ -26,7 +26,7 @@ protected override void OnParametersSet() /// The current theme styles /// </summary> [CascadingParameter] - public required IPureTheme PureTheme { get; set; } + public required PureTheme PureTheme { get; set; } [Parameter] public RenderFragment? ChildContent { get; set; } diff --git a/src/Pure.Blazor.Components.Primitives/PureTheme.cs b/src/Pure.Blazor.Components.Primitives/PureTheme.cs new file mode 100644 index 0000000..2e7c011 --- /dev/null +++ b/src/Pure.Blazor.Components.Primitives/PureTheme.cs @@ -0,0 +1,51 @@ +namespace Pure.Blazor.Components.Primitives; + +public record PureTheme +{ + public ButtonDefaults ButtonDefaults { get; set; } = new(); + public IStylePrioritizer? StylePrioritizer { get; set; } + public Dictionary<string, ComponentStyle> Styles { get; set; } = new(); + + public ComponentStyle GetStyle(Type type) + { + return GetStyleByName(type.Name); + } + + public ComponentStyle GetStyleByName(string name) + { + // TODO: decide if we want this to be an exceptional event + return Styles.GetValueOrDefault(name) ?? new ComponentStyle("", null, null, null); + } + + /// <summary> + /// Merges the styles into the current theme, overwriting any existing styles. + /// </summary> + /// <param name="styles"></param> + public void Merge(Dictionary<string, ComponentStyle> styles) + { + Styles = Styles.MergeLeft(styles); + } +} + +internal static class DictionaryExtensions +{ + // Works in C#3/VS2008: + // Returns a new dictionary of this ... others merged leftward. + // Keeps the type of 'this', which must be default-instantiable. + // Example: + // result = map.MergeLeft(other1, other2, ...) + public static T MergeLeft<T,K,V>(this T me, params IDictionary<K,V>[] others) + where T : IDictionary<K,V>, new() + { + T newMap = new T(); + foreach (IDictionary<K,V> src in + (new List<IDictionary<K,V>> { me }).Concat(others)) { + // ^-- echk. Not quite there type-system. + foreach (KeyValuePair<K,V> p in src) { + newMap[p.Key] = p.Value; + } + } + return newMap; + } + +} diff --git a/src/Pure.Blazor.Components/Common/DefaultTheme.cs b/src/Pure.Blazor.Components/Common/DefaultTheme.cs index 98fe476..17f7f98 100644 --- a/src/Pure.Blazor.Components/Common/DefaultTheme.cs +++ b/src/Pure.Blazor.Components/Common/DefaultTheme.cs @@ -6,50 +6,49 @@ namespace Pure.Blazor.Components.Common; -public class DefaultTheme : IPureTheme +public record DefaultTheme : PureTheme { - public ButtonDefaults ButtonDefaults { get; set; } = new() + public DefaultTheme() { - PressEffect = Effect.InsetShadow, - HoverEffect = Effect.Unset - }; - - public IStylePrioritizer StylePrioritizer { get; set; } = new StylePrioritizer(); - public Dictionary<string, ComponentStyle> Styles { get; set; } = new() - { - { - nameof(PureButton), - new ComponentStyle(ButtonStyles.Base, null, ButtonStyles.Variants, ButtonStyles.Sizes) - }, + ButtonDefaults.PressEffect = Effect.InsetShadow; + ButtonDefaults.HoverEffect = Effect.Unset; + StylePrioritizer = new StylePrioritizer(); + Styles = new Dictionary<string, ComponentStyle> { - nameof(PureIconButton), - new ComponentStyle(ButtonStyles.Base, null, ButtonStyles.Variants, ButtonStyles.Sizes) - }, - { - nameof(PureDropdown), - new ComponentStyle(DropdownStyles.Base, null, null, DropdownStyles.Sizes) { - InnerContainer = new ComponentStyle(DropdownStyles.Container.Base, null, null, null) - } - }, - { - nameof(PureDropdownItem), - new ComponentStyle(DropdownStyles.MenuItem.Base, DropdownStyles.MenuItem.Accents, null, - DropdownStyles.MenuItem.Sizes) - }, - { nameof(PureBanner), new ComponentStyle(BannerStyles.Base, null, BannerStyles.Variants, null) }, - { nameof(PureLink), new ComponentStyle(LinkStyles.Base, null, null, null) }, - { nameof(PureBadge), new ComponentStyle("", null, BadgeStyles.Variants, null) }, - { nameof(PureAlert), new ComponentStyle(AlertStyles.Base, AlertStyles.Accents, null, null) }, - { - nameof(PureColorIndicator), - new ComponentStyle("", null, null, null) + nameof(PureButton), + new ComponentStyle(ButtonStyles.Base, null, ButtonStyles.Variants, ButtonStyles.Sizes) + }, + { + nameof(PureIconButton), + new ComponentStyle(ButtonStyles.Base, null, ButtonStyles.Variants, ButtonStyles.Sizes) + }, + { + nameof(PureDropdown), + new ComponentStyle(DropdownStyles.Base, null, null, DropdownStyles.Sizes) + { + InnerContainer = new ComponentStyle(DropdownStyles.Container.Base, null, null, null) + } + }, + { + nameof(PureDropdownItem), + new ComponentStyle(DropdownStyles.MenuItem.Base, DropdownStyles.MenuItem.Accents, null, + DropdownStyles.MenuItem.Sizes) + }, + { nameof(PureBanner), new ComponentStyle(BannerStyles.Base, null, BannerStyles.Variants, null) }, + { nameof(PureLink), new ComponentStyle(LinkStyles.Base, null, null, null) }, + { nameof(PureBadge), new ComponentStyle("", null, BadgeStyles.Variants, null) }, + { nameof(PureAlert), new ComponentStyle(AlertStyles.Base, AlertStyles.Accents, null, null) }, { - InnerContainer = new ComponentStyle("", IndicatorStyles.Background, null, null) + nameof(PureColorIndicator), + new ComponentStyle("", null, null, null) { - OuterContainer = new ComponentStyle("", IndicatorStyles.Foreground, null, null) + InnerContainer = new ComponentStyle("", IndicatorStyles.Background, null, null) + { + OuterContainer = new ComponentStyle("", IndicatorStyles.Foreground, null, null) + } } - } - }, - }; + }, + }; + } } diff --git a/src/Pure.Blazor.Components/WebAssemblyHostBuilderExtensions.cs b/src/Pure.Blazor.Components/WebAssemblyHostBuilderExtensions.cs index 09c1093..189308a 100644 --- a/src/Pure.Blazor.Components/WebAssemblyHostBuilderExtensions.cs +++ b/src/Pure.Blazor.Components/WebAssemblyHostBuilderExtensions.cs @@ -12,7 +12,7 @@ namespace Pure.Blazor.Components; public static class WebAssemblyHostBuilderExtensions { public static WebAssemblyHostBuilder AddPureBlazorComponents(this WebAssemblyHostBuilder builder, - IPureTheme? theme = null) + PureTheme? theme = null) { // javascript builder.Services.AddSingleton<IElementUtils, ElementUtils>(); @@ -23,7 +23,7 @@ public static WebAssemblyHostBuilder AddPureBlazorComponents(this WebAssemblyHos builder.Services.AddCascadingValue(sp => { theme ??= new DefaultTheme(); - var source = new CascadingValueSource<IPureTheme>(theme, isFixed: true); + var source = new CascadingValueSource<PureTheme>(theme, isFixed: true); return source; }); return builder; From afa9efeec02bf948920f428024a86d2814526ef9 Mon Sep 17 00:00:00 2001 From: Cody Mullins <joshua.c.mullins@gmail.com> Date: Sat, 4 May 2024 15:05:14 -0400 Subject: [PATCH 2/2] add missing attribution --- src/Pure.Blazor.Components.Primitives/PureTheme.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Pure.Blazor.Components.Primitives/PureTheme.cs b/src/Pure.Blazor.Components.Primitives/PureTheme.cs index 2e7c011..db7146a 100644 --- a/src/Pure.Blazor.Components.Primitives/PureTheme.cs +++ b/src/Pure.Blazor.Components.Primitives/PureTheme.cs @@ -27,6 +27,7 @@ public void Merge(Dictionary<string, ComponentStyle> styles) } } +// https://stackoverflow.com/a/2679857/783284 internal static class DictionaryExtensions { // Works in C#3/VS2008: