experimental: migrate style section to style object model (#4065)

Ref https://github.com/webstudio-is/webstudio/issues/1536
https://github.com/webstudio-is/webstudio/issues/3399

Power style section and its colorful dots with new style engine.

Can be tested

- size section
- background section
- transforms section
- advanced section
This commit is contained in:
Bogdan Chadkin authored and GitHub committed 2024-09-05 01:12:32 +02:00
1 parent ca62a9837e
commit e381a70580
19 files changed
+273 -402

No files matched your search

@@ -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 (
<CollapsibleSectionRoot
label={label}
isOpen={isOpen}
onOpenChange={setIsOpen}
trigger={
<SectionTitle
dots={getDots(styles)}
suffix={
<SectionTitleButton
prefix={<PlusIcon />}
onClick={() => {
setIsOpen(true);
onAdd();
}}
/>
}
>
<SectionTitleLabel>{label}</SectionTitleLabel>
</SectionTitle>
}
>
{children}
</CollapsibleSectionRoot>
);
};
export const Section = ({
currentStyle,
setProperty,
@@ -97,13 +146,10 @@ export const Section = ({
};
return (
<CollapsibleSection
<AdvancedStyleSection
label="Advanced"
currentStyle={currentStyle}
properties={propertyNames}
onAdd={() => {
setAddingProp("");
}}
onAdd={() => setAddingProp("")}
>
{addingProp !== undefined && (
<Add
@@ -171,6 +217,6 @@ export const Section = ({
);
})}
</Box>
</CollapsibleSection>
</AdvancedStyleSection>
);
};
@@ -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 (
<CollapsibleSectionRoot
fullWidth
<RepeatedStyleSection
label={label}
isOpen={isOpen}
onOpenChange={setIsOpen}
trigger={
<SectionTitle
dots={getDots(currentStyle, properties)}
suffix={
<Tooltip content={"Add a backdrop-filter"}>
<SectionTitleButton
prefix={<PlusIcon />}
onClick={() => {
addLayer(
property,
parseCssValue(
property,
initialBackdropFilter
) as LayersValue,
currentStyle,
props.createBatchUpdate
);
setIsOpen(true);
}}
/>
</Tooltip>
}
>
<PropertySectionLabel
label={label}
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}
/>
</SectionTitle>
}
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 && (
<LayersList
@@ -109,6 +76,6 @@ export const Section = (props: SectionProps) => {
}}
/>
)}
</CollapsibleSectionRoot>
</RepeatedStyleSection>
);
};
@@ -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<StyleProperty>;
const BackgroundsCollapsibleSection = ({
children,
currentStyle,
createBatchUpdate,
}: SectionProps & { children: React.ReactNode }) => {
const label = "Backgrounds";
const [isOpen, setIsOpen] = useOpenState({ label });
return (
<CollapsibleSectionRoot
label={label}
fullWidth
isOpen={isOpen}
onOpenChange={(nextIsOpen) => {
setIsOpen(nextIsOpen);
}}
trigger={
<SectionTitle
dots={getDots(currentStyle, properties)}
suffix={
<SectionTitleButton
prefix={<PlusIcon />}
onClick={() => {
addLayer(currentStyle, createBatchUpdate);
setIsOpen(true);
}}
/>
}
>
<PropertySectionLabel
label="Backgrounds"
description="Add one or more backgrounds to the instance such as a color, image, or gradient."
properties={layeredBackgroundProps}
/>
</SectionTitle>
}
>
{children}
</CollapsibleSectionRoot>
);
};
export const Section = (props: SectionProps) => {
const { setProperty, deleteProperty, currentStyle, createBatchUpdate } =
props;
@@ -213,11 +164,13 @@ export const Section = (props: SectionProps) => {
});
return (
<BackgroundsCollapsibleSection
setProperty={setProperty}
deleteProperty={deleteProperty}
createBatchUpdate={createBatchUpdate}
currentStyle={currentStyle}
<RepeatedStyleSection
label="Backgrounds"
description="Add one or more backgrounds to the instance such as a color, image, or gradient."
properties={layeredBackgroundProps}
onAdd={() => {
addLayer(currentStyle, createBatchUpdate);
}}
>
<Flex gap={1} direction="column">
<CssValueListArrowFocus dragItemId={dragItemId}>
@@ -270,6 +223,6 @@ export const Section = (props: SectionProps) => {
<ColorControl property="backgroundColor" />
</Grid>
</Flex>
</BackgroundsCollapsibleSection>
</RepeatedStyleSection>
);
};
@@ -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 (
<CollapsibleSection
label="Borders"
currentStyle={props.currentStyle}
properties={properties}
>
<StyleSection label="Borders" properties={properties}>
<Flex direction="column" gap={2}>
<BorderStyle />
<BorderColor />
<BorderWidth {...props} />
<BorderRadius {...props} />
</Flex>
</CollapsibleSection>
</StyleSection>
);
};
@@ -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 (
<CollapsibleSectionRoot
fullWidth
<RepeatedStyleSection
label={label}
isOpen={isOpen}
onOpenChange={setIsOpen}
trigger={
<SectionTitle
dots={getDots(currentStyle, properties)}
suffix={
<SectionTitleButton
prefix={<PlusIcon />}
onClick={() => {
addLayer(
property,
parseCssValue(property, initialBoxShadow) as LayersValue,
currentStyle,
props.createBatchUpdate
);
setIsOpen(true);
}}
/>
}
>
<PropertySectionLabel
label={label}
description="Adds shadow effects around an element's frame."
properties={properties}
/>
</SectionTitle>
}
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 && (
<LayersList
@@ -99,6 +72,6 @@ export const Section = (props: SectionProps) => {
}}
/>
)}
</CollapsibleSectionRoot>
</RepeatedStyleSection>
);
};
@@ -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 (
<CollapsibleSectionRoot
fullWidth
<RepeatedStyleSection
label={label}
isOpen={isOpen}
onOpenChange={setIsOpen}
trigger={
<SectionTitle
dots={getDots(currentStyle, properties)}
suffix={
<Tooltip content={"Add a filter"}>
<SectionTitleButton
prefix={<PlusIcon />}
onClick={() => {
addLayer(
property,
parseCssValue(property, initialFilter) as LayersValue,
currentStyle,
props.createBatchUpdate
);
setIsOpen(true);
}}
/>
</Tooltip>
}
>
<PropertySectionLabel
label={label}
description="Filter effects allow you to apply graphical effects like blurring, color shifting, and more to elements."
properties={properties}
/>
</SectionTitle>
}
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 && (
<LayersList
@@ -106,6 +76,6 @@ export const Section = (props: SectionProps) => {
}}
/>
)}
</CollapsibleSectionRoot>
</RepeatedStyleSection>
);
};
@@ -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 (
<CollapsibleSection
label="Flex Child"
currentStyle={props.currentStyle}
properties={properties}
>
<StyleSection label="Flex Child" properties={properties}>
<Flex css={{ flexDirection: "column", gap: theme.spacing[5] }}>
<FlexChildSectionAlign />
<FlexChildSectionSizing />
<FlexChildSectionOrder />
</Flex>
</CollapsibleSection>
</StyleSection>
);
};
@@ -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 (
<CollapsibleSection
label="Layout"
currentStyle={currentStyle}
properties={properties}
>
<StyleSection label="Layout" properties={properties}>
<Flex direction="column" gap="2">
<Grid
css={{
@@ -523,6 +519,6 @@ export const Section = ({ currentStyle, createBatchUpdate }: SectionProps) => {
/>
)}
</Flex>
</CollapsibleSection>
</StyleSection>
);
};
@@ -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<StyleProperty>;
export const Section = ({ currentStyle: style }: SectionProps) => {
export const Section = () => {
return (
<CollapsibleSection
label="List Item"
currentStyle={style}
properties={properties}
>
<StyleSection label="List Item" properties={properties}>
<Grid gap={2} css={{ gridTemplateColumns: `1fr ${theme.spacing[21]}` }}>
<PropertyLabel
label="List Style Type"
@@ -23,6 +18,6 @@ export const Section = ({ currentStyle: style }: SectionProps) => {
/>
<SelectControl property="listStyleType" />
</Grid>
</CollapsibleSection>
</StyleSection>
);
};
@@ -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 (
<CollapsibleSection
label="Outline"
currentStyle={currentStyle}
properties={properties}
>
<StyleSection label="Outline" properties={properties}>
<Flex direction="column" gap={2}>
<OutlineStyle />
{outlineStyle.value.value !== "none" && (
@@ -64,6 +60,6 @@ export const Section = (props: SectionProps) => {
</>
)}
</Flex>
</CollapsibleSection>
</StyleSection>
);
};
@@ -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 (
<CollapsibleSection
label="Position"
currentStyle={currentStyle}
properties={properties}
>
<StyleSection label="Position" properties={properties}>
<Grid gap={2}>
<Grid
gap={2}
@@ -102,6 +98,6 @@ export const Section = ({
</Grid>
)}
</Grid>
</CollapsibleSection>
</StyleSection>
);
};
@@ -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 (
<CollapsibleSection
label="Size"
currentStyle={currentStyle}
properties={properties}
fullWidth
>
<StyleSection label="Size" properties={properties} fullWidth>
<SectionLayout columns={2}>
<SizeProperty property="width" />
<SizeProperty property="height" />
@@ -190,6 +185,6 @@ export const Section = ({
deleteProperty={deleteProperty}
/>
</SectionLayout>
</CollapsibleSection>
</StyleSection>
);
};
@@ -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 (
<CollapsibleSection
label="Space"
currentStyle={currentStyle}
properties={spaceProperties}
>
<StyleSection label="Space" properties={spaceProperties}>
<SpaceLayout
ref={layoutRef}
onClick={(event) => {
@@ -172,6 +168,6 @@ export const Section = ({
/>
)}
/>
</CollapsibleSection>
</StyleSection>
);
};
@@ -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 (
<CollapsibleSectionRoot
fullWidth
<RepeatedStyleSection
label={label}
isOpen={isOpen}
onOpenChange={setIsOpen}
trigger={
<SectionTitle
dots={getDots(currentStyle, properties)}
suffix={
<SectionTitleButton
prefix={<PlusIcon />}
onClick={() => {
addLayer(
property,
parseCssValue(property, initialTextShadow) as LayersValue,
currentStyle,
createBatchUpdate
);
setIsOpen(true);
}}
/>
}
>
<PropertySectionLabel
label={label}
description="Adds shadow effects around a text."
properties={properties}
/>
</SectionTitle>
}
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 && (
<LayersList
@@ -99,6 +72,6 @@ export const Section = (props: SectionProps) => {
}}
/>
)}
</CollapsibleSectionRoot>
</RepeatedStyleSection>
);
};
@@ -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 (
<CollapsibleSectionRoot
fullWidth
@@ -102,7 +104,7 @@ export const Section = (props: SectionProps) => {
onOpenChange={setIsOpen}
trigger={
<SectionTitle
dots={getDots(currentStyle, properties)}
dots={getDots(styles)}
suffix={
<DropdownMenu>
<DropdownMenuTrigger asChild>
@@ -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 (
<CollapsibleSectionRoot
@@ -103,7 +105,7 @@ export const Section = (props: SectionProps) => {
onOpenChange={setIsOpen}
trigger={
<SectionTitle
dots={getDots(currentStyle, transitionLongHandProperties)}
dots={getDots(styles)}
suffix={
<Tooltip
content={
@@ -116,6 +118,7 @@ export const Section = (props: SectionProps) => {
disabled={isStyleInLocalState === false}
prefix={<PlusIcon />}
onClick={() => {
setIsOpen(true);
const batch = createBatchUpdate();
for (const property of transitionLongHandProperties) {
batch.setProperty(property)({
@@ -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 (
<CollapsibleSection
label="Typography"
currentStyle={props.currentStyle}
properties={properties}
>
<StyleSection label="Typography" properties={properties}>
<Flex gap="2" direction="column">
<TypographySectionFont {...props} />
<TypographySectionSizing />
<TypographySectionAdvanced {...props} />
</Flex>
</CollapsibleSection>
</StyleSection>
);
};
@@ -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<StyleProperty>
) => {
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<StyleProperty>;
fullWidth?: boolean;
onAdd?: () => void;
}) => {
const { label, children, currentStyle, properties, fullWidth, onAdd } = props;
const [isOpen, setIsOpen] = useOpenState(props);
return (
<CollapsibleSectionRoot
label={label}
isOpen={isOpen}
onOpenChange={setIsOpen}
trigger={
<SectionTitle
dots={getDots(currentStyle, properties)}
suffix={
onAdd && (
<SectionTitleButton
prefix={<PlusIcon />}
onClick={() => {
if (isOpen === false) {
setIsOpen(true);
}
onAdd();
}}
/>
)
}
>
<SectionTitleLabel>{label}</SectionTitleLabel>
</SectionTitle>
}
fullWidth={fullWidth}
>
{children}
</CollapsibleSectionRoot>
);
};
@@ -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 (
<CollapsibleSectionRoot
label={label}
isOpen={isOpen}
onOpenChange={setIsOpen}
trigger={
<SectionTitle dots={getDots(styles)}>
<SectionTitleLabel>{label}</SectionTitleLabel>
</SectionTitle>
}
fullWidth={fullWidth}
>
{children}
</CollapsibleSectionRoot>
);
};
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 (
<CollapsibleSectionRoot
fullWidth
label={label}
isOpen={isOpen}
onOpenChange={setIsOpen}
trigger={
<SectionTitle
dots={getDots(styles)}
suffix={
<SectionTitleButton
prefix={<PlusIcon />}
onClick={() => {
setIsOpen(true);
onAdd();
}}
/>
}
>
<PropertySectionLabel
label={label}
description={description}
properties={properties}
/>
</SectionTitle>
}
>
{children}
</CollapsibleSectionRoot>
);
};