diff --git a/apps/builder/app/builder/features/style-panel/sections/box-shadows/box-shadows.tsx b/apps/builder/app/builder/features/style-panel/sections/box-shadows/box-shadows.tsx index 2bed364d9d..8d58370877 100644 --- a/apps/builder/app/builder/features/style-panel/sections/box-shadows/box-shadows.tsx +++ b/apps/builder/app/builder/features/style-panel/sections/box-shadows/box-shadows.tsx @@ -1,12 +1,18 @@ -import { Tooltip, Text } from "@webstudio-is/design-system"; -import { InfoCircleIcon } from "@webstudio-is/icons"; -import type { LayersValue, StyleProperty } from "@webstudio-is/css-engine"; +import { colord, type RgbaColor } from "colord"; +import { + toValue, + type StyleProperty, + type StyleValue, +} from "@webstudio-is/css-engine"; import { RepeatedStyleSection } from "../../shared/style-section"; -import type { SectionProps } from "../shared/section"; -import { LayersList } from "../../style-layers-list"; -import { addLayer } from "../../style-layer-utils"; -import { parseCssValue } from "@webstudio-is/css-data"; import { ShadowContent } from "../../shared/shadow-content"; +import { useComputedStyleDecl } from "../../shared/model"; +import { + addRepeatedStyleItem, + editRepeatedStyleItem, + RepeatedStyle, +} from "../../shared/repeated-style"; +import { parseCssFragment } from "../../shared/parse-css-fragment"; export const properties = ["boxShadow"] satisfies [ StyleProperty, @@ -17,9 +23,41 @@ const property: StyleProperty = properties[0]; const label = "Box Shadows"; const initialBoxShadow = "0px 2px 5px 0px rgba(0, 0, 0, 0.2)"; -export const Section = (props: SectionProps) => { - const { currentStyle, deleteProperty } = props; - const value = currentStyle[property]?.value; +const getItemProps = (_index: number, layer: StyleValue) => { + const values = layer.type === "tuple" ? layer.value : []; + const labels = []; + let color: RgbaColor | undefined; + let isInset = false; + + for (const item of values) { + if (item.type === "rgb") { + color = colord(toValue(item)).toRgb(); + continue; + } + if (item.type === "keyword") { + if (item.value === "inset") { + isInset = true; + continue; + } + if (colord(item.value).isValid()) { + color = colord(item.value).toRgb(); + continue; + } + } + labels.push(toValue(item)); + } + + if (isInset) { + labels.unshift("Inner Shadow:"); + } else { + labels.unshift("Outer Shadow:"); + } + + return { label: labels.join(" "), color }; +}; + +export const Section = () => { + const styleDecl = useComputedStyleDecl("boxShadow"); return ( { description="Adds shadow effects around an element's frame." properties={properties} onAdd={() => { - addLayer( - property, - parseCssValue(property, initialBoxShadow) as LayersValue, - currentStyle, - props.createBatchUpdate + addRepeatedStyleItem( + [styleDecl], + parseCssFragment(initialBoxShadow, "boxShadow") ); }} > - {value?.type === "layers" && value.value.length > 0 && ( - { - if (layerProps.layer.type !== "tuple") { - return <>; - } - - return ( - - Paste a box-shadow CSS code without the property name, - for example: -

- {initialBoxShadow} - - } - > - - - } - /> - ); - }} - /> - )} + ( + { + editRepeatedStyleItem( + [styleDecl], + index, + new Map([["boxShadow", value]]), + options + ); + }} + /> + )} + />
); }; diff --git a/apps/builder/app/builder/features/style-panel/sections/text-shadows/text-shadows.tsx b/apps/builder/app/builder/features/style-panel/sections/text-shadows/text-shadows.tsx index 1b502a9706..f12f252dcf 100644 --- a/apps/builder/app/builder/features/style-panel/sections/text-shadows/text-shadows.tsx +++ b/apps/builder/app/builder/features/style-panel/sections/text-shadows/text-shadows.tsx @@ -1,12 +1,18 @@ -import type { SectionProps } from "../shared/section"; -import type { LayersValue, StyleProperty } from "@webstudio-is/css-engine"; -import { Tooltip, Text } from "@webstudio-is/design-system"; -import { InfoCircleIcon } from "@webstudio-is/icons"; -import { addLayer } from "../../style-layer-utils"; -import { parseCssValue } from "@webstudio-is/css-data"; +import { colord, type RgbaColor } from "colord"; +import { + toValue, + type StyleProperty, + type StyleValue, +} from "@webstudio-is/css-engine"; import { RepeatedStyleSection } from "../../shared/style-section"; -import { LayersList } from "../../style-layers-list"; import { ShadowContent } from "../../shared/shadow-content"; +import { + addRepeatedStyleItem, + editRepeatedStyleItem, + RepeatedStyle, +} from "../../shared/repeated-style"; +import { parseCssFragment } from "../../shared/parse-css-fragment"; +import { useComputedStyleDecl } from "../../shared/model"; export const properties = ["textShadow"] satisfies [ StyleProperty, @@ -17,9 +23,28 @@ const property: StyleProperty = properties[0]; const label = "Text Shadows"; const initialTextShadow = "0px 2px 5px rgba(0, 0, 0, 0.2)"; -export const Section = (props: SectionProps) => { - const { currentStyle, createBatchUpdate, deleteProperty } = props; - const value = currentStyle[property]?.value; +const getItemProps = (_index: number, layer: StyleValue) => { + const values = layer.type === "tuple" ? layer.value : []; + const labels = ["Text Shadow:"]; + let color: RgbaColor | undefined; + + for (const item of values) { + if (item.type === "rgb") { + color = colord(toValue(item)).toRgb(); + continue; + } + if (item.type === "keyword" && colord(item.value).isValid()) { + color = colord(item.value).toRgb(); + continue; + } + labels.push(toValue(item)); + } + + return { label: labels.join(" "), color }; +}; + +export const Section = () => { + const styleDecl = useComputedStyleDecl("textShadow"); return ( { description="Adds shadow effects around a text." properties={properties} onAdd={() => { - addLayer( - property, - parseCssValue(property, initialTextShadow) as LayersValue, - currentStyle, - createBatchUpdate + addRepeatedStyleItem( + [styleDecl], + parseCssFragment(initialTextShadow, "textShadow") ); }} > - {value?.type === "layers" && value.value.length > 0 && ( - { - if (layerProps.layer.type !== "tuple") { - return <>; - } - - return ( - - Paste a text-shadow CSS code without the property name, - for example: -

- {initialTextShadow} - - } - > - - - } - /> - ); - }} - /> - )} + ( + { + editRepeatedStyleItem( + [styleDecl], + index, + new Map([["textShadow", value]]), + options + ); + }} + /> + )} + />
); }; diff --git a/apps/builder/app/builder/features/style-panel/shared/filter-content.tsx b/apps/builder/app/builder/features/style-panel/shared/filter-content.tsx index c5c2357fd9..f9f4c15ade 100644 --- a/apps/builder/app/builder/features/style-panel/shared/filter-content.tsx +++ b/apps/builder/app/builder/features/style-panel/shared/filter-content.tsx @@ -228,7 +228,6 @@ export const FilterSectionContent = ({ index={index} property="dropShadow" layer={layer.args} - tooltip={<>} propertyValue={toValue(layer.args)} onEditLayer={(_, dropShadowLayers, options) => { handleComplete( @@ -236,7 +235,6 @@ export const FilterSectionContent = ({ options ); }} - deleteProperty={() => {}} hideCodeEditor={true} /> ) : undefined} diff --git a/apps/builder/app/builder/features/style-panel/shared/repeated-style.tsx b/apps/builder/app/builder/features/style-panel/shared/repeated-style.tsx index 3cb442c8e7..058bd3bf39 100644 --- a/apps/builder/app/builder/features/style-panel/shared/repeated-style.tsx +++ b/apps/builder/app/builder/features/style-panel/shared/repeated-style.tsx @@ -141,7 +141,7 @@ export const RepeatedStyle = (props: { index: number, primaryValue: StyleValue ) => { label: string; color?: RgbaColor }; - renderItemContent: (index: number) => JSX.Element; + renderItemContent: (index: number, primaryValue: StyleValue) => JSX.Element; }) => { const transformLayers = createLayersTransformer(props.styles); const { label, styles, getItemProps, renderItemContent } = props; @@ -183,7 +183,7 @@ export const RepeatedStyle = (props: { void; - deleteProperty: DeleteProperty; hideCodeEditor?: boolean; }; @@ -122,18 +123,20 @@ export const ShadowContent = ({ index, property, propertyValue, - tooltip, hideCodeEditor = false, onEditLayer, - deleteProperty, }: ShadowContentProps) => { const [intermediateValue, setIntermediateValue] = useState< IntermediateStyleValue | InvalidValue | undefined - >(); - const layerValues = useMemo(() => { + >({ type: "intermediate", value: propertyValue }); + useEffect(() => { setIntermediateValue({ type: "intermediate", value: propertyValue }); - return extractShadowProperties(layer); - }, [layer, propertyValue]); + }, [propertyValue]); + const layerValues = useMemo(() => { + return extractShadowProperties( + layer.type === "tuple" ? layer : { type: "tuple", value: [] } + ); + }, [layer]); const { offsetX, offsetY, blur, spread, color, inset } = layerValues; const colorControlProp = color ?? { @@ -379,7 +382,21 @@ export const ShadowContent = ({