Skip to content

Commit bf0cbfa

Browse files
committed
Initial support for style module media query variations
1 parent 66d7aba commit bf0cbfa

File tree

10 files changed

+153
-25
lines changed

10 files changed

+153
-25
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/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 type { ValuesOf } from '@microsoft/fast-foundation';
1414

1515
// @public (undocumented)
@@ -521,6 +521,15 @@ export const focusStrokeWidth: CSSDesignToken<number>;
521521
// @public (undocumented)
522522
export const fontWeight: CSSDesignToken<number>;
523523

524+
// @public (undocumented)
525+
export const forcedColorsButtonStyles: Styles;
526+
527+
// @public (undocumented)
528+
export const forcedColorsHighlightStyles: Styles;
529+
530+
// @public (undocumented)
531+
export const forcedColorsTextStyles: Styles;
532+
524533
// @public @deprecated (undocumented)
525534
export const foregroundOnAccentActive: CSSDesignToken<Swatch>;
526535

@@ -1261,7 +1270,7 @@ export interface RelativeLuminance {
12611270
}
12621271

12631272
// @public
1264-
export function renderElementStyles(styles: Styles, params: StyleModuleEvaluateParameters): ElementStyles[];
1273+
export function renderElementStyles(styles: Styles, params: StyleModuleEvaluateParameters): ElementStyles;
12651274

12661275
// @public
12671276
export function resolvePaletteDirection(direction: PaletteDirection): PaletteDirectionValue;
@@ -1380,7 +1389,7 @@ export interface StyleModuleTarget {
13801389
}
13811390

13821391
// @public
1383-
export type StyleProperties = Partial<Record<StyleProperty, CSSDesignToken<any> | InteractiveTokenSet<any> | CSSDirective | string>>;
1392+
export type StyleProperties = Partial<Record<StyleProperty, CSSDesignToken<any> | InteractiveTokenSet<any> | CSSDirective | string | InteractiveSet<string>>>;
13841393

13851394
// @public
13861395
export const StyleProperty: {
@@ -1417,8 +1426,10 @@ export class Styles {
14171426
get composed(): Styles[] | undefined;
14181427
get effectiveProperties(): StyleProperties;
14191428
static fromProperties(properties: StyleProperties): Styles;
1429+
getMediaQueryStyles(): ReadonlyMap<string, Styles> | undefined;
14201430
get properties(): StyleProperties | undefined;
14211431
set properties(properties: StyleProperties | undefined);
1432+
withMediaQuery(query: string, styles: Styles): this;
14221433
}
14231434

14241435
// @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
@@ -3,5 +3,6 @@ export * from "./color.js";
33
export * from "./elevation.js";
44
export * from "./layer.js";
55
export * from "./modules.js";
6+
export * from "./modules.forced-colors.js";
67
export * from "./palette.js";
78
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
@@ -3,6 +3,7 @@ import { InteractiveColorRecipe, InteractiveColorRecipeBySet, InteractiveSwatchS
33
import { Swatch } from "../color/swatch.js";
44
import type { InteractiveSet, InteractiveTokenSet } from "../types.js";
55
import { StyleProperties, Styles } from "../modules/styles.js";
6+
import { MediaQuery } from "../modules/css.js";
67
import {
78
accentFillDiscernibleInteractiveSet,
89
accentFillReadableInteractiveSet,
@@ -60,6 +61,7 @@ import {
6061
typeRampPlus6FontVariations,
6162
typeRampPlus6LineHeight,
6263
} from "./type.js";
64+
import { forcedColorsButtonStyles, forcedColorsHighlightStyles, forcedColorsTextStyles } from "./modules.forced-colors.js";
6365

6466
/**
6567
* Creates a set of foreground tokens applied over the background tokens.
@@ -517,6 +519,9 @@ export const inputStyles: Styles = Styles.compose(
517519
export const selectableSelectedStyles: Styles = Styles.compose(
518520
typeRampBaseStyles,
519521
accentFillReadableControlStyles
522+
).withMediaQuery(
523+
MediaQuery.ForcedColors,
524+
forcedColorsHighlightStyles,
520525
);
521526

522527
/**
@@ -525,6 +530,9 @@ export const selectableSelectedStyles: Styles = Styles.compose(
525530
export const selectableUnselectedStyles: Styles = Styles.compose(
526531
typeRampBaseStyles,
527532
neutralOutlineDiscernibleControlStyles
533+
).withMediaQuery(
534+
MediaQuery.ForcedColors,
535+
forcedColorsButtonStyles,
528536
);
529537

530538
/**
@@ -549,4 +557,7 @@ export const plainTextStyles: Styles = Styles.compose(
549557
export const labelTextStyles: Styles = Styles.compose(
550558
typeRampBaseStyles,
551559
neutralForegroundStrongElementStyles
560+
).withMediaQuery(
561+
MediaQuery.ForcedColors,
562+
forcedColorsTextStyles,
552563
);

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: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
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";
5-
import type { InteractiveTokenSet } from "../types.js";
5+
import type { InteractiveSet } from "../types.js";
66
import { makeSelector } from "./selector.js";
77
import type { FocusSelector, StyleModuleEvaluateParameters } from "./types.js";
88
import { stylePropertyToCssProperty } from "./css.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: InteractiveTokenSet<T>,
23+
values: InteractiveSet<string | CSSDesignToken<any>>,
2424
focusSelector: FocusSelector = "focus-visible",
2525
): StyleModuleEvaluate {
2626
return (params: StyleModuleEvaluateParameters): ElementStyles => css`
@@ -51,16 +51,17 @@ function createElementStyleModules(styles: Styles): StyleModuleEvaluate[] {
5151
} else if (value && typeof (value as any).createCSS === "function") {
5252
return propertySingle(property, value as CSSDirective);
5353
} else {
54-
return propertyInteractive(property, value as InteractiveTokenSet<any>);
54+
return propertyInteractive(property, value as InteractiveSet<any>);
5555
}
5656
});
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: 32 additions & 6 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 { InteractiveTokenSet } from "../types.js";
3+
import { InteractiveSet, InteractiveTokenSet } 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> | InteractiveTokenSet<any> | CSSDirective | string>>;
11+
export type StyleProperties = Partial<Record<
12+
StyleProperty,
13+
CSSDesignToken<any> | InteractiveTokenSet<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)) {
@@ -53,20 +58,41 @@ export class Styles {
5358
}
5459

5560
/**
56-
* Gets the local properties or composition overrides. See {@link }.
61+
* The local properties or composition overrides.
5762
*/
5863
public get properties(): StyleProperties | undefined {
5964
return this._properties;
6065
}
6166

62-
/**
63-
* Sets the local properties or composition overrides.
64-
*/
6567
public set properties(properties: StyleProperties | undefined) {
6668
this._properties = properties;
6769
this.createEffectiveProperties();
6870
}
6971

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+
7096
/**
7197
* Gets the full effective set of properties, from composed styles and local properties as applicable.
7298
*/

packages/adaptive-web-components/src/design-system.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -131,9 +131,7 @@ export class DesignSystem {
131131
for (const [target, styles] of options.styleModules) {
132132
const params: StyleModuleEvaluateParameters = Object.assign({}, interactivity, target);
133133
const renderedStyles = renderElementStyles(styles, params);
134-
for (const s of renderedStyles) {
135-
componentStyles.push(s);
136-
}
134+
componentStyles.push(renderedStyles);
137135
}
138136
}
139137

0 commit comments

Comments
 (0)