Skip to content

Commit f47071e

Browse files
committed
Cover more cases
1 parent 2f269f8 commit f47071e

File tree

2 files changed

+94
-26
lines changed

2 files changed

+94
-26
lines changed

apps/builder/app/builder/features/style-panel/shared/model.tsx

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { propertiesData } from "@webstudio-is/css-data";
66
import {
77
compareMedia,
88
hyphenateProperty,
9+
matchMedia,
910
toVarFallback,
1011
type CssProperty,
1112
type StyleValue,
@@ -41,6 +42,7 @@ import {
4142
type InstancePath,
4243
} from "~/shared/awareness";
4344
import type { InstanceSelector } from "~/shared/tree-utils";
45+
import { $canvasWidth } from "~/builder/shared/nano-states";
4446

4547
const $presetStyles = computed($registeredComponentMetas, (metas) => {
4648
const presetStyles = new Map<string, StyleValue>();
@@ -111,16 +113,28 @@ const $instanceComponents = computed(
111113
);
112114

113115
export const $matchingBreakpoints = computed(
114-
[$breakpoints, $selectedBreakpoint],
115-
(breakpoints, selectedBreakpoint) => {
116-
const sortedBreakpoints = Array.from(breakpoints.values()).sort(
117-
compareMedia
118-
);
116+
[$breakpoints, $selectedBreakpoint, $canvasWidth],
117+
(breakpoints, selectedBreakpoint, canvasWidth) => {
118+
// zero is not correct, need to use current width for base breakpoint
119+
// add always add base
120+
const selectedWidth =
121+
selectedBreakpoint?.minWidth ??
122+
selectedBreakpoint?.maxWidth ??
123+
canvasWidth ??
124+
0;
125+
const sortedBreakpoints = Array.from(breakpoints.values())
126+
.sort(compareMedia)
127+
.sort((left, right) => {
128+
// put selected breakpoint always in the end
129+
// to make style from matching breakpoints remote
130+
const leftScore = left.id === selectedBreakpoint?.id ? 1 : 0;
131+
const rightScore = right.id === selectedBreakpoint?.id ? 1 : 0;
132+
return leftScore - rightScore;
133+
});
119134
const matchingBreakpoints: Breakpoint["id"][] = [];
120135
for (const breakpoint of sortedBreakpoints) {
121-
matchingBreakpoints.push(breakpoint.id);
122-
if (breakpoint.id === selectedBreakpoint?.id) {
123-
break;
136+
if (matchMedia(breakpoint, selectedWidth)) {
137+
matchingBreakpoints.push(breakpoint.id);
124138
}
125139
}
126140
return matchingBreakpoints;

apps/builder/app/shared/style-object-model.test.tsx

Lines changed: 72 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1638,12 +1638,13 @@ describe("compute matching breakpoints", () => {
16381638
])
16391639
);
16401640
$selectedBreakpointId.set("desktop");
1641-
const computedStyleDecl = getComputedStyleDecl({
1642-
model: _$model.get(),
1643-
instanceSelector: ["body"],
1644-
property: "color",
1645-
});
1646-
expect(computedStyleDecl.computedValue).toEqual({
1641+
expect(
1642+
getComputedStyleDecl({
1643+
model: _$model.get(),
1644+
instanceSelector: ["body"],
1645+
property: "color",
1646+
}).computedValue
1647+
).toEqual({
16471648
type: "keyword",
16481649
value: "red",
16491650
});
@@ -1670,18 +1671,19 @@ describe("compute matching breakpoints", () => {
16701671
])
16711672
);
16721673
$selectedBreakpointId.set("desktop");
1673-
const computedStyleDecl = getComputedStyleDecl({
1674-
model: _$model.get(),
1675-
instanceSelector: ["body"],
1676-
property: "color",
1677-
});
1678-
expect(computedStyleDecl.computedValue).toEqual({
1674+
expect(
1675+
getComputedStyleDecl({
1676+
model: _$model.get(),
1677+
instanceSelector: ["body"],
1678+
property: "color",
1679+
}).computedValue
1680+
).toEqual({
16791681
type: "keyword",
16801682
value: "black",
16811683
});
16821684
});
16831685

1684-
test("mixed min-width and max-width breakpoints", () => {
1686+
test("mixed min-width and max-width with selected min-width", () => {
16851687
const model = createModel({
16861688
css: `
16871689
@media mobile {
@@ -1702,14 +1704,66 @@ describe("compute matching breakpoints", () => {
17021704
])
17031705
);
17041706
$selectedBreakpointId.set("desktop");
1705-
const computedStyleDecl = getComputedStyleDecl({
1706-
model: _$model.get(),
1707-
instanceSelector: ["body"],
1708-
property: "color",
1707+
expect(
1708+
getComputedStyleDecl({
1709+
model: _$model.get(),
1710+
instanceSelector: ["body"],
1711+
property: "color",
1712+
}).computedValue
1713+
).toEqual({
1714+
type: "keyword",
1715+
value: "black",
17091716
});
1710-
expect(computedStyleDecl.computedValue).toEqual({
1717+
$selectedBreakpointId.set("base");
1718+
expect(
1719+
getComputedStyleDecl({
1720+
model: _$model.get(),
1721+
instanceSelector: ["body"],
1722+
property: "color",
1723+
}).source
1724+
).toEqual(
1725+
expect.objectContaining({ name: "remote", breakpointId: "mobile" })
1726+
);
1727+
});
1728+
1729+
test("mixed min-width and max-width with selected max-width", () => {
1730+
const model = createModel({
1731+
css: `
1732+
@media desktop {
1733+
bodyLocal {
1734+
color: red;
1735+
}
1736+
}
1737+
`,
1738+
jsx: <$.Body ws:id="body" ws:tag="body" class="bodyLocal"></$.Body>,
1739+
});
1740+
$styles.set(model.styles);
1741+
$styleSourceSelections.set(model.styleSourceSelections);
1742+
$breakpoints.set(
1743+
new Map([
1744+
["desktop", { id: "desktop", label: "", minWidth: 991 }],
1745+
["base", { id: "base", label: "" }],
1746+
["mobile", { id: "mobile", label: "", maxWidth: 479 }],
1747+
])
1748+
);
1749+
$selectedBreakpointId.set("mobile");
1750+
expect(
1751+
getComputedStyleDecl({
1752+
model: _$model.get(),
1753+
instanceSelector: ["body"],
1754+
property: "color",
1755+
}).computedValue
1756+
).toEqual({
17111757
type: "keyword",
17121758
value: "black",
17131759
});
1760+
$selectedBreakpointId.set("base");
1761+
expect(
1762+
getComputedStyleDecl({
1763+
model: _$model.get(),
1764+
instanceSelector: ["body"],
1765+
property: "color",
1766+
}).source
1767+
).toEqual(expect.objectContaining({ name: "default" }));
17141768
});
17151769
});

0 commit comments

Comments
 (0)