Skip to content

Commit

Permalink
refactor: migrate properties data to hyphen case (#4970)
Browse files Browse the repository at this point in the history
properties data are now more type safe and can accept any CssProperty
name though in case of custom properties (--string) will return
undefined.

This also removes a lot of `keyof typeof properties` castings.
  • Loading branch information
TrySound authored Mar 8, 2025
1 parent fbe9eed commit 3c8ac56
Show file tree
Hide file tree
Showing 21 changed files with 444 additions and 400 deletions.
11 changes: 4 additions & 7 deletions apps/builder/app/builder/features/style-panel/property-label.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
type CssProperty,
type StyleProperty,
} from "@webstudio-is/css-engine";
import { propertiesData } from "@webstudio-is/css-data";
import {
Button,
Flex,
Expand Down Expand Up @@ -36,7 +37,6 @@ import { useComputedStyles } from "./shared/model";
import { StyleSourceBadge } from "./style-source";
import { createBatchUpdate } from "./shared/use-style-data";
import { $virtualInstances } from "~/shared/awareness";
import { styleConfigByName } from "./shared/configs";

const $isAltPressed = atom(false);
if (typeof window !== "undefined") {
Expand Down Expand Up @@ -251,7 +251,6 @@ export const PropertyLabel = ({
}
batch.publish();
};
const styleConfig = styleConfigByName(properties[0]);

return (
<Flex align="center">
Expand Down Expand Up @@ -281,7 +280,7 @@ export const PropertyLabel = ({
resetProperty();
setIsOpen(false);
}}
link={styleConfig?.mdnUrl}
link={propertiesData[hyphenateProperty(properties[0])]?.mdnUrl}
/>
}
>
Expand Down Expand Up @@ -314,7 +313,6 @@ export const PropertySectionLabel = ({
}
batch.publish();
};
const styleConfig = styleConfigByName(properties[0]);

return (
<Flex align="center">
Expand Down Expand Up @@ -342,7 +340,7 @@ export const PropertySectionLabel = ({
resetProperty();
setIsOpen(false);
}}
link={styleConfig?.mdnUrl}
link={propertiesData[hyphenateProperty(properties[0])]?.mdnUrl}
/>
}
>
Expand Down Expand Up @@ -444,7 +442,6 @@ export const PropertyValueTooltip = ({
}
batch.publish();
};
const styleConfig = styleConfigByName(properties[0]);

return (
<Tooltip
Expand Down Expand Up @@ -480,7 +477,7 @@ export const PropertyValueTooltip = ({
resetProperty();
setIsOpen(false);
}}
link={styleConfig?.mdnUrl}
link={propertiesData[hyphenateProperty(properties[0])]?.mdnUrl}
/>
}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
Grid,
} from "@webstudio-is/design-system";
import { InfoCircleIcon } from "@webstudio-is/icons";
import { properties, propertyDescriptions } from "@webstudio-is/css-data";
import { propertiesData, propertyDescriptions } from "@webstudio-is/css-data";
import { type IntermediateStyleValue } from "../../shared/css-value-input";
import { CssValueInputContainer } from "../../shared/css-value-input";
import { parseCssFragment } from "../../shared/css-fragment";
Expand Down Expand Up @@ -128,7 +128,7 @@ export const TransitionContent = ({ index }: { index: number }) => {
properties={["transitionProperty"]}
/>
<TransitionProperty
value={property ?? properties.transitionProperty.initial}
value={property ?? propertiesData["transition-property"].initial}
onChange={(value) => {
updateIntermediateValue({ property: value });
setRepeatedStyleItem(transitionProperty, index, value);
Expand All @@ -144,7 +144,7 @@ export const TransitionContent = ({ index }: { index: number }) => {
property="transitionDuration"
styleSource="local"
getOptions={() => $availableUnitVariables.get()}
value={duration ?? properties.transitionDuration.initial}
value={duration ?? propertiesData["transition-duration"].initial}
deleteProperty={() => {}}
setValue={(value, options) => {
if (value === undefined) {
Expand All @@ -169,7 +169,7 @@ export const TransitionContent = ({ index }: { index: number }) => {
property="transitionDelay"
styleSource="local"
getOptions={() => $availableUnitVariables.get()}
value={delay ?? properties.transitionDelay.initial}
value={delay ?? propertiesData["transition-delay"].initial}
deleteProperty={() => {}}
setValue={(value, options) => {
if (value === undefined) {
Expand Down Expand Up @@ -203,7 +203,10 @@ export const TransitionContent = ({ index }: { index: number }) => {
{ type: "keyword", value: "step-end" },
...$availableVariables.get(),
]}
value={timingFunction ?? properties.transitionTimingFunction.initial}
value={
timingFunction ??
propertiesData["transition-timing-function"].initial
}
deleteProperty={() => {}}
setValue={(value, options) => {
if (value === undefined) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@ import {
SectionTitleButton,
Tooltip,
} from "@webstudio-is/design-system";
import { properties } from "@webstudio-is/css-data";
import { propertiesData } from "@webstudio-is/css-data";
import {
hyphenateProperty,
toValue,
type CssProperty,
type LayerValueItem,
type StyleProperty,
} from "@webstudio-is/css-engine";
import {
CollapsibleSectionRoot,
Expand All @@ -30,12 +31,12 @@ import { TransitionContent } from "./transition-content";
import { parseCssFragment } from "../../shared/css-fragment";

const transitionLongHandProperties = [
"transitionProperty",
"transitionTimingFunction",
"transitionDelay",
"transitionDuration",
"transitionBehavior",
] as const satisfies StyleProperty[];
"transition-property",
"transition-timing-function",
"transition-delay",
"transition-duration",
"transition-behavior",
] as const satisfies CssProperty[];

export { transitionLongHandProperties as properties };

Expand All @@ -47,7 +48,7 @@ const getTransitionLayers = (
) => {
const transitionPropertyValue = styles[0].cascadedValue;
const currentPropertyValue = styles.find(
(styleDecl) => styleDecl.property === property
(styleDecl) => hyphenateProperty(styleDecl.property) === property
)?.cascadedValue;
const transitionPropertiesCount =
transitionPropertyValue.type === "layers"
Expand All @@ -56,7 +57,7 @@ const getTransitionLayers = (
const definedLayers: LayerValueItem[] =
currentPropertyValue?.type === "layers"
? currentPropertyValue.value
: [properties[property].initial];
: [propertiesData[property].initial as LayerValueItem];
return repeatUntil(definedLayers, transitionPropertiesCount);
};

Expand All @@ -68,19 +69,19 @@ const getLayerLabel = ({
index: number;
}) => {
// show label without hidden replacement
const propertyLayer = getTransitionLayers(styles, "transitionProperty")[
const propertyLayer = getTransitionLayers(styles, "transition-property")[
index
];
const property = humanizeString(toValue({ ...propertyLayer, hidden: false }));
const duration = toValue(
getTransitionLayers(styles, "transitionDuration")[index]
getTransitionLayers(styles, "transition-duration")[index]
);
const timingFunctionLayer = getTransitionLayers(
styles,
"transitionTimingFunction"
"transition-timing-function"
)[index];
const timingFunction = toValue({ ...timingFunctionLayer, hidden: false });
const delay = toValue(getTransitionLayers(styles, "transitionDelay")[index]);
const delay = toValue(getTransitionLayers(styles, "transition-delay")[index]);
return `${property}: ${duration} ${timingFunction} ${delay}`;
};

Expand Down
10 changes: 1 addition & 9 deletions apps/builder/app/builder/features/style-panel/shared/configs.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,11 @@
import type { CssProperty, StyleProperty } from "@webstudio-is/css-engine";
import {
camelCaseProperty,
keywordValues,
properties,
} from "@webstudio-is/css-data";
import { camelCaseProperty, keywordValues } from "@webstudio-is/css-data";
import { humanizeString } from "~/shared/string-utils";
import type * as Controls from "../controls";

type BaseStyleConfig = {
label: string;
property: StyleProperty;
mdnUrl?: string;
};

export type Control = keyof typeof Controls;
Expand Down Expand Up @@ -59,15 +54,12 @@ export const styleConfigByName = (

const keywords = keywordValues[property] || [];
const label = humanizeString(property);
// property data does not exist for css custom properties
const propertyData = properties[property] ?? {};

const result = {
label,
property,
control: getControl(property),
items: keywords.map((keyword) => ({ label: keyword, name: keyword })),
...("mdnUrl" in propertyData && { mdnUrl: propertyData.mdnUrl }),
};

styleConfigCache.set(property, result);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,12 @@ import {
} from "react";
import { useUnitSelect, type UnitOption } from "./unit-select";
import { parseIntermediateOrInvalidValue } from "./parse-intermediate-or-invalid-value";
import { toValue } from "@webstudio-is/css-engine";
import { hyphenateProperty, toValue } from "@webstudio-is/css-engine";
import {
camelCaseProperty,
declarationDescriptions,
isValidDeclaration,
properties,
propertiesData,
} from "@webstudio-is/css-data";
import {
$selectedInstanceBrowserStyle,
Expand All @@ -66,7 +66,7 @@ import { useEffectEvent } from "~/shared/hook-utils/effect-event";
// We need to enable scrub on properties that can have numeric value.
const canBeNumber = (property: StyleProperty, value: CssValueInputValue) => {
const unitGroups =
properties[property as keyof typeof properties]?.unitGroups ?? [];
propertiesData[hyphenateProperty(property)]?.unitGroups ?? [];
// allow scrubbing css variables with unit value
return unitGroups.length !== 0 || value.type === "unit";
};
Expand Down Expand Up @@ -610,7 +610,7 @@ export const CssValueInput = ({

const [isUnitsOpen, unitSelectElement] = useUnitSelect({
options: unitOptions,
property,
property: hyphenateProperty(multiCaseProperty),
value,
onChange: (unitOrKeyword) => {
if (unitOrKeyword.type === "keyword") {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import type {
StyleProperty,
StyleValue,
InvalidValue,
Unit,
import {
type StyleProperty,
type StyleValue,
type InvalidValue,
type Unit,
hyphenateProperty,
} from "@webstudio-is/css-engine";
import {
units,
parseCssValue,
cssTryParseValue,
properties,
propertiesData,
} from "@webstudio-is/css-data";
import type { IntermediateStyleValue } from "./css-value-input";
import { evaluateMath } from "./evaluate-math";
Expand All @@ -18,7 +19,7 @@ const unitsList = Object.values(units).flat();

const getDefaultUnit = (property: StyleProperty): Unit => {
const unitGroups =
properties[property as keyof typeof properties]?.unitGroups ?? [];
propertiesData[hyphenateProperty(property)]?.unitGroups ?? [];

for (const unitGroup of unitGroups) {
if (unitGroup === "number") {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import type { CssValueInputValue } from "./css-value-input";
import { properties, units, isValidDeclaration } from "@webstudio-is/css-data";
import {
propertiesData,
units,
isValidDeclaration,
} from "@webstudio-is/css-data";
import type { UnitOption } from "./unit-select";
import type { CssProperty } from "@webstudio-is/css-engine";

// To make sorting stable
const preferedSorting = [
Expand Down Expand Up @@ -37,7 +42,7 @@ const initialLengthUnits = [
] as const;

export const buildOptions = (
property: string,
property: CssProperty,
value: CssValueInputValue,
nestedSelectButtonUnitless: string
) => {
Expand All @@ -50,8 +55,7 @@ export const buildOptions = (

// show at least current unit when no property meta is available
// for example in custom properties
const unitGroups =
properties[property as keyof typeof properties]?.unitGroups ?? [];
const unitGroups = propertiesData[property]?.unitGroups ?? [];

for (const unitGroup of unitGroups) {
if (unitGroup === "number") {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useState, useMemo, type JSX } from "react";
import * as SelectPrimitive from "@radix-ui/react-select";
import type { Unit } from "@webstudio-is/css-engine";
import type { CssProperty, Unit } from "@webstudio-is/css-engine";
import {
SelectScrollUpButton,
SelectScrollDownButton,
Expand All @@ -23,7 +23,7 @@ export type UnitOption =
| { id: string; label: string; type: "keyword" };

type UseUnitSelectType = {
property: string;
property: CssProperty;
value: CssValueInputValue;
onChange: (
value: { type: "unit"; value: Unit } | { type: "keyword"; value: string }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ import { useMemo, useRef } from "react";
import type { HtmlTags } from "html-tags";
import { computed, type ReadableAtom } from "nanostores";
import { useStore } from "@nanostores/react";
import { camelCaseProperty, properties } from "@webstudio-is/css-data";
import { camelCaseProperty, propertiesData } from "@webstudio-is/css-data";
import {
compareMedia,
hyphenateProperty,
toVarFallback,
type CssProperty,
type StyleProperty,
Expand Down Expand Up @@ -181,7 +182,7 @@ export const getDefinedStyles = ({
instanceStyles.add(styleDecl);
}
const inherited =
properties[styleDecl.property as keyof typeof properties]?.inherited ??
propertiesData[hyphenateProperty(styleDecl.property)]?.inherited ??
// custom properties are always inherited
true;
if (
Expand Down
Loading

0 comments on commit 3c8ac56

Please sign in to comment.