From ea50da67acd0d8d4ea0e4f7303e77ba9b9a107ec Mon Sep 17 00:00:00 2001 From: Bogdan Chadkin Date: Tue, 3 Sep 2024 22:47:05 +0200 Subject: [PATCH] feat: show generated css in property label (#4058) Here improved property label to show css declaration with computed (used) value. image --- .../controls/menu/menu-control.tsx | 3 +- .../controls/toggle/toggle-control.tsx | 8 ++- .../features/style-panel/property-label.tsx | 65 +++++++------------ .../sections/borders/border-color.tsx | 3 +- .../features/style-panel/shared/model.tsx | 21 +++++- 5 files changed, 54 insertions(+), 46 deletions(-) diff --git a/apps/builder/app/builder/features/style-panel/controls/menu/menu-control.tsx b/apps/builder/app/builder/features/style-panel/controls/menu/menu-control.tsx index e9d19e1d5d..fc0a671b30 100644 --- a/apps/builder/app/builder/features/style-panel/controls/menu/menu-control.tsx +++ b/apps/builder/app/builder/features/style-panel/controls/menu/menu-control.tsx @@ -55,7 +55,8 @@ export const MenuControl = ({ diff --git a/apps/builder/app/builder/features/style-panel/controls/toggle/toggle-control.tsx b/apps/builder/app/builder/features/style-panel/controls/toggle/toggle-control.tsx index 251cfb7720..8f839c6dda 100644 --- a/apps/builder/app/builder/features/style-panel/controls/toggle/toggle-control.tsx +++ b/apps/builder/app/builder/features/style-panel/controls/toggle/toggle-control.tsx @@ -1,4 +1,5 @@ import { ToggleButton } from "@webstudio-is/design-system"; +import { declarationDescriptions } from "@webstudio-is/css-data"; import { toValue, type StyleProperty } from "@webstudio-is/css-engine"; import type { IconComponent } from "@webstudio-is/icons"; import { humanizeString } from "~/shared/string-utils"; @@ -29,11 +30,16 @@ export const ToggleControl = ({ // when there is no matching item const isAdvanced = computedStyleDecl.source.name !== "default" && currentItem === undefined; + const description = + declarationDescriptions[ + `${property}:${currentValue}` as keyof typeof declarationDescriptions + ]; return ( { + let css = ""; + for (const computedStyleDecl of styles) { + const property = hyphenateProperty(computedStyleDecl.property); + const value = toValue(computedStyleDecl.cascadedValue); + css += `${property}: ${value};\n`; + } + return css.trimEnd(); +}; + export const PropertyInfo = ({ title, code, @@ -54,16 +62,14 @@ export const PropertyInfo = ({ const metas = useStore($registeredComponentMetas); let resettable = false; - const properties: string[] = []; const breakpointSet = new Set(); const styleSourceNameSet = new Set(); const instanceSet = new Set(); - for (const { property, source } of styles) { + for (const { source } of styles) { if (source.name === "local" || source.name === "overwritten") { resettable = true; } - properties.push(hyphenateProperty(property)); const instance = source.instanceId ? instances.get(source.instanceId) : undefined; @@ -110,7 +116,7 @@ export const PropertyInfo = ({ userSelect="text" css={{ whiteSpace: "break-spaces", cursor: "text" }} > - {code ?? properties.join("\n")} + {code ?? renderCss(styles)} {description} {(styleSourceNameSet.size > 0 || instanceSet.size > 0) && ( @@ -189,14 +195,7 @@ export const PropertyLabel = ({ description: string; properties: [StyleProperty, ...StyleProperty[]]; }) => { - const $styles = useMemo(() => { - return computed( - properties.map(createComputedStyleDeclStore), - (...computedStyles) => computedStyles - ); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, properties); - const styles = useStore($styles); + const styles = useComputedStyles(properties); const colors = styles.map(({ source }) => source.name); const styleValueSourceColor = getPriorityStyleSource(colors); const [isOpen, setIsOpen] = useState(false); @@ -255,14 +254,7 @@ export const PropertySectionLabel = ({ description: string; properties: [StyleProperty, ...StyleProperty[]]; }) => { - const $styles = useMemo(() => { - return computed( - properties.map(createComputedStyleDeclStore), - (...computedStyles) => computedStyles - ); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, properties); - const styles = useStore($styles); + const styles = useComputedStyles(properties); const colors = styles.map(({ source }) => source.name); const styleValueSourceColor = getPriorityStyleSource(colors); const [isOpen, setIsOpen] = useState(false); @@ -377,32 +369,26 @@ export const PropertyInlineLabel = ({ export const PropertyValueTooltip = ({ label, - property, + description, + properties, isAdvanced, children, }: { label: string; - property: StyleProperty; + description: string; + properties: [StyleProperty, ...StyleProperty[]]; isAdvanced?: boolean; children: ReactNode; }) => { - const $computedStyleDecl = useMemo( - () => createComputedStyleDeclStore(property), - [property] - ); - const computedStyleDecl = useStore($computedStyleDecl); + const styles = useComputedStyles(properties); const [isOpen, setIsOpen] = useState(false); const resetProperty = () => { const batch = createBatchUpdate(); - batch.deleteProperty(property); + for (const property of properties) { + batch.deleteProperty(property); + } batch.publish(); }; - const value = toValue(computedStyleDecl.usedValue); - const css = `${hyphenateProperty(property)}: ${value};`; - const description = - declarationDescriptions[ - `${property}:${value}` as keyof typeof declarationDescriptions - ]; return ( {description} @@ -433,7 +418,7 @@ export const PropertyValueTooltip = ({ )} } - styles={[computedStyleDecl]} + styles={styles} onReset={() => { resetProperty(); setIsOpen(false); diff --git a/apps/builder/app/builder/features/style-panel/sections/borders/border-color.tsx b/apps/builder/app/builder/features/style-panel/sections/borders/border-color.tsx index 92d2bb0c2f..a8a69b590c 100644 --- a/apps/builder/app/builder/features/style-panel/sections/borders/border-color.tsx +++ b/apps/builder/app/builder/features/style-panel/sections/borders/border-color.tsx @@ -49,7 +49,8 @@ export const BorderColor = (_props: SectionProps) => {
diff --git a/apps/builder/app/builder/features/style-panel/shared/model.tsx b/apps/builder/app/builder/features/style-panel/shared/model.tsx index 3c5f44e4c4..cdca33597c 100644 --- a/apps/builder/app/builder/features/style-panel/shared/model.tsx +++ b/apps/builder/app/builder/features/style-panel/shared/model.tsx @@ -1,6 +1,11 @@ +import { useMemo } from "react"; import { computed } from "nanostores"; import { useStore } from "@nanostores/react"; -import { compareMedia, type StyleValue } from "@webstudio-is/css-engine"; +import { + compareMedia, + type StyleProperty, + type StyleValue, +} from "@webstudio-is/css-engine"; import type { Breakpoint, Instance } from "@webstudio-is/sdk"; import { $breakpoints, @@ -19,7 +24,6 @@ import { getPresetStyleDeclKey, type StyleObjectModel, } from "~/shared/style-object-model"; -import { useMemo } from "react"; const $presetStyles = computed($registeredComponentMetas, (metas) => { const presetStyles = new Map(); @@ -125,10 +129,21 @@ export const useStyleObjectModel = () => { return useStore($model); }; -export const useComputedStyleDecl = (property: string) => { +export const useComputedStyleDecl = (property: StyleProperty) => { const $store = useMemo( () => createComputedStyleDeclStore(property), [property] ); return useStore($store); }; + +export const useComputedStyles = (properties: StyleProperty[]) => { + const $styles = useMemo(() => { + return computed( + properties.map(createComputedStyleDeclStore), + (...computedStyles) => computedStyles + ); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, properties); + return useStore($styles); +};