Skip to content

Commit df8a0b3

Browse files
committed
Initial support for style module media query variations
1 parent ea5e7e4 commit df8a0b3

File tree

11 files changed

+151
-20
lines changed

11 files changed

+151
-20
lines changed

package-lock.json

Lines changed: 3 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/adaptive-ui-explorer/src/components/adaptive-component.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,6 @@ export class AdaptiveComponent extends FASTElement {
5555
// prev.forEach((s) => this.$fastController.removeStyles(s));
5656
// }
5757
const elementStyles = renderElementStyles(next, params);
58-
elementStyles.forEach((s) => this.$fastController.addStyles(s));
58+
this.$fastController.addStyles(elementStyles);
5959
}
6060
}

packages/adaptive-ui/docs/api-report.md

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { CSSDesignToken } from '@microsoft/fast-foundation';
99
import { CSSDirective } from '@microsoft/fast-element';
1010
import { DesignToken } from '@microsoft/fast-foundation';
1111
import { DesignTokenResolver } from '@microsoft/fast-foundation';
12-
import type { ElementStyles } from '@microsoft/fast-element';
12+
import { ElementStyles } from '@microsoft/fast-element';
1313
import { TypedCSSDesignToken as TypedCSSDesignToken_2 } from '../adaptive-design-tokens.js';
1414
import { ValuesOf } from '@microsoft/fast-foundation';
1515

@@ -593,6 +593,15 @@ export const fontFamily: TypedCSSDesignToken_2<string>;
593593
// @public (undocumented)
594594
export const fontWeight: TypedCSSDesignToken_2<number>;
595595

596+
// @public (undocumented)
597+
export const forcedColorsButtonStyles: Styles;
598+
599+
// @public (undocumented)
600+
export const forcedColorsHighlightStyles: Styles;
601+
602+
// @public (undocumented)
603+
export const forcedColorsTextStyles: Styles;
604+
596605
// @public @deprecated (undocumented)
597606
export const foregroundOnAccentActive: TypedCSSDesignToken<Swatch>;
598607

@@ -1339,7 +1348,7 @@ export interface RelativeLuminance {
13391348
}
13401349

13411350
// @public
1342-
export function renderElementStyles(styles: Styles, params: StyleModuleEvaluateParameters): ElementStyles[];
1351+
export function renderElementStyles(styles: Styles, params: StyleModuleEvaluateParameters): ElementStyles;
13431352

13441353
// @public
13451354
export function resolvePaletteDirection(direction: PaletteDirection): PaletteDirectionValue;
@@ -1461,7 +1470,7 @@ export interface StyleModuleTarget {
14611470
}
14621471

14631472
// @public
1464-
export type StyleProperties = Partial<Record<StyleProperty, CSSDesignToken<any> | InteractiveTokenGroup<any> | CSSDirective | string>>;
1473+
export type StyleProperties = Partial<Record<StyleProperty, CSSDesignToken<any> | InteractiveTokenGroup<any> | CSSDirective | string | InteractiveSet<string>>>;
14651474

14661475
// @public
14671476
export const StyleProperty: {
@@ -1498,8 +1507,10 @@ export class Styles {
14981507
get composed(): Styles[] | undefined;
14991508
get effectiveProperties(): StyleProperties;
15001509
static fromProperties(properties: StyleProperties): Styles;
1510+
getMediaQueryStyles(): ReadonlyMap<string, Styles> | undefined;
15011511
get properties(): StyleProperties | undefined;
15021512
set properties(properties: StyleProperties | undefined);
1513+
withMediaQuery(query: string, styles: Styles): this;
15031514
}
15041515

15051516
// @public

packages/adaptive-ui/package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@
3535
},
3636
"dependencies": {
3737
"@microsoft/fast-colors": "^5.3.1",
38-
"@microsoft/fast-foundation": "3.0.0-alpha.27"
38+
"@microsoft/fast-foundation": "3.0.0-alpha.27",
39+
"@microsoft/fast-web-utilities": "^6.0.0"
3940
},
4041
"devDependencies": {
4142
"@microsoft/api-extractor": "^7.34.4",
@@ -52,4 +53,4 @@
5253
"default": "./dist/esm/index.js"
5354
}
5455
}
55-
}
56+
}

