Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compute currentColor #1815

Merged
merged 4 commits into from
Jun 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -190,12 +190,26 @@ export const ColorPicker = ({
const rgbValue = styleValueToRgbaColor(currentValue);

// Change prefix color in sync with color picker, don't change during input changed
const prefixColor = styleValueResolve(
let prefixColor = styleValueResolve(
currentValue.type === "keyword" || currentValue.type === "rgb"
? currentValue
: value,
currentColor
);
// consider inherit on color same as currentColor
if (
property === "color" &&
prefixColor.type === "keyword" &&
prefixColor.value === "inherit"
) {
prefixColor = {
type: "rgb",
r: currentColor.r,
g: currentColor.g,
b: currentColor.b,
alpha: currentColor.alpha,
};
}

const prefixColorRgba = styleValueToRgbaColor(prefixColor);

Expand Down
228 changes: 214 additions & 14 deletions apps/builder/app/builder/features/style-panel/shared/style-info.test.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,32 @@
import { test, expect } from "@jest/globals";
import { test, expect, describe } from "@jest/globals";
import { renderHook } from "@testing-library/react-hooks";
import * as defaultMetas from "@webstudio-is/sdk-components-react/metas";
import type {
Breakpoints,
Instance,
Instances,
StyleDecl,
StylesList,
import {
getStyleDeclKey,
type Breakpoints,
type Instance,
type Instances,
type StyleDecl,
type StylesList,
} from "@webstudio-is/project-build";
import {
breakpointsStore,
instancesStore,
registeredComponentMetasStore,
selectedInstanceIntanceToTagStore,
selectedInstanceSelectorStore,
selectedStyleSourceSelectorStore,
styleSourceSelectionsStore,
styleSourcesStore,
stylesStore,
} from "~/shared/nano-states";
import {
getCascadedBreakpointIds,
getCascadedInfo,
getInheritedInfo,
getNextSourceInfo,
getPreviousSourceInfo,
useStyleInfo,
} from "./style-info";

const metas = new Map(Object.entries(defaultMetas));
Expand Down Expand Up @@ -179,13 +193,6 @@ test("compute inherited styles", () => {
)
).toMatchInlineSnapshot(`
{
"color": {
"instanceId": "1",
"value": {
"type": "keyword",
"value": "black",
},
},
"fontFamily": {
"instanceId": "1",
"value": {
Expand Down Expand Up @@ -353,3 +360,196 @@ test("compute styles from next sources", () => {
}
`);
});

const resetStores = () => {
registeredComponentMetasStore.set(new Map());
instancesStore.set(new Map());
stylesStore.set(new Map());
styleSourcesStore.set(new Map());
styleSourceSelectionsStore.set(new Map());
breakpointsStore.set(new Map());
selectedInstanceSelectorStore.set(undefined);
selectedInstanceIntanceToTagStore.set(new Map());
selectedStyleSourceSelectorStore.set(undefined);
};

describe("color and currentColor", () => {
const bodyBoxInstances: Instances = new Map([
[
"body",
{
type: "instance",
id: "body",
component: "Body",
children: [{ type: "id", value: "box" }],
},
],
["box", { type: "instance", id: "box", component: "Box", children: [] }],
]);
const baseBreakpoint = new Map([["base", { id: "base", label: "Base" }]]);

test("initial color and currentColor is taken from properties", () => {
resetStores();
instancesStore.set(bodyBoxInstances);
selectedInstanceSelectorStore.set(["box", "body"]);
const { result } = renderHook(() => useStyleInfo());
expect(result.current.color?.value).toEqual({
type: "keyword",
value: "black",
});
expect(result.current.color?.currentColor).toEqual({
type: "keyword",
value: "black",
});
});

test("color and currentColor inherits from parent instance", () => {
resetStores();
instancesStore.set(bodyBoxInstances);
breakpointsStore.set(baseBreakpoint);
styleSourcesStore.set(
new Map([["body.local", { id: "body.local", type: "local" }]])
);
styleSourceSelectionsStore.set(
new Map([["body", { instanceId: "body", values: ["body.local"] }]])
);
const bodyColor: StyleDecl = {
styleSourceId: "body.local",
breakpointId: "base",
property: "color",
value: { type: "keyword", value: "red" },
};
stylesStore.set(new Map([[getStyleDeclKey(bodyColor), bodyColor]]));
selectedInstanceSelectorStore.set(["box", "body"]);
const { result } = renderHook(() => useStyleInfo());
expect(result.current.color?.value).toEqual({
type: "keyword",
value: "red",
});
expect(result.current.color?.currentColor).toEqual({
type: "keyword",
value: "red",
});
});

test("color: inherit inherits from parent instance", () => {
resetStores();
instancesStore.set(bodyBoxInstances);
breakpointsStore.set(baseBreakpoint);
styleSourcesStore.set(
new Map([
["body.local", { id: "body.local", type: "local" }],
["box.local", { id: "box.local", type: "local" }],
])
);
styleSourceSelectionsStore.set(
new Map([
["body", { instanceId: "body", values: ["body.local"] }],
["box", { instanceId: "box", values: ["box.local"] }],
])
);
const bodyColor: StyleDecl = {
styleSourceId: "body.local",
breakpointId: "base",
property: "color",
value: { type: "keyword", value: "red" },
};
const boxColor: StyleDecl = {
styleSourceId: "box.local",
breakpointId: "base",
property: "color",
value: { type: "keyword", value: "inherit" },
};
stylesStore.set(
new Map([
[getStyleDeclKey(bodyColor), bodyColor],
[getStyleDeclKey(boxColor), boxColor],
])
);
selectedInstanceSelectorStore.set(["box", "body"]);
const { result } = renderHook(() => useStyleInfo());
expect(result.current.color?.value).toEqual({
type: "keyword",
value: "inherit",
});
expect(result.current.color?.currentColor).toEqual({
type: "keyword",
value: "red",
});
});

test("color: currentColor inherits from parent instance", () => {
resetStores();
instancesStore.set(bodyBoxInstances);
breakpointsStore.set(baseBreakpoint);
styleSourcesStore.set(
new Map([
["body.local", { id: "body.local", type: "local" }],
["box.local", { id: "box.local", type: "local" }],
])
);
styleSourceSelectionsStore.set(
new Map([
["body", { instanceId: "body", values: ["body.local"] }],
["box", { instanceId: "box", values: ["box.local"] }],
])
);
const bodyColor: StyleDecl = {
styleSourceId: "body.local",
breakpointId: "base",
property: "color",
value: { type: "keyword", value: "red" },
};
const boxColor: StyleDecl = {
styleSourceId: "box.local",
breakpointId: "base",
property: "color",
value: { type: "keyword", value: "currentColor" },
};
stylesStore.set(
new Map([
[getStyleDeclKey(bodyColor), bodyColor],
[getStyleDeclKey(boxColor), boxColor],
])
);
selectedInstanceSelectorStore.set(["box", "body"]);
const { result } = renderHook(() => useStyleInfo());
expect(result.current.color?.value).toEqual({
type: "keyword",
value: "currentColor",
});
expect(result.current.color?.currentColor).toEqual({
type: "keyword",
value: "red",
});
});

test("color and currentColor inherits default value", () => {
resetStores();
instancesStore.set(bodyBoxInstances);
breakpointsStore.set(baseBreakpoint);
styleSourcesStore.set(
new Map([["body.local", { id: "body.local", type: "local" }]])
);
styleSourceSelectionsStore.set(
new Map([["body", { instanceId: "body", values: ["body.local"] }]])
);
const bodyColor: StyleDecl = {
styleSourceId: "body.local",
breakpointId: "base",
property: "color",
value: { type: "keyword", value: "inherit" },
};
stylesStore.set(new Map([[getStyleDeclKey(bodyColor), bodyColor]]));
selectedInstanceSelectorStore.set(["box", "body"]);
const { result } = renderHook(() => useStyleInfo());
expect(result.current.color?.value).toEqual({
type: "keyword",
value: "inherit",
});
expect(result.current.color?.currentColor).toEqual({
type: "keyword",
value: "black",
});
});
});
26 changes: 17 additions & 9 deletions apps/builder/app/builder/features/style-panel/shared/style-info.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import { compareMedia } from "@webstudio-is/css-engine";
import {
type StyleSourceSelector,
instancesStore,
selectedInstanceBrowserStyleStore,
selectedInstanceSelectorStore,
selectedInstanceIntanceToTagStore,
stylesIndexStore,
Expand Down Expand Up @@ -418,7 +417,6 @@ export const useStyleInfo = () => {
const selectedOrLastStyleSourceSelector = useStore(
selectedOrLastStyleSourceSelectorStore
);
const browserStyle = useStore(selectedInstanceBrowserStyleStore);
const selectedInstanceIntanceToTag = useStore(
selectedInstanceIntanceToTagStore
);
Expand Down Expand Up @@ -586,7 +584,6 @@ export const useStyleInfo = () => {
const styleInfoData: StyleInfo = {};
for (const property of styleProperties) {
// temporary solution until we start computing all styles from data
const computed = browserStyle?.[property];
const htmlValue = htmlStyle?.[property];
const defaultValue =
CUSTOM_DEFAULT_VALUES[property] ??
Expand All @@ -597,17 +594,29 @@ export const useStyleInfo = () => {
const previousSource = previousSourceInfo[property];
const nextSource = nextSourceInfo[property];
const local = selectedStyle?.[property];
const value =
const ownValue =
local ??
nextSource?.value ??
previousSource?.value ??
cascaded?.value ??
preset ??
htmlValue ??
inherited?.value ??
defaultValue;
htmlValue;
const inheritedValue = inherited?.value;
const value = ownValue ?? inheritedValue ?? defaultValue;
if (value) {
if (property === "color") {
const ownColor =
ownValue?.type === "keyword" &&
(ownValue.value === "inherit" || ownValue.value === "currentColor")
? undefined
: ownValue;
const inheritedColor =
inheritedValue?.type === "keyword" &&
(inheritedValue.value === "inherit" ||
inheritedValue.value === "currentColor")
? undefined
: inheritedValue;
const currentColor = ownColor ?? inheritedColor ?? defaultValue;
styleInfoData[property] = {
value,
local,
Expand All @@ -617,7 +626,7 @@ export const useStyleInfo = () => {
inherited,
preset,
htmlValue,
currentColor: computed,
currentColor,
};
} else {
styleInfoData[property] = {
Expand All @@ -636,7 +645,6 @@ export const useStyleInfo = () => {
return styleInfoData;
}, [
htmlStyle,
browserStyle,
presetStyle,
inheritedInfo,
cascadedInfo,
Expand Down
1 change: 1 addition & 0 deletions apps/builder/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@
"@jest/globals": "^29.3.1",
"@remix-run/dev": "1.15.0",
"@storybook/react": "^6.5.16",
"@testing-library/react-hooks": "^8.0.1",
"@types/hyphenate-style-name": "^1.0.0",
"@types/lodash.debounce": "^4.0.6",
"@types/prismjs": "^1.26.0",
Expand Down
3 changes: 2 additions & 1 deletion packages/css-data/bin/mdn-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ const normalizedValues = {
"font-family": inheritValue,
"font-size": inheritValue,
"line-height": inheritValue,
color: inheritValue,
// canvastext
color: { type: "keyword", value: "black" },
"column-gap": {
type: "unit",
value: 0,
Expand Down
2 changes: 1 addition & 1 deletion packages/css-data/src/__generated__/properties.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 0 additions & 6 deletions packages/sdk-components-react/src/body.ws.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,6 @@ const presetStyle = {
property: "lineHeight",
value: { type: "unit", unit: "number", value: 1.5 },
},
// temporary set root color
// until builder start to fallback "inherit" to black
{
property: "color",
value: { type: "keyword", value: "black" },
},
],
} satisfies PresetStyle<typeof defaultTag>;

Expand Down
Loading