feat: show generated css in property label (#4058)

Here improved property label to show css declaration with computed
(used) value.

<img width="381" alt="image"
src="https://github.com/user-attachments/assets/b299939b-c421-4571-b365-c7c8140f2a64">
This commit is contained in:
Bogdan Chadkin authored and GitHub committed 2024-09-03 22:47:05 +02:00
1 parent 99851a40d6
commit ea50da67ac
5 files changed
+54 -46

No files matched your search

@@ -55,7 +55,8 @@ export const MenuControl = ({
<DropdownMenu modal={false}>
<PropertyValueTooltip
label={currentItem?.label ?? humanizeString(property)}
property={property}
description={description}
properties={[property]}
isAdvanced={isAdvanced}
>
<DropdownMenuTrigger asChild>
@@ -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 (
<PropertyValueTooltip
label={currentItem?.label ?? humanizeString(property)}
property={property}
description={description}
properties={[property]}
isAdvanced={isAdvanced}
>
<ToggleButton
@@ -1,13 +1,11 @@
import { computed } from "nanostores";
import { useStore } from "@nanostores/react";
import { useMemo, useState, type ReactNode } from "react";
import { useState, type ReactNode } from "react";
import { AlertIcon, ResetIcon } from "@webstudio-is/icons";
import {
hyphenateProperty,
toValue,
type StyleProperty,
} from "@webstudio-is/css-engine";
import { declarationDescriptions } from "@webstudio-is/css-data";
import {
Button,
Flex,
@@ -31,10 +29,20 @@ import type {
ComputedStyleDecl,
StyleValueSourceColor,
} from "~/shared/style-object-model";
import { createComputedStyleDeclStore } from "./shared/model";
import { useComputedStyles } from "./shared/model";
import { StyleSourceBadge } from "./style-source";
import { createBatchUpdate } from "./shared/use-style-data";
const renderCss = (styles: ComputedStyleDecl[]) => {
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<string>();
const styleSourceNameSet = new Set<string>();
const instanceSet = new Set<string>();
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)}
</Text>
<Text>{description}</Text>
{(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 (
<Tooltip
open={isOpen}
@@ -421,7 +407,6 @@ export const PropertyValueTooltip = ({
content={
<PropertyInfo
title={label}
code={css}
description={
<Flex gap="2" direction="column">
{description}
@@ -433,7 +418,7 @@ export const PropertyValueTooltip = ({
)}
</Flex>
}
styles={[computedStyleDecl]}
styles={styles}
onReset={() => {
resetProperty();
setIsOpen(false);
@@ -49,7 +49,8 @@ export const BorderColor = (_props: SectionProps) => {
<Box css={{ gridColumn: `span 2` }}>
<PropertyValueTooltip
label="Color"
property={local.property as StyleProperty}
description="Sets the color of the border"
properties={properties}
isAdvanced={isAdvanced}
>
<div>
@@ -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<string, StyleValue>();
@@ -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);
};