diff --git a/apps/builder/app/builder/features/style-panel/sections/advanced/advanced.tsx b/apps/builder/app/builder/features/style-panel/sections/advanced/advanced.tsx
index 4f8e2619ff32..3f05991d8af2 100644
--- a/apps/builder/app/builder/features/style-panel/sections/advanced/advanced.tsx
+++ b/apps/builder/app/builder/features/style-panel/sections/advanced/advanced.tsx
@@ -1,5 +1,13 @@
-import { useMemo, useRef, useState } from "react";
-import { Box, Flex, Text } from "@webstudio-is/design-system";
+import { useMemo, useRef, useState, type ReactNode } from "react";
+import { PlusIcon } from "@webstudio-is/icons";
+import {
+ Box,
+ Flex,
+ SectionTitle,
+ SectionTitleButton,
+ SectionTitleLabel,
+ Text,
+} from "@webstudio-is/design-system";
import { properties as propertiesData } from "@webstudio-is/css-data";
import { useStore } from "@nanostores/react";
import type { StyleProperty } from "@webstudio-is/css-engine";
@@ -17,10 +25,15 @@ import {
type StyleInfo,
} from "../../shared/style-info";
import { Add } from "./add";
-import { CollapsibleSection } from "../../shared/collapsible-section";
import { sections } from "../sections";
import { toKebabCase } from "../../shared/keyword-utils";
import type { DeleteProperty } from "../../shared/use-style-data";
+import {
+ CollapsibleSectionRoot,
+ useOpenState,
+} from "~/builder/shared/collapsible-section";
+import { useComputedStyles } from "../../shared/model";
+import { getDots } from "../../shared/style-section";
const allPropertyNames = Object.keys(propertiesData).sort(
Intl.Collator().compare
@@ -82,6 +95,42 @@ const usePropertyNames = (currentStyle: StyleInfo) => {
// Only here to keep the same section module interface
export const properties = [];
+const AdvancedStyleSection = (props: {
+ label: string;
+ properties: StyleProperty[];
+ onAdd: () => void;
+ children: ReactNode;
+}) => {
+ const { label, children, properties, onAdd } = props;
+ const [isOpen, setIsOpen] = useOpenState(props);
+ const styles = useComputedStyles(properties);
+ return (
+ }
+ onClick={() => {
+ setIsOpen(true);
+ onAdd();
+ }}
+ />
+ }
+ >
+ {label}
+
+ }
+ >
+ {children}
+
+ );
+};
+
export const Section = ({
currentStyle,
setProperty,
@@ -97,13 +146,10 @@ export const Section = ({
};
return (
- {
- setAddingProp("");
- }}
+ onAdd={() => setAddingProp("")}
>
{addingProp !== undefined && (
-
+
);
};
diff --git a/apps/builder/app/builder/features/style-panel/sections/backdrop-filter/backdrop-filter.tsx b/apps/builder/app/builder/features/style-panel/sections/backdrop-filter/backdrop-filter.tsx
index 7c997da47706..9de87cd46af3 100644
--- a/apps/builder/app/builder/features/style-panel/sections/backdrop-filter/backdrop-filter.tsx
+++ b/apps/builder/app/builder/features/style-panel/sections/backdrop-filter/backdrop-filter.tsx
@@ -1,21 +1,12 @@
-import { CollapsibleSectionRoot } from "~/builder/shared/collapsible-section";
import type { SectionProps } from "../shared/section";
import type { LayersValue, StyleProperty } from "@webstudio-is/css-engine";
-import { useState } from "react";
-import {
- SectionTitle,
- SectionTitleButton,
- Tooltip,
- Flex,
- Text,
-} from "@webstudio-is/design-system";
+import { Tooltip, Flex, Text } from "@webstudio-is/design-system";
import { parseCssValue } from "@webstudio-is/css-data";
-import { getDots } from "../../shared/collapsible-section";
-import { InfoCircleIcon, PlusIcon } from "@webstudio-is/icons";
+import { RepeatedStyleSection } from "../../shared/style-section";
+import { InfoCircleIcon } from "@webstudio-is/icons";
import { addLayer } from "../../style-layer-utils";
import { LayersList } from "../../style-layers-list";
import { FilterSectionContent } from "../../shared/filter-content";
-import { PropertySectionLabel } from "../../property-label";
export const properties = ["backdropFilter"] satisfies [
StyleProperty,
@@ -28,45 +19,21 @@ const initialBackdropFilter = "blur(0px)";
export const Section = (props: SectionProps) => {
const { currentStyle, deleteProperty } = props;
- const [isOpen, setIsOpen] = useState(true);
const value = currentStyle[property]?.value;
return (
-
- }
- onClick={() => {
- addLayer(
- property,
- parseCssValue(
- property,
- initialBackdropFilter
- ) as LayersValue,
- currentStyle,
- props.createBatchUpdate
- );
- setIsOpen(true);
- }}
- />
-
- }
- >
-
-
- }
+ description="Backdrop filters are similar to filters, but are applied to the area behind an element. This can be useful for creating frosted glass effects."
+ properties={properties}
+ onAdd={() => {
+ addLayer(
+ property,
+ parseCssValue(property, initialBackdropFilter) as LayersValue,
+ currentStyle,
+ props.createBatchUpdate
+ );
+ }}
>
{value?.type === "tuple" && value.value.length > 0 && (
{
}}
/>
)}
-
+
);
};
diff --git a/apps/builder/app/builder/features/style-panel/sections/backgrounds/backgrounds.tsx b/apps/builder/app/builder/features/style-panel/sections/backgrounds/backgrounds.tsx
index 21398f60b4dd..1e5a60af76ba 100644
--- a/apps/builder/app/builder/features/style-panel/sections/backgrounds/backgrounds.tsx
+++ b/apps/builder/app/builder/features/style-panel/sections/backgrounds/backgrounds.tsx
@@ -1,14 +1,13 @@
import { useStore } from "@nanostores/react";
-import type { SectionProps } from "../shared/section";
-import { FloatingPanel } from "~/builder/shared/floating-panel";
+import { useMemo } from "react";
+import type { StyleProperty, StyleValue } from "@webstudio-is/css-engine";
+import { propertyDescriptions } from "@webstudio-is/css-data";
import {
CssValueListItem,
CssValueListArrowFocus,
Flex,
Grid,
Label,
- SectionTitle,
- SectionTitleButton,
SmallIconButton,
SmallToggleButton,
theme,
@@ -18,8 +17,9 @@ import {
EyeconOpenIcon,
EyeconClosedIcon,
SubtractIcon,
- PlusIcon,
} from "@webstudio-is/icons";
+import type { SectionProps } from "../shared/section";
+import { FloatingPanel } from "~/builder/shared/floating-panel";
import { $assets } from "~/shared/nano-states";
import type { StyleInfo } from "../../shared/style-info";
import { ColorControl } from "../../controls/color/color-control";
@@ -37,15 +37,8 @@ import {
} from "./background-layers";
import { BackgroundContent } from "./background-content";
import { getLayerName, LayerThumbnail } from "./background-thumbnail";
-import { useMemo } from "react";
-import type { StyleProperty, StyleValue } from "@webstudio-is/css-engine";
-import {
- CollapsibleSectionRoot,
- useOpenState,
-} from "~/builder/shared/collapsible-section";
-import { getDots } from "../../shared/collapsible-section";
-import { PropertyLabel, PropertySectionLabel } from "../../property-label";
-import { propertyDescriptions } from "@webstudio-is/css-data";
+import { RepeatedStyleSection } from "../../shared/style-section";
+import { PropertyLabel } from "../../property-label";
const Layer = (props: {
id: string;
@@ -149,48 +142,6 @@ export const properties = [
"backgroundBlendMode",
] satisfies Array;
-const BackgroundsCollapsibleSection = ({
- children,
- currentStyle,
- createBatchUpdate,
-}: SectionProps & { children: React.ReactNode }) => {
- const label = "Backgrounds";
- const [isOpen, setIsOpen] = useOpenState({ label });
-
- return (
- {
- setIsOpen(nextIsOpen);
- }}
- trigger={
- }
- onClick={() => {
- addLayer(currentStyle, createBatchUpdate);
- setIsOpen(true);
- }}
- />
- }
- >
-
-
- }
- >
- {children}
-
- );
-};
-
export const Section = (props: SectionProps) => {
const { setProperty, deleteProperty, currentStyle, createBatchUpdate } =
props;
@@ -213,11 +164,13 @@ export const Section = (props: SectionProps) => {
});
return (
- {
+ addLayer(currentStyle, createBatchUpdate);
+ }}
>
@@ -270,6 +223,6 @@ export const Section = (props: SectionProps) => {
-
+
);
};
diff --git a/apps/builder/app/builder/features/style-panel/sections/borders/borders.tsx b/apps/builder/app/builder/features/style-panel/sections/borders/borders.tsx
index d8222d15f555..d433beabdf63 100644
--- a/apps/builder/app/builder/features/style-panel/sections/borders/borders.tsx
+++ b/apps/builder/app/builder/features/style-panel/sections/borders/borders.tsx
@@ -1,7 +1,7 @@
import { Flex } from "@webstudio-is/design-system";
import type { StyleProperty } from "@webstudio-is/css-engine";
import type { SectionProps } from "../shared/section";
-import { CollapsibleSection } from "../../shared/collapsible-section";
+import { StyleSection } from "../../shared/style-section";
import {
BorderRadius,
properties as borderRadiusProperties,
@@ -28,17 +28,13 @@ export const properties = [
export const Section = (props: SectionProps) => {
return (
-
+
-
+
);
};
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 46187dc04c1e..2bed364d9d71 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,20 +1,12 @@
-import {
- SectionTitle,
- SectionTitleButton,
- Tooltip,
- Text,
-} from "@webstudio-is/design-system";
-import { InfoCircleIcon, PlusIcon } from "@webstudio-is/icons";
+import { Tooltip, Text } from "@webstudio-is/design-system";
+import { InfoCircleIcon } from "@webstudio-is/icons";
import type { LayersValue, StyleProperty } from "@webstudio-is/css-engine";
-import { CollapsibleSectionRoot } from "~/builder/shared/collapsible-section";
-import { useState } from "react";
-import { getDots } from "../../shared/collapsible-section";
+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 { PropertySectionLabel } from "../../property-label";
export const properties = ["boxShadow"] satisfies [
StyleProperty,
@@ -27,40 +19,21 @@ const initialBoxShadow = "0px 2px 5px 0px rgba(0, 0, 0, 0.2)";
export const Section = (props: SectionProps) => {
const { currentStyle, deleteProperty } = props;
- const [isOpen, setIsOpen] = useState(true);
const value = currentStyle[property]?.value;
return (
- }
- onClick={() => {
- addLayer(
- property,
- parseCssValue(property, initialBoxShadow) as LayersValue,
- currentStyle,
- props.createBatchUpdate
- );
- setIsOpen(true);
- }}
- />
- }
- >
-
-
- }
+ description="Adds shadow effects around an element's frame."
+ properties={properties}
+ onAdd={() => {
+ addLayer(
+ property,
+ parseCssValue(property, initialBoxShadow) as LayersValue,
+ currentStyle,
+ props.createBatchUpdate
+ );
+ }}
>
{value?.type === "layers" && value.value.length > 0 && (
{
}}
/>
)}
-
+
);
};
diff --git a/apps/builder/app/builder/features/style-panel/sections/filter/filter.tsx b/apps/builder/app/builder/features/style-panel/sections/filter/filter.tsx
index 0b40b6b1a2d3..f1c5d8e2e297 100644
--- a/apps/builder/app/builder/features/style-panel/sections/filter/filter.tsx
+++ b/apps/builder/app/builder/features/style-panel/sections/filter/filter.tsx
@@ -1,21 +1,12 @@
-import { CollapsibleSectionRoot } from "~/builder/shared/collapsible-section";
import type { SectionProps } from "../shared/section";
-import { useState } from "react";
-import {
- Flex,
- SectionTitle,
- SectionTitleButton,
- Tooltip,
- Text,
-} from "@webstudio-is/design-system";
+import { Flex, Tooltip, Text } from "@webstudio-is/design-system";
import { parseCssValue } from "@webstudio-is/css-data";
-import { getDots } from "../../shared/collapsible-section";
-import { InfoCircleIcon, PlusIcon } from "@webstudio-is/icons";
+import { RepeatedStyleSection } from "../../shared/style-section";
+import { InfoCircleIcon } from "@webstudio-is/icons";
import { LayersValue, type StyleProperty } from "@webstudio-is/css-engine";
import { LayersList } from "../../style-layers-list";
import { addLayer } from "../../style-layer-utils";
import { FilterSectionContent } from "../../shared/filter-content";
-import { PropertySectionLabel } from "../../property-label";
export const properties = ["filter"] satisfies [
StyleProperty,
@@ -28,42 +19,21 @@ const initialFilter = "blur(0px)";
export const Section = (props: SectionProps) => {
const { currentStyle, deleteProperty } = props;
- const [isOpen, setIsOpen] = useState(true);
const value = currentStyle[property]?.value;
return (
-
- }
- onClick={() => {
- addLayer(
- property,
- parseCssValue(property, initialFilter) as LayersValue,
- currentStyle,
- props.createBatchUpdate
- );
- setIsOpen(true);
- }}
- />
-
- }
- >
-
-
- }
+ description="Filter effects allow you to apply graphical effects like blurring, color shifting, and more to elements."
+ properties={properties}
+ onAdd={() => {
+ addLayer(
+ property,
+ parseCssValue(property, initialFilter) as LayersValue,
+ currentStyle,
+ props.createBatchUpdate
+ );
+ }}
>
{value?.type === "tuple" && value.value.length > 0 && (
{
}}
/>
)}
-
+
);
};
diff --git a/apps/builder/app/builder/features/style-panel/sections/flex-child/flex-child.tsx b/apps/builder/app/builder/features/style-panel/sections/flex-child/flex-child.tsx
index d69ed1cba680..ce8367eea06e 100644
--- a/apps/builder/app/builder/features/style-panel/sections/flex-child/flex-child.tsx
+++ b/apps/builder/app/builder/features/style-panel/sections/flex-child/flex-child.tsx
@@ -7,7 +7,6 @@ import {
} from "@webstudio-is/design-system";
import { toValue } from "@webstudio-is/css-engine";
import type { StyleProperty } from "@webstudio-is/css-engine";
-import type { SectionProps } from "../shared/section";
import {
ToggleGroupControl,
ToggleGroupTooltip,
@@ -27,7 +26,7 @@ import {
EllipsesIcon,
} from "@webstudio-is/icons";
import { FloatingPanel } from "~/builder/shared/floating-panel";
-import { CollapsibleSection } from "../../shared/collapsible-section";
+import { StyleSection } from "../../shared/style-section";
import {
getPriorityStyleValueSource,
PropertyLabel,
@@ -45,19 +44,15 @@ export const properties = [
"order",
] satisfies [StyleProperty, ...StyleProperty[]];
-export const Section = (props: SectionProps) => {
+export const Section = () => {
return (
-
+
-
+
);
};
diff --git a/apps/builder/app/builder/features/style-panel/sections/layout/layout.tsx b/apps/builder/app/builder/features/style-panel/sections/layout/layout.tsx
index ab4d2b5ca836..def38ae42f96 100644
--- a/apps/builder/app/builder/features/style-panel/sections/layout/layout.tsx
+++ b/apps/builder/app/builder/features/style-panel/sections/layout/layout.tsx
@@ -42,7 +42,7 @@ import type { SectionProps } from "../shared/section";
import { FlexGrid } from "./shared/flex-grid";
import { MenuControl, SelectControl } from "../../controls";
import { styleConfigByName } from "../../shared/configs";
-import { CollapsibleSection } from "../../shared/collapsible-section";
+import { StyleSection } from "../../shared/style-section";
import { createBatchUpdate, deleteProperty } from "../../shared/use-style-data";
import {
type IntermediateStyleValue,
@@ -492,11 +492,7 @@ export const Section = ({ currentStyle, createBatchUpdate }: SectionProps) => {
const value = toValue(currentStyle.display?.value);
return (
-
+
{
/>
)}
-
+
);
};
diff --git a/apps/builder/app/builder/features/style-panel/sections/list-item.tsx b/apps/builder/app/builder/features/style-panel/sections/list-item.tsx
index 60a7712e90ca..8f525fa5a143 100644
--- a/apps/builder/app/builder/features/style-panel/sections/list-item.tsx
+++ b/apps/builder/app/builder/features/style-panel/sections/list-item.tsx
@@ -1,20 +1,15 @@
import { propertyDescriptions } from "@webstudio-is/css-data";
import type { StyleProperty } from "@webstudio-is/css-engine";
import { Grid, theme } from "@webstudio-is/design-system";
-import type { SectionProps } from "./shared/section";
import { SelectControl } from "../controls";
-import { CollapsibleSection } from "../shared/collapsible-section";
+import { StyleSection } from "../shared/style-section";
import { PropertyLabel } from "../property-label";
export const properties = ["listStyleType"] satisfies Array;
-export const Section = ({ currentStyle: style }: SectionProps) => {
+export const Section = () => {
return (
-
+
{
/>
-
+
);
};
diff --git a/apps/builder/app/builder/features/style-panel/sections/outline/outline.tsx b/apps/builder/app/builder/features/style-panel/sections/outline/outline.tsx
index f4ed7dd37927..9c0f568e925a 100644
--- a/apps/builder/app/builder/features/style-panel/sections/outline/outline.tsx
+++ b/apps/builder/app/builder/features/style-panel/sections/outline/outline.tsx
@@ -2,7 +2,7 @@ import { Flex, Grid, theme, Box } from "@webstudio-is/design-system";
import { propertyDescriptions } from "@webstudio-is/css-data";
import type { StyleProperty } from "@webstudio-is/css-engine";
import { ColorControl } from "../../controls";
-import { CollapsibleSection } from "../../shared/collapsible-section";
+import { StyleSection } from "../../shared/style-section";
import type { SectionProps } from "../shared/section";
import { OutlineStyle } from "./outline-style";
import { OutlineWidth } from "./outline-width";
@@ -25,11 +25,7 @@ export const Section = (props: SectionProps) => {
}
return (
-
+
{outlineStyle.value.value !== "none" && (
@@ -64,6 +60,6 @@ export const Section = (props: SectionProps) => {
>
)}
-
+
);
};
diff --git a/apps/builder/app/builder/features/style-panel/sections/position/position.tsx b/apps/builder/app/builder/features/style-panel/sections/position/position.tsx
index 6fe32a7d763e..3b6fb8981a4a 100644
--- a/apps/builder/app/builder/features/style-panel/sections/position/position.tsx
+++ b/apps/builder/app/builder/features/style-panel/sections/position/position.tsx
@@ -1,6 +1,6 @@
import type { StyleProperty } from "@webstudio-is/css-engine";
import type { SectionProps } from "../shared/section";
-import { CollapsibleSection } from "../../shared/collapsible-section";
+import { StyleSection } from "../../shared/style-section";
import { Grid, theme } from "@webstudio-is/design-system";
import { SelectControl, TextControl } from "../../controls";
import { styleConfigByName } from "../../shared/configs";
@@ -54,11 +54,7 @@ export const Section = ({
);
return (
-
+
)}
-
+
);
};
diff --git a/apps/builder/app/builder/features/style-panel/sections/size/size.tsx b/apps/builder/app/builder/features/style-panel/sections/size/size.tsx
index 7b2678b6dc3a..f1dd7035906e 100644
--- a/apps/builder/app/builder/features/style-panel/sections/size/size.tsx
+++ b/apps/builder/app/builder/features/style-panel/sections/size/size.tsx
@@ -21,7 +21,7 @@ import {
AutoScrollIcon,
EllipsesIcon,
} from "@webstudio-is/icons";
-import { CollapsibleSection } from "../../shared/collapsible-section";
+import { StyleSection } from "../../shared/style-section";
import { theme } from "@webstudio-is/design-system";
import { ToggleGroupControl } from "../../controls/toggle-group/toggle-group-control";
import { getStyleSourceColor } from "../../shared/style-info";
@@ -114,12 +114,7 @@ export const Section = ({
deleteProperty,
}: SectionProps) => {
return (
-
+
@@ -190,6 +185,6 @@ export const Section = ({
deleteProperty={deleteProperty}
/>
-
+
);
};
diff --git a/apps/builder/app/builder/features/style-panel/sections/space/space.tsx b/apps/builder/app/builder/features/style-panel/sections/space/space.tsx
index 006582325689..6b1dc348c3a5 100644
--- a/apps/builder/app/builder/features/style-panel/sections/space/space.tsx
+++ b/apps/builder/app/builder/features/style-panel/sections/space/space.tsx
@@ -8,7 +8,7 @@ import type { SpaceStyleProperty, HoverTarget } from "./types";
import { InputPopover } from "../shared/input-popover";
import { SpaceTooltip } from "./tooltip";
import { getStyleSource } from "../../shared/style-info";
-import { CollapsibleSection } from "../../shared/collapsible-section";
+import { StyleSection } from "../../shared/style-section";
import { movementMapSpace, useKeyboardNavigation } from "../shared/keyboard";
import type { CreateBatchUpdate } from "../../shared/use-style-data";
@@ -133,11 +133,7 @@ export const Section = ({
};
return (
-
+
{
@@ -172,6 +168,6 @@ export const Section = ({
/>
)}
/>
-
+
);
};
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 7af32e5c8a35..1b502a970687 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,20 +1,12 @@
-import { CollapsibleSectionRoot } from "~/builder/shared/collapsible-section";
import type { SectionProps } from "../shared/section";
import type { LayersValue, StyleProperty } from "@webstudio-is/css-engine";
-import { useState } from "react";
-import {
- SectionTitle,
- SectionTitleButton,
- Tooltip,
- Text,
-} from "@webstudio-is/design-system";
-import { InfoCircleIcon, PlusIcon } from "@webstudio-is/icons";
+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 { getDots } from "../../shared/collapsible-section";
+import { RepeatedStyleSection } from "../../shared/style-section";
import { LayersList } from "../../style-layers-list";
import { ShadowContent } from "../../shared/shadow-content";
-import { PropertySectionLabel } from "../../property-label";
export const properties = ["textShadow"] satisfies [
StyleProperty,
@@ -27,40 +19,21 @@ const initialTextShadow = "0px 2px 5px rgba(0, 0, 0, 0.2)";
export const Section = (props: SectionProps) => {
const { currentStyle, createBatchUpdate, deleteProperty } = props;
- const [isOpen, setIsOpen] = useState(true);
const value = currentStyle[property]?.value;
return (
- }
- onClick={() => {
- addLayer(
- property,
- parseCssValue(property, initialTextShadow) as LayersValue,
- currentStyle,
- createBatchUpdate
- );
- setIsOpen(true);
- }}
- />
- }
- >
-
-
- }
+ description="Adds shadow effects around a text."
+ properties={properties}
+ onAdd={() => {
+ addLayer(
+ property,
+ parseCssValue(property, initialTextShadow) as LayersValue,
+ currentStyle,
+ createBatchUpdate
+ );
+ }}
>
{value?.type === "layers" && value.value.length > 0 && (
{
}}
/>
)}
-
+
);
};
diff --git a/apps/builder/app/builder/features/style-panel/sections/transforms/transforms.tsx b/apps/builder/app/builder/features/style-panel/sections/transforms/transforms.tsx
index 7a2123d06343..959318bde542 100644
--- a/apps/builder/app/builder/features/style-panel/sections/transforms/transforms.tsx
+++ b/apps/builder/app/builder/features/style-panel/sections/transforms/transforms.tsx
@@ -40,10 +40,11 @@ import { SkewPanelContent } from "./transform-skew";
import { BackfaceVisibility } from "./transform-backface-visibility";
import { TransformPerspective } from "./transform-perspective";
import { humanizeString } from "~/shared/string-utils";
-import { getDots } from "../../shared/collapsible-section";
+import { getDots } from "../../shared/style-section";
import { TransformAndPerspectiveOrigin } from "./transform-and-perspective-origin";
import { PropertySectionLabel } from "../../property-label";
import { propertyDescriptions } from "@webstudio-is/css-data";
+import { useComputedStyles } from "../../shared/model";
export const transformPanels = [
"translate",
@@ -94,6 +95,7 @@ export const Section = (props: SectionProps) => {
panel: "perspective",
});
+ const styles = useComputedStyles(properties);
return (
{
onOpenChange={setIsOpen}
trigger={
diff --git a/apps/builder/app/builder/features/style-panel/sections/transitions/transitions.tsx b/apps/builder/app/builder/features/style-panel/sections/transitions/transitions.tsx
index 2246136fa5fa..5f193cf6d704 100644
--- a/apps/builder/app/builder/features/style-panel/sections/transitions/transitions.tsx
+++ b/apps/builder/app/builder/features/style-panel/sections/transitions/transitions.tsx
@@ -12,7 +12,7 @@ import {
} from "@webstudio-is/css-data";
import { CollapsibleSectionRoot } from "~/builder/shared/collapsible-section";
import type { SectionProps } from "../shared/section";
-import { getDots } from "../../shared/collapsible-section";
+import { getDots } from "../../shared/style-section";
import { $selectedOrLastStyleSourceSelector } from "~/shared/nano-states";
import { TransitionContent } from "./transition-content";
import {
@@ -25,6 +25,7 @@ import { RepeatedStyle } from "../../shared/repeated-style";
import type { StyleInfo } from "../../shared/style-info";
import { repeatUntil } from "~/shared/array-utils";
import { PropertySectionLabel } from "../../property-label";
+import { useComputedStyles } from "../../shared/model";
export { transitionLongHandProperties as properties };
@@ -94,6 +95,7 @@ export const Section = (props: SectionProps) => {
const isStyleInLocalState =
selectedOrLastStyleSourceSelector &&
selectedOrLastStyleSourceSelector.state === undefined;
+ const styles = useComputedStyles(transitionLongHandProperties);
return (
{
onOpenChange={setIsOpen}
trigger={
{
disabled={isStyleInLocalState === false}
prefix={}
onClick={() => {
+ setIsOpen(true);
const batch = createBatchUpdate();
for (const property of transitionLongHandProperties) {
batch.setProperty(property)({
diff --git a/apps/builder/app/builder/features/style-panel/sections/typography/typography.tsx b/apps/builder/app/builder/features/style-panel/sections/typography/typography.tsx
index ad8b5d07ef11..4f3dc8b3c199 100644
--- a/apps/builder/app/builder/features/style-panel/sections/typography/typography.tsx
+++ b/apps/builder/app/builder/features/style-panel/sections/typography/typography.tsx
@@ -37,7 +37,7 @@ import {
import { ToggleGroupControl } from "../../controls/toggle-group/toggle-group-control";
import { FloatingPanel } from "~/builder/shared/floating-panel";
import { getStyleSourceColor, type StyleInfo } from "../../shared/style-info";
-import { CollapsibleSection } from "../../shared/collapsible-section";
+import { StyleSection } from "../../shared/style-section";
import { PropertyLabel } from "../../property-label";
export const properties = [
@@ -61,17 +61,13 @@ export const properties = [
export const Section = (props: SectionProps) => {
return (
-
+
-
+
);
};
diff --git a/apps/builder/app/builder/features/style-panel/shared/collapsible-section.tsx b/apps/builder/app/builder/features/style-panel/shared/collapsible-section.tsx
deleted file mode 100644
index d269a672c903..000000000000
--- a/apps/builder/app/builder/features/style-panel/shared/collapsible-section.tsx
+++ /dev/null
@@ -1,82 +0,0 @@
-import type { StyleProperty } from "@webstudio-is/css-engine";
-import {
- SectionTitle,
- SectionTitleButton,
- SectionTitleLabel,
-} from "@webstudio-is/design-system";
-import type { ReactNode } from "react";
-import {
- CollapsibleSectionRoot,
- useOpenState,
-} from "~/builder/shared/collapsible-section";
-import { getStyleSource, type StyleInfo } from "./style-info";
-import { PlusIcon } from "@webstudio-is/icons";
-
-export const getDots = (
- currentStyle: StyleInfo,
- properties: ReadonlyArray
-) => {
- const dots = new Set<"local" | "overwritten" | "remote">();
-
- for (const property of properties) {
- const style = currentStyle[property];
-
- // Unparsed values are not editable directly in the section, so we don't show the dot
- if (
- style?.value.type === "unparsed" ||
- style?.value.type === "guaranteedInvalid"
- ) {
- return;
- }
-
- const source = getStyleSource(style);
- if (source === "local" || source === "overwritten" || source === "remote") {
- dots.add(source);
- }
- }
-
- return Array.from(dots);
-};
-
-export const CollapsibleSection = (props: {
- label: string;
- children: ReactNode;
- currentStyle: StyleInfo;
- properties: ReadonlyArray;
- fullWidth?: boolean;
- onAdd?: () => void;
-}) => {
- const { label, children, currentStyle, properties, fullWidth, onAdd } = props;
- const [isOpen, setIsOpen] = useOpenState(props);
-
- return (
- }
- onClick={() => {
- if (isOpen === false) {
- setIsOpen(true);
- }
- onAdd();
- }}
- />
- )
- }
- >
- {label}
-
- }
- fullWidth={fullWidth}
- >
- {children}
-
- );
-};
diff --git a/apps/builder/app/builder/features/style-panel/shared/style-section.tsx b/apps/builder/app/builder/features/style-panel/shared/style-section.tsx
new file mode 100644
index 000000000000..f192a4650899
--- /dev/null
+++ b/apps/builder/app/builder/features/style-panel/shared/style-section.tsx
@@ -0,0 +1,105 @@
+import type { StyleProperty } from "@webstudio-is/css-engine";
+import {
+ SectionTitle,
+ SectionTitleButton,
+ SectionTitleLabel,
+} from "@webstudio-is/design-system";
+import type { ReactNode } from "react";
+import {
+ CollapsibleSectionRoot,
+ useOpenState,
+} from "~/builder/shared/collapsible-section";
+import { PlusIcon } from "@webstudio-is/icons";
+import { useComputedStyles } from "./model";
+import type { ComputedStyleDecl } from "~/shared/style-object-model";
+import { PropertySectionLabel } from "../property-label";
+
+export const getDots = (styles: ComputedStyleDecl[]) => {
+ const dots = new Set<"local" | "overwritten" | "remote">();
+
+ for (const styleDecl of styles) {
+ // Unparsed values are not editable directly in the section, so we don't show the dot
+ if (
+ styleDecl.usedValue.type === "unparsed" ||
+ styleDecl.usedValue.type === "guaranteedInvalid"
+ ) {
+ return;
+ }
+
+ const source = styleDecl.source.name;
+ if (source === "local" || source === "overwritten" || source === "remote") {
+ dots.add(source);
+ }
+ }
+
+ return Array.from(dots);
+};
+
+export const StyleSection = (props: {
+ label: string;
+ properties: StyleProperty[];
+ // @todo remove to keep sections consistent
+ fullWidth?: boolean;
+ children: ReactNode;
+}) => {
+ const { label, children, properties, fullWidth } = props;
+ const [isOpen, setIsOpen] = useOpenState(props);
+ const styles = useComputedStyles(properties);
+ return (
+
+ {label}
+
+ }
+ fullWidth={fullWidth}
+ >
+ {children}
+
+ );
+};
+
+export const RepeatedStyleSection = (props: {
+ label: string;
+ description: string;
+ properties: [StyleProperty, ...StyleProperty[]];
+ onAdd: () => void;
+ children: ReactNode;
+}) => {
+ const { label, description, children, properties, onAdd } = props;
+ const [isOpen, setIsOpen] = useOpenState(props);
+ const styles = useComputedStyles(properties);
+ return (
+ }
+ onClick={() => {
+ setIsOpen(true);
+ onAdd();
+ }}
+ />
+ }
+ >
+
+
+ }
+ >
+ {children}
+
+ );
+};