Skip to content

Commit 999918f

Browse files
committed
Export an API for perfoming media queries on breakpoints
1 parent 38210cc commit 999918f

File tree

11 files changed

+126
-24
lines changed

11 files changed

+126
-24
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,5 +44,5 @@ jspm_packages
4444
/.yarn_home
4545
/dsfr
4646
/dist_test
47-
/src/lib/useTheme/generated
47+
/src/lib/generatedFromCss/
4848

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@
7373
},
7474
"dependencies": {
7575
"@gouvfr/dsfr": "1.7.2",
76-
"tsafe": "^1.0.1"
76+
"tsafe": "^1.1.1"
7777
},
7878
"devDependencies": {
7979
"@emotion/react": "^11.10.4",

src/bin/css_to_ts/breakpoints.ts

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import css from "css";
22
import { assert } from "tsafe/assert";
3+
import { objectKeys } from "tsafe/objectKeys";
4+
import { exclude } from "tsafe/exclude";
35

46
export type BreakpointsValues = {
57
unit: string /* em, px ... */;
@@ -41,7 +43,7 @@ export function parseBreakpointsValues(rawCssCode: string): BreakpointsValues {
4143
assert(values.length === 4);
4244
assert(prevUnit !== undefined);
4345

44-
const [sm, md, lg, xl] = values;
46+
const [sm, md, lg, xl] = values.sort();
4547

4648
return {
4749
"unit": prevUnit,
@@ -53,15 +55,42 @@ export function parseBreakpointsValues(rawCssCode: string): BreakpointsValues {
5355
}
5456

5557
export function generateBreakpointsValuesTsCode(breakpointsValues: BreakpointsValues): string {
58+
const sortedKeys = objectKeys(breakpointsValues)
59+
.filter(exclude("unit"))
60+
.sort((a, b) => breakpointsValues[a] - breakpointsValues[b]);
61+
5662
return [
57-
`export const breakpointsValues = {`,
58-
JSON.stringify(breakpointsValues, null, 2)
63+
`import { assert } from "tsafe/assert";`,
64+
`import type { Extends } from "tsafe";`,
65+
``,
66+
`export const breakpointValuesUnit = "em";`,
67+
``,
68+
`export const breakpointKeys = ["xs", ${sortedKeys
69+
.map(key => `"${key}"`)
70+
.join(", ")}] as const;`,
71+
``,
72+
`export type BreakpointKeys = typeof breakpointKeys[number];`,
73+
``,
74+
`export const breakpointValues = {`,
75+
JSON.stringify(
76+
Object.fromEntries(
77+
(["xs", ...sortedKeys] as const).map(key => [
78+
key,
79+
key === "xs" ? 0 : breakpointsValues[key]
80+
])
81+
),
82+
null,
83+
2
84+
)
5985
.replace(/^{\n/, "")
6086
.replace(/\n}$/, "")
6187
.split("\n")
6288
.map(line => line.replace(/^[ ]{2}/, ""))
6389
.map(line => ` ${line}`)
6490
.join("\n"),
65-
`} as const;`
91+
`} as const;`,
92+
``,
93+
`assert<Extends<typeof breakpointValues, Record<BreakpointKeys, number>>>();`,
94+
``
6695
].join("\n");
6796
}

src/bin/css_to_ts/css_to_ts.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { generateGetColorOptionsTsCode, parseColorOptions } from "./colorOptions";
22
import { generateGetColorDecisionsTsCode, parseColorDecision } from "./colorDecisions";
3+
import { parseBreakpointsValues, generateBreakpointsValuesTsCode } from "./breakpoints";
34
import { getProjectRoot } from "../tools/getProjectRoot";
45
import * as fs from "fs";
56
import { join as pathJoin, basename as pathBasename, relative as pathRelative } from "path";
@@ -8,7 +9,7 @@ const projectRoot = getProjectRoot();
89

910
const rawCssCode = fs.readFileSync(pathJoin(projectRoot, "dsfr", "dsfr.css")).toString("utf8");
1011

11-
const generatedDirPath = pathJoin(projectRoot, "src", "lib", "useTheme", "generated");
12+
const generatedDirPath = pathJoin(projectRoot, "src", "lib", "generatedFromCss");
1213

1314
fs.mkdirSync(generatedDirPath, { "recursive": true });
1415

@@ -63,3 +64,17 @@ fs.writeFileSync(
6364
"utf8"
6465
)
6566
);
67+
68+
const targetBreakpointsValuesFilePath = pathJoin(generatedDirPath, "breakpoints.ts");
69+
70+
fs.writeFileSync(
71+
targetBreakpointsValuesFilePath,
72+
Buffer.from(
73+
[
74+
warningMessage,
75+
``,
76+
generateBreakpointsValuesTsCode(parseBreakpointsValues(rawCssCode))
77+
].join("\n"),
78+
"utf8"
79+
)
80+
);

src/lib/breakpoints.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import type { BreakpointKeys } from "./generatedFromCss/breakpoints";
2+
import {
3+
breakpointValues as values,
4+
breakpointValuesUnit as unit,
5+
breakpointKeys as keys
6+
} from "./generatedFromCss/breakpoints";
7+
8+
export type { BreakpointKeys };
9+
10+
const epsilon = 0.003125;
11+
12+
export const breakpoints = {
13+
"up": (key: BreakpointKeys) => `@media (min-width:${values[key]}${unit})`,
14+
"down": (key: BreakpointKeys) => `@media (max-width:${values[key] - epsilon}${unit})`,
15+
"between": (start: BreakpointKeys, end: BreakpointKeys) =>
16+
[
17+
`@media (min-width:${values[start]}${unit})`,
18+
`(max-width:${values[end] - epsilon}${unit})`
19+
].join(" and "),
20+
"only": (key: BreakpointKeys) =>
21+
keys.indexOf(key) + 1 < keys.length
22+
? breakpoints.between(key, keys[keys.indexOf(key) + 1])
23+
: breakpoints.up(key),
24+
"not": (key: BreakpointKeys) => {
25+
// handle first and last key separately, for better readability
26+
const keyIndex = keys.indexOf(key);
27+
if (keyIndex === 0) {
28+
return breakpoints.up(keys[1]);
29+
}
30+
if (keyIndex === keys.length - 1) {
31+
return breakpoints.down(keys[keyIndex]);
32+
}
33+
34+
return breakpoints
35+
.between(key, keys[keys.indexOf(key) + 1])
36+
.replace("@media", "@media not all and");
37+
}
38+
};

src/lib/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
export { $colorScheme, useIsDark } from "./useColorScheme";
2+
export * from "./breakpoints";
23
export { useTheme } from "./useTheme";
34
export type { Theme } from "./useTheme";
45
export type { ColorScheme } from "./useColorScheme";

src/lib/useTheme/useTheme.ts renamed to src/lib/useTheme.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import { useMemo } from "react";
2-
import { getColorOptions } from "./generated/getColorOptions";
3-
import type { ColorOptions } from "./generated/getColorOptions";
4-
import { getColorDecisions } from "./generated/getColorDecisions";
5-
import type { ColorDecisions } from "./generated/getColorDecisions";
6-
import { useIsDark } from "../useColorScheme";
2+
import { getColorOptions } from "./generatedFromCss/getColorOptions";
3+
import type { ColorOptions } from "./generatedFromCss/getColorOptions";
4+
import { getColorDecisions } from "./generatedFromCss/getColorDecisions";
5+
import type { ColorDecisions } from "./generatedFromCss/getColorDecisions";
6+
import { useIsDark } from "./useColorScheme";
77

88
export type Theme = {
99
isDark: boolean;

src/lib/useTheme/index.ts

Lines changed: 0 additions & 1 deletion
This file was deleted.

src/test/bin/breakpoints/generateBreakpointsValuesTsCode.ts

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,31 @@ const input: BreakpointsValues = {
1313
};
1414

1515
const expected = `
16-
export const breakpointsValues = {
17-
"unit": "em",
16+
import { assert } from "tsafe/assert";
17+
import type { Extends } from "tsafe";
18+
19+
export const breakpointValuesUnit = "em";
20+
21+
export const breakpointKeys = ["xs", "sm", "md", "lg", "xl"] as const;
22+
23+
export type BreakpointKeys = typeof breakpointKeys[number];
24+
25+
export const breakpointValues = {
26+
"xs": 0,
1827
"sm": 36,
1928
"md": 48,
2029
"lg": 62,
2130
"xl": 78
22-
} as const;`.replace(/^\n/, "");
31+
} as const;
32+
33+
assert<Extends<typeof breakpointValues, Record<BreakpointKeys, number>>>();
34+
`.replace(/^\n/, "");
2335

2436
const got = generateBreakpointsValuesTsCode(input);
2537

38+
console.log(JSON.stringify(got));
39+
console.log(JSON.stringify(expected));
40+
2641
assert(got === expected);
2742

2843
console.log("PASS");

src/test/bin/breakpoints/parseBreakpointsValues.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,20 +25,20 @@ const input = `
2525
}
2626
}
2727
28-
@media (min-width: 62em) {
29-
/*! media lg */
28+
@media (min-width: 78em) {
29+
/*! media xl */
3030
31-
/*! media lg */
32-
.fr-hidden-lg {
31+
/*! media xl */
32+
.fr-hidden-xl {
3333
display: none !important;
3434
}
3535
}
3636
37-
@media (min-width: 78em) {
38-
/*! media xl */
37+
@media (min-width: 62em) {
38+
/*! media lg */
3939
40-
/*! media xl */
41-
.fr-hidden-xl {
40+
/*! media lg */
41+
.fr-hidden-lg {
4242
display: none !important;
4343
}
4444
}

0 commit comments

Comments
 (0)