mirror of
https://github.com/webstudio-is/webstudio.git
synced 2026-11-09 05:26:24 +09:00
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:
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>
|
||||
);
|
||||
};
|
||||
+15
-48
@@ -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>
|
||||
);
|
||||
};
|
||||
+15
-62
@@ -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>
|
||||
);
|
||||
};
|
||||
+15
-42
@@ -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>
|
||||
);
|
||||
};
|
||||
+15
-42
@@ -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>
|
||||
);
|
||||
};
|
||||
Reference in new issue
Block a user