Use the first button go swith bewteen dark and light mode. Click the second button to toggle the accent and neutral colors. The third button has a custom font, and the last one has a custom border width and corner radius.
+
+ As can be seen in the code tab (with the `ref4.Element`), it is possible to apply multiple tokens to the same component.
+
+
+
+ For Design Tokens that work with a color value, you must call the ToSwatch() extension method* on a string value or use one of the Swatch constructors. This
+ makes sure the color is using a format that Design Tokens can handle. A Swatch has a lot of commonality with the System.Drawing.Color struct. Instead of
+ the values of the components being between 0 and 255, in a Swatch the components are expressed as a value between 0 and 1
+
+
* except for the AccentBaseColor and NeutralBaseColor. These just take a hex value as a string for the color.
+
+
+
+
Colors for integration with specific Microsoft products
+
+ If you are configuring the components for integration into a specific Microsoft product, the following table provides `AccentBaseColor` values you can use.
+ The specific accent colors for many Office applications are offered in the `OfficeColor` enumeration.
+
+
@if (refreshCount > 0)
{
diff --git a/examples/Demo/Shared/Pages/Design/Examples/DesignTokensDefault.razor b/examples/Demo/Shared/Pages/Design/Examples/DesignTokensDefault.razor
new file mode 100644
index 0000000000..3bccf11a68
--- /dev/null
+++ b/examples/Demo/Shared/Pages/Design/Examples/DesignTokensDefault.razor
@@ -0,0 +1,74 @@
+@using Microsoft.FluentUI.AspNetCore.Components.DesignTokens
+
+Dark/Light
+Accent button
+And one more
+Last button
+
+
+@code {
+ [Inject]
+ private BaseLayerLuminance BaseLayerLuminance { get; set; } = default!;
+
+ [Inject]
+ private AccentBaseColor AccentBaseColor { get; set; } = default!;
+
+ [Inject]
+ private NeutralBaseColor NeutralBaseColor { get; set; } = default!;
+
+ [Inject]
+ private BodyFont BodyFont { get; set; } = default!;
+
+ [Inject]
+ private StrokeWidth StrokeWidth { get; set; } = default!;
+
+ [Inject]
+ private ControlCornerRadius ControlCornerRadius { get; set; } = default!;
+
+ private FluentButton? ref1;
+ private FluentButton? ref2;
+ private FluentButton? ref3;
+ private FluentButton? ref4;
+
+ protected override async Task OnAfterRenderAsync(bool firstRender)
+ {
+ if (firstRender)
+ {
+ //Set to dark mode
+ //await BaseLayerLuminance.SetValueFor(ref1!.Element, (float)0.15);
+
+ //Set the font
+ await BodyFont.SetValueFor(ref3!.Element, "Comic Sans MS");
+
+ //Set 'border' width for ref4
+ await StrokeWidth.SetValueFor(ref4!.Element, 7);
+ //And change conrner radius as well
+ await ControlCornerRadius.SetValueFor(ref4!.Element, 15);
+
+ StateHasChanged();
+ }
+ }
+
+ public async Task OnClickFirst()
+ {
+ float? value = await BaseLayerLuminance.GetValueFor(ref1!.Element);
+ //Set to light mode
+ await BaseLayerLuminance.WithDefault(value == 0.15f ? (float)1.0 : (float)0.15);
+ }
+
+ public async Task OnClickSecond()
+ {
+ Swatch accent = await AccentBaseColor.GetValueFor(ref2!.Element);
+ Swatch neutral = await NeutralBaseColor.GetValueFor(ref2!.Element);
+
+ await AccentBaseColor.WithDefault(accent.B == (float)0.274509817 ? "#0078D4" : "#217346");
+ await NeutralBaseColor.WithDefault(neutral.B == (float)0.3372549 ? "#808080" : "#c75656");
+ }
+
+ public async Task OnClickLast()
+ {
+ //Remove the wide border
+ await StrokeWidth.DeleteValueFor(ref4!.Element);
+ }
+
+}
diff --git a/examples/Demo/Shared/Pages/Lab/IssueTester.razor b/examples/Demo/Shared/Pages/Lab/IssueTester.razor
index 5f282702bb..8bcfb12f9d 100644
--- a/examples/Demo/Shared/Pages/Lab/IssueTester.razor
+++ b/examples/Demo/Shared/Pages/Lab/IssueTester.razor
@@ -1 +1,68 @@
-
\ No newline at end of file
+@using Microsoft.FluentUI.AspNetCore.Components.DesignTokens
+
+Dark/Light
+Accent button
+And one more
+Last button
+
+
+@code {
+ [Inject]
+ private BaseLayerLuminance BaseLayerLuminance { get; set; } = default!;
+
+ [Inject]
+ private AccentBaseColor AccentBaseColor { get; set; } = default!;
+
+ [Inject]
+ private NeutralBaseColor NeutralBaseColor { get; set; } = default!;
+
+ [Inject]
+ private BodyFont BodyFont { get; set; } = default!;
+
+ [Inject]
+ private StrokeWidth StrokeWidth { get; set; } = default!;
+
+ [Inject]
+ private ControlCornerRadius ControlCornerRadius { get; set; } = default!;
+
+ private FluentButton? ref1;
+ private FluentButton? ref2;
+ private FluentButton? ref3;
+ private FluentButton? ref4;
+
+ protected override async Task OnAfterRenderAsync(bool firstRender)
+ {
+ if (firstRender)
+ {
+ //Set to dark mode
+ //await BaseLayerLuminance.SetValueFor(ref1!.Element, (float)0.15);
+
+ //Set the font
+ await BodyFont.SetValueFor(ref3!.Element, "Comic Sans MS");
+
+ //Set 'border' width for ref4
+ await StrokeWidth.SetValueFor(ref4!.Element, 7);
+ //And change conrner radius as well
+ await ControlCornerRadius.SetValueFor(ref4!.Element, 15);
+
+ await AccentBaseColor.WithDefault("#217346");
+ await NeutralBaseColor.WithDefault("#c75656");
+
+ StateHasChanged();
+ }
+ }
+
+ public async Task OnClickFirst()
+ {
+ float? value = await BaseLayerLuminance.GetValueFor(ref1!.Element);
+ //Set to light mode
+ await BaseLayerLuminance.WithDefault(value == 0.15f ? (float)1.0 : (float)0.15);
+ }
+
+ public async Task OnClickLast()
+ {
+ //Remove the wide border
+ await StrokeWidth.DeleteValueFor(ref4!.Element);
+ }
+
+}
diff --git a/examples/Demo/Shared/wwwroot/docs/DesignTokens.md b/examples/Demo/Shared/wwwroot/docs/DesignTokens.md
index 4e6af245cc..34af0d1e6e 100644
--- a/examples/Demo/Shared/wwwroot/docs/DesignTokens.md
+++ b/examples/Demo/Shared/wwwroot/docs/DesignTokens.md
@@ -237,78 +237,7 @@ There are a couple of methods available **per design token** to get or set its v
- `{DesignTokenName}.WithDefault(T value)` - Sets the default value for the whole design system use.
- `{DesignTokenName}.GetValueFor(ElementReference element)` - Gets the value for the given element.- `
-#### Example
-Given the following `.razor` page fragment:
-
-```cshtml
-A button
-Another button
-And one more
-Last button
-```
-
-You can use Design Tokens to manipulate the styles from C# code as follows:
-
-```csharp
-@using Microsoft.FluentUI.AspNetCore.Components.DesignTokens
-
-[Inject]
-private BaseLayerLuminance BaseLayerLuminance { get; set; } = default!;
-
-[Inject]
-private AccentBaseColor AccentBaseColor { get; set; } = default!;
-
-[Inject]
-private BodyFont BodyFont { get; set; } = default!;
-
-[Inject]
-private StrokeWidth StrokeWidth { get; set; } = default!;
-
-[Inject]
-private ControlCornerRadius ControlCornerRadius { get; set; } = default!;
-
-private FluentButton? ref1;
-private FluentButton? ref2;
-private FluentButton? ref3;
-private FluentButton? ref4;
-protected override async Task OnAfterRenderAsync(bool firstRender)
-{
- if (firstRender)
- {
- //Set to dark mode
- await BaseLayerLuminance.SetValueFor(ref1!.Element, (float)0.15);
-
- //Set to Excel color
- await AccentBaseColor.SetValueFor(ref2!.Element, "#217346".ToSwatch());
-
- //Set the font
- await BodyFont.SetValueFor(ref3!.Element, "Comic Sans MS");
-
- //Set 'border' width for ref4
- await StrokeWidth.SetValueFor(ref4!.Element, 7);
- //And change conrner radius as well
- await ControlCornerRadius.SetValueFor(ref4!.Element, 15);
-
- // If you would like to change the BaseLayerLuminance value for the whole site, you can use the WithDefault method
- await BaseLayerLuminance.WithDefault((float)0.15);
-
- StateHasChanged();
- }
-}
-
-public async Task OnClick()
-{
- //Remove the wide border
- await StrokeWidth.DeleteValueFor(ref4!.Element);
-}
-```
-
-As can be seen in the code above (with the `ref4.Element`), it is possible to apply multiple tokens to the same component.
-
-For Design Tokens that work with a color value, you must call the `ToSwatch()` extension method on a string value or use one of the Swatch constructors. This
-makes sure the color is using a format that Design Tokens can handle. A Swatch has a lot of commonality with the `System.Drawing.Color` struct. Instead of
-the values of the components being between 0 and 255, in a Swatch the components are expressed as a value between 0 and 1.
### Using Design Tokens as components
The Design Tokens can also be used as components in a `.razor` page directely. It looks like this:
@@ -334,6 +263,3 @@ To make this work, a link needs to be created between the Design Token component
> Only one Design Token component at a time can be used this way. If you need to set more tokens, use the code approach as described in Option 1 above.
-## Colors for integration with specific Microsoft products
-If you are configuring the components for integration into a specific Microsoft product, the following table provides `AccentBaseColor` values you can use.
-*The specific accent colors for many Office applications are offered in the `OfficeColor` enumeration.*
diff --git a/src/Core.Assets/src/Design/ColorsUtils.ts b/src/Core.Assets/src/Design/ColorsUtils.ts
index 7a9edd80a0..d14eb716ce 100644
--- a/src/Core.Assets/src/Design/ColorsUtils.ts
+++ b/src/Core.Assets/src/Design/ColorsUtils.ts
@@ -4,53 +4,6 @@ class ColorsUtils {
return (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches);
}
- /**
- * See https://github.com/microsoft/fast -> packages/utilities/fast-colors/src/parse-color.ts
- */
- public static parseColorHexRGB(raw: string | null): ColorRGB | null {
- // Matches #RGB and #RRGGBB, where R, G, and B are [0-9] or [A-F]
- const hexRGBRegex: RegExp = /^#((?:[0-9a-f]{6}|[0-9a-f]{3}))$/i;
- const result: string[] | null = hexRGBRegex.exec(raw ?? ColorsUtils.DEFAULT_COLOR);
-
- if (result === null) {
- return null;
- }
-
- let digits: string = result[1];
-
- if (digits.length === 3) {
- const r: string = digits.charAt(0);
- const g: string = digits.charAt(1);
- const b: string = digits.charAt(2);
-
- digits = r.concat(r, g, g, b, b);
- }
-
- const rawInt: number = parseInt(digits, 16);
-
- if (isNaN(rawInt)) {
- return null;
- }
-
- return new ColorRGB(
- this.normalized((rawInt & 0xff0000) >>> 16, 0, 255),
- this.normalized((rawInt & 0x00ff00) >>> 8, 0, 255),
- this.normalized(rawInt & 0x0000ff, 0, 255),
- );
- }
-
- /**
- * Scales an input to a number between 0 and 1
- */
- public static normalized(i: number, min: number, max: number): number {
- if (isNaN(i) || i <= min) {
- return 0.0;
- } else if (i >= max) {
- return 1.0;
- }
- return i / (max - min);
- }
-
/**
* Convert to named color to an equivalent Hex color
* @param name Office color name
@@ -94,16 +47,4 @@ class ColorsUtils {
];
}
-class ColorRGB {
- constructor(red: number, green: number, blue: number) {
- this.r = red;
- this.g = green;
- this.b = blue;
- }
-
- public readonly r: number;
- public readonly g: number;
- public readonly b: number;
-}
-
export { ColorsUtils };
diff --git a/src/Core.Assets/src/DesignTheme.ts b/src/Core.Assets/src/DesignTheme.ts
index d21334a8cb..12c12129c5 100644
--- a/src/Core.Assets/src/DesignTheme.ts
+++ b/src/Core.Assets/src/DesignTheme.ts
@@ -3,6 +3,7 @@
// ********************
import { ColorsUtils } from "./Design/ColorsUtils";
+import { parseColorHexRGB } from '@microsoft/fast-colors'
import {
baseLayerLuminance,
StandardLuminance,
@@ -81,8 +82,8 @@ class DesignTheme extends HTMLElement {
/**
* Gets the current color or office name attribute value.
- * Access, Booking, Exchange, Excel, GroupMe, Office, OneDrive, OneNote, Outlook,
- * Planner, PowerApps, PowerBI, PowerPoint, Project, Publisher, SharePoint, Skype,
+ * Access, Booking, Exchange, Excel, GroupMe, Office, OneDrive, OneNote, Outlook,
+ * Planner, PowerApps, PowerBI, PowerPoint, Project, Publisher, SharePoint, Skype,
* Stream, Sway, Teams, Visio, Windows, Word, Yammer
*/
get primaryColor(): string | null {
@@ -101,7 +102,7 @@ class DesignTheme extends HTMLElement {
: value;
// Apply the color
- const rgb = ColorsUtils.parseColorHexRGB(color);
+ const rgb = parseColorHexRGB(color);
if (rgb != null) {
const swatch = SwatchRGB.from(rgb);
accentBaseColor.withDefault(swatch);
@@ -250,7 +251,7 @@ class DesignTheme extends HTMLElement {
// If not, the dev already "forced" the mode to "dark" or "light"
if (currentMode == null) {
- // console.log(` ** colorSchemeListener = "${currentMode}"`)
+ // console.log(` ** colorSchemeListener = "${currentMode}"`)
// Dark
if (e.matches) {
diff --git a/src/Core.Assets/src/index.ts b/src/Core.Assets/src/index.ts
index 837f31d5ea..a7f22097b6 100644
--- a/src/Core.Assets/src/index.ts
+++ b/src/Core.Assets/src/index.ts
@@ -1,5 +1,9 @@
export * from '@fluentui/web-components/dist/web-components'
export { parseColorHexRGB } from '@microsoft/fast-colors'
+
+import { accentBaseColor, neutralBaseColor, SwatchRGB, } from '@fluentui/web-components/dist/web-components'
+import { parseColorHexRGB } from '@microsoft/fast-colors'
+import { ColorsUtils } from './Design/ColorsUtils'
import { SplitPanels } from './SplitPanels'
import { DesignTheme } from './DesignTheme'
import { FluentPageScript, onEnhancedLoad } from './FluentPageScript'
@@ -28,7 +32,6 @@ interface FluentUIEventType {
type: string;
}
-
var styleSheet = new CSSStyleSheet();
const styles = `
@@ -301,7 +304,7 @@ export function afterStarted(blazor: Blazor, mode: string) {
browserEventName: 'change',
createEventArgs: event => {
return {
- value: event.target._selectedOptions[0] ? event.target._selectedOptions[0].value : event.target.value
+ value: event.target._selectedOptions[0] ? event.target._selectedOptions[0].value : event.target.value
}
}
});
@@ -331,3 +334,21 @@ export function beforeStart(options: any) {
beforeStartCalled = true;
}
+
+export function updateAccentBaseColor(value: string | null) {
+ const color = value == null || !value.startsWith("#") ? ColorsUtils.getHexColor(value) : value;
+ const rgb = parseColorHexRGB(color);
+ if (rgb != null) {
+ const swatch = SwatchRGB.from(rgb);
+ accentBaseColor.withDefault(swatch);
+ }
+}
+
+export function updateNeutralBaseColor(value: string | null) {
+ const color = value == null || !value.startsWith("#") ? ColorsUtils.getHexColor(value) : value;
+ const rgb = parseColorHexRGB(color);
+ if (rgb != null) {
+ const swatch = SwatchRGB.from(rgb);
+ neutralBaseColor.withDefault(swatch);
+ }
+}
diff --git a/src/Core/Components/DesignSystemProvider/FluentDesignTheme.razor.cs b/src/Core/Components/DesignSystemProvider/FluentDesignTheme.razor.cs
index cdadb36c4a..376bad2a5c 100644
--- a/src/Core/Components/DesignSystemProvider/FluentDesignTheme.razor.cs
+++ b/src/Core/Components/DesignSystemProvider/FluentDesignTheme.razor.cs
@@ -1,3 +1,7 @@
+// ------------------------------------------------------------------------
+// MIT License - Copyright (c) Microsoft Corporation. All rights reserved.
+// ------------------------------------------------------------------------
+
using System.Globalization;
using System.Text.Json;
using Microsoft.AspNetCore.Components;
@@ -175,7 +179,7 @@ public async Task OnChangeRaisedAsync(string name, string value)
}
}
- protected async override Task OnAfterRenderAsync(bool firstRender)
+ protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
diff --git a/src/Core/DesignTokens/DesignToken.razor.cs b/src/Core/DesignTokens/DesignToken.razor.cs
index 0791948ef3..15cdd41d57 100644
--- a/src/Core/DesignTokens/DesignToken.razor.cs
+++ b/src/Core/DesignTokens/DesignToken.razor.cs
@@ -1,3 +1,7 @@
+// ------------------------------------------------------------------------
+// MIT License - Copyright (c) Microsoft Corporation. All rights reserved.
+// ------------------------------------------------------------------------
+
using System.Diagnostics.CodeAnalysis;
using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;
@@ -84,7 +88,19 @@ private async Task InitJSReferenceAsync()
public async ValueTask> WithDefault(string value)
{
await InitJSReferenceAsync();
- await _jsModule.InvokeVoidAsync(Name + ".withDefault", value);
+
+ if (Name == "accentBaseColor")
+ {
+ await _jsModule.InvokeVoidAsync("updateAccentBaseColor", value);
+ }
+ else if (Name == "neutralBaseColor")
+ {
+ await _jsModule.InvokeVoidAsync("updateNeutralBaseColor", value);
+ }
+ else
+ {
+ await _jsModule.InvokeVoidAsync(Name + ".withDefault", value);
+ }
return this;
}
@@ -147,7 +163,6 @@ public async ValueTask GetValueFor(ElementReference element)
/// Convert a hex color string to a value the DesignToken can work with
///
/// the value
- [SuppressMessage("Style", "VSTHRD200:Use `Async` suffix for async methods", Justification = "#vNext: To update in the next version")]
public async ValueTask