packages/adaptive-ui/src/design-tokens/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,6 @@ export * from "./create.js";
44
export * from "./elevation.js";
55
export * from "./layer.js";
66
export * from "./modules.js";
7+
export * from "./modules.forced-colors.js";
78
export * from "./palette.js";
89
export * from "./type.js";
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import { SystemColors } from "@microsoft/fast-web-utilities";
2+
import { InteractiveSet } from "../types.js";
3+
import { Styles } from "../modules/styles.js";
4+
5+
/**
6+
* Convenience function for styles that share rest/focus and hover/active states.
7+
*
8+
* @param restAndFocus - The value to use for rest and focus states.
9+
* @param hoverAndActive - The value to use for hover and active states.
10+
* @returns A full interactive color set.
11+
*/
12+
function set(
13+
restAndFocus: string,
14+
hoverAndActive: string,
15+
): InteractiveSet<string> {
16+
return {
17+
rest: restAndFocus,
18+
hover: hoverAndActive,
19+
active: hoverAndActive,
20+
focus: restAndFocus,
21+
};
22+
}
23+
24+
/**
25+
* @public
26+
*/
27+
export const forcedColorsButtonStyles: Styles = Styles.fromProperties({
28+
backgroundFill: {
29+
...set(SystemColors.ButtonFace, SystemColors.HighlightText),
30+
},
31+
foregroundFill: {
32+
...set(SystemColors.ButtonText, SystemColors.Highlight),
33+
},
34+
borderFill: {
35+
...set(SystemColors.ButtonText, SystemColors.Highlight),
36+
},
37+
});
38+
39+
/**
40+
* @public
41+
*/
42+
export const forcedColorsHighlightStyles: Styles = Styles.fromProperties({
43+
backgroundFill: {
44+
...set(SystemColors.Highlight, SystemColors.ButtonFace),
45+
},
46+
foregroundFill: {
47+
...set(SystemColors.HighlightText, SystemColors.ButtonText),
48+
},
49+
borderFill: {
50+
...set(SystemColors.Highlight, SystemColors.ButtonText),
51+
},
52+
});
53+
54+
/**
55+
* @public
56+
*/
57+
export const forcedColorsTextStyles: Styles = Styles.fromProperties({
58+
foregroundFill: SystemColors.CanvasText,
59+
});

packages/adaptive-ui/src/design-tokens/modules.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { Swatch } from "../color/swatch.js";
44
import type { InteractiveSet, InteractiveTokenGroup } from "../types.js";
55
import { StyleProperties, Styles } from "../modules/styles.js";
66
import { TypedCSSDesignToken } from "../adaptive-design-tokens.js";
7+
import { MediaQuery } from "../modules/css.js";
78
import { cornerRadiusControl, cornerRadiusLayer, strokeThickness } from "./appearance.js";
89
import {
910
accentFillDiscernible,
@@ -63,6 +64,7 @@ import {
6364
typeRampPlus6FontVariations,
6465
typeRampPlus6LineHeight,
6566
} from "./type.js";
67+
import { forcedColorsButtonStyles, forcedColorsHighlightStyles, forcedColorsTextStyles } from "./modules.forced-colors.js";
6668

6769
/**
6870
* Creates a set of foreground tokens applied over the background tokens.
@@ -553,6 +555,9 @@ export const selectableSelectedStyles: Styles = Styles.compose(
553555
controlShapeStyles,
554556
typeRampBaseStyles,
555557
accentFillReadableControlStyles
558+
).withMediaQuery(
559+
MediaQuery.ForcedColors,
560+
forcedColorsHighlightStyles,
556561
);
557562

558563
/**
@@ -562,6 +567,9 @@ export const selectableUnselectedStyles: Styles = Styles.compose(
562567
controlShapeStyles,
563568
typeRampBaseStyles,
564569
neutralOutlineDiscernibleControlStyles
570+
).withMediaQuery(
571+
MediaQuery.ForcedColors,
572+
forcedColorsButtonStyles,
565573
);
566574

567575
/**
@@ -587,4 +595,7 @@ export const plainTextStyles: Styles = Styles.compose(
587595
export const labelTextStyles: Styles = Styles.compose(
588596
typeRampBaseStyles,
589597
neutralForegroundStrongElementStyles
598+
).withMediaQuery(
599+
MediaQuery.ForcedColors,
600+
forcedColorsTextStyles,
590601
);

packages/adaptive-ui/src/modules/css.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
import { StyleProperty } from "./types.js";
22

3+
/**
4+
* Convenience media queries for {@link Styles} variations.
5+
*/
6+
export const MediaQuery = {
7+
ForcedColors: "(forced-colors)",
8+
ColorsDark: "(prefers-color-scheme: dark)",
9+
ColorsLight: "(prefers-color-scheme: light)",
10+
} as const;
11+
312
/**
413
* Converts a {@link StyleProperty} to a css property name.
514
*

packages/adaptive-ui/src/modules/element-styles-renderer.ts

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { css } from "@microsoft/fast-element";
2-
import type { CSSDirective, ElementStyles } from "@microsoft/fast-element";
3-
import { CSSDesignToken } from "@microsoft/fast-foundation";
2+
import { CSSDirective, ElementStyles } from "@microsoft/fast-element";
3+
import { CSSDesignToken, MatchMediaStyleSheetBehavior } from "@microsoft/fast-foundation";
44
import type { StyleProperty } from "../modules/types.js";
55
import type { InteractiveTokenGroup } from "../types.js";
66
import { makeSelector } from "./selector.js";
@@ -18,9 +18,9 @@ function propertySingle<T = string>(
1818
css`${makeSelector(params)} { ${property}: ${value}; }`;
1919
}
2020

21-
function propertyInteractive<T = string>(
21+
function propertyInteractive(
2222
property: string,
23-
values: InteractiveTokenGroup<T>,
23+
values: InteractiveTokenGroup<string | CSSDesignToken<any>>,
2424
focusSelector: FocusSelector = "focus-visible",
2525
): StyleModuleEvaluate {
2626
return (params: StyleModuleEvaluateParameters): ElementStyles => css`
@@ -57,10 +57,11 @@ function createElementStyleModules(styles: Styles): StyleModuleEvaluate[] {
5757
return modules;
5858
}
5959

60-
function createElementStyles(modules: StyleModuleEvaluate[], params: StyleModuleEvaluateParameters): ElementStyles[] {
61-
return modules.map((module) =>
60+
function createElementStyles(modules: StyleModuleEvaluate[], params: StyleModuleEvaluateParameters): ElementStyles {
61+
const styles = modules.map((module) =>
6262
module(params)
6363
);
64+
return new ElementStyles(styles);
6465
}
6566

6667
/**
@@ -72,6 +73,15 @@ function createElementStyles(modules: StyleModuleEvaluate[], params: StyleModule
7273
*
7374
* @public
7475
*/
75-
export function renderElementStyles(styles: Styles, params: StyleModuleEvaluateParameters): ElementStyles[] {
76-
return createElementStyles(createElementStyleModules(styles), params);
76+
export function renderElementStyles(styles: Styles, params: StyleModuleEvaluateParameters): ElementStyles {
77+
const elementStyles = createElementStyles(createElementStyleModules(styles), params);
78+
79+
styles.getMediaQueryStyles()?.forEach((queryStyles, query) => {
80+
const queryElementStyles = createElementStyles(createElementStyleModules(queryStyles), params);
81+
elementStyles.withBehaviors(
82+
MatchMediaStyleSheetBehavior.with(
83+
window.matchMedia(query))(queryElementStyles))
84+
});
85+
86+
return elementStyles;
7787
}

packages/adaptive-ui/src/modules/styles.ts

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
import type { CSSDirective } from "@microsoft/fast-element";
22
import type { CSSDesignToken } from "@microsoft/fast-foundation";
3-
import { InteractiveTokenGroup } from "../types.js";
3+
import { InteractiveSet, InteractiveTokenGroup } from "../types.js";
44
import { StyleProperty } from "./types.js";
55

66
/**
77
* A collection of style definitions, where the key is the {@link (StyleProperty:type)} and the value is the token or final value.
88
*
99
* @public
1010
*/
11-
export type StyleProperties = Partial<Record<StyleProperty, CSSDesignToken<any> | InteractiveTokenGroup<any> | CSSDirective | string>>;
11+
export type StyleProperties = Partial<Record<
12+
StyleProperty,
13+
CSSDesignToken<any> | InteractiveTokenGroup<any> | CSSDirective | string | InteractiveSet<string>
14+
>>;
1215

1316
/**
1417
* A modular definition of style properties, either an alias to another style module or a collection of style properties.
@@ -22,6 +25,8 @@ export class Styles {
2225
private _properties?: StyleProperties;
2326
// Effective properties from composed styles and additional properties
2427
private _composedProperties?: StyleProperties;
28+
// Style overrides for a media query
29+
private _mediaQueryVariations: Map<string, Styles>;
2530

2631
private constructor(propertiesOrStyles: StyleProperties | Styles[]) {
2732
if (Array.isArray(propertiesOrStyles)) {
@@ -64,6 +69,30 @@ export class Styles {
6469
this.createEffectiveProperties();
6570
}
6671

72+
/**
73+
* Adds a style variation for a media query like `forced-colors`.
74+
*
75+
* @param query - The media query, see {@link MediaQuery}.
76+
* @param styles - The styles to apply for the provided media query
77+
* @returns The `Styles` definition with media query variation.
78+
*/
79+
public withMediaQuery(query: string, styles: Styles): this {
80+
if (!this._mediaQueryVariations) {
81+
this._mediaQueryVariations = new Map();
82+
}
83+
this._mediaQueryVariations.set(query, styles);
84+
return this;
85+
}
86+
87+
/**
88+
* Gets the media query variations for this style.
89+
*
90+
* @returns The defined media query variations.
91+
*/
92+
public getMediaQueryStyles(): ReadonlyMap<string, Styles> | undefined {
93+
return this._mediaQueryVariations;
94+
}
95+
6796
/**
6897
* Gets the full effective set of properties, from composed styles and local properties as applicable.
6998
*/

0 commit comments

Comments
 (0)