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} + + ); +};