diff --git a/apps/builder/app/builder/features/style-panel/sections/borders/border-style.tsx b/apps/builder/app/builder/features/style-panel/sections/borders/border-style.tsx index b647b0a525..699080d3a5 100644 --- a/apps/builder/app/builder/features/style-panel/sections/borders/border-style.tsx +++ b/apps/builder/app/builder/features/style-panel/sections/borders/border-style.tsx @@ -1,13 +1,36 @@ import type { StyleProperty } from "@webstudio-is/css-data"; +import { toValue } from "@webstudio-is/css-engine"; +import { + Grid, + theme, + ToggleGroup, + ToggleGroupItem, + Tooltip, +} from "@webstudio-is/design-system"; +import { + DashBorderIcon, + DashedBorderIcon, + DottedBorderIcon, + SmallXIcon, +} from "@webstudio-is/icons"; +import { toPascalCase } from "../../shared/keyword-utils"; +import { PropertyName } from "../../shared/property-name"; import type { RenderCategoryProps } from "../../style-sections"; -import { BorderProperty } from "./border-property"; +import { deleteAllProperties, setAllProperties } from "./border-utils"; -const borderPropertyOptions = { - borderTopStyle: {}, - borderRightStyle: {}, - borderLeftStyle: {}, - borderBottomStyle: {}, -} as const satisfies Partial<{ [property in StyleProperty]: unknown }>; +const borderStyleProperties = [ + "borderTopStyle", + "borderRightStyle", + "borderLeftStyle", + "borderBottomStyle", +] as const satisfies readonly StyleProperty[]; + +const borderStyleValues = [ + { value: "none", Icon: SmallXIcon }, + { value: "solid", Icon: DashBorderIcon }, + { value: "dashed", Icon: DashedBorderIcon }, + { value: "dotted", Icon: DottedBorderIcon }, +] as const; export const BorderStyle = ( props: Pick< @@ -15,14 +38,66 @@ export const BorderStyle = ( "currentStyle" | "setProperty" | "deleteProperty" | "createBatchUpdate" > ) => { + /** + * We do not use shorthand properties such as borderWidth or borderRadius in our code. + * However, in the UI, we can display a single field, and in that case, we can use any property + * from the shorthand property set and pass it instead. + **/ + const firstPropertyName = borderStyleProperties[0]; + + const deleteBorderProperties = deleteAllProperties( + borderStyleProperties, + props.createBatchUpdate + ); + + const setBorderProperties = setAllProperties( + borderStyleProperties, + props.createBatchUpdate + )(firstPropertyName); + + const firstPropertyValue = toValue( + props.currentStyle[firstPropertyName]?.value ?? { + type: "keyword", + value: "none", + } + ); + return ( - + + deleteBorderProperties(firstPropertyName)} + /> + + { + setBorderProperties({ + type: "keyword", + value, + }); + }} + > + {borderStyleValues.map(({ value, Icon }) => ( + + + + + + ))} + + ); }; diff --git a/apps/builder/app/builder/features/style-panel/sections/borders/borders.stories.tsx b/apps/builder/app/builder/features/style-panel/sections/borders/borders.stories.tsx index 7bf9b10c33..9064991066 100644 --- a/apps/builder/app/builder/features/style-panel/sections/borders/borders.stories.tsx +++ b/apps/builder/app/builder/features/style-panel/sections/borders/borders.stories.tsx @@ -20,7 +20,6 @@ const styleInfoInitial: StyleInfo = { const Panel = styled("div", { width: theme.spacing[30], boxSizing: "border-box", - padding: theme.spacing[9], }); export const Borders = () => { 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 3f5c579fc0..1a2ccc8528 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 @@ -42,6 +42,13 @@ export const BordersSection = (props: RenderCategoryProps) => { return ( + + { - - ; }; diff --git a/packages/icons/icons/dash-border.svg b/packages/icons/icons/dash-border.svg new file mode 100644 index 0000000000..3800a43236 --- /dev/null +++ b/packages/icons/icons/dash-border.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/icons/icons/dashed-border.svg b/packages/icons/icons/dashed-border.svg new file mode 100644 index 0000000000..b8713a3b1e --- /dev/null +++ b/packages/icons/icons/dashed-border.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/packages/icons/icons/dotted-border.svg b/packages/icons/icons/dotted-border.svg new file mode 100644 index 0000000000..b72136a3c8 --- /dev/null +++ b/packages/icons/icons/dotted-border.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/packages/icons/icons/small-x.svg b/packages/icons/icons/small-x.svg new file mode 100644 index 0000000000..83438b01cc --- /dev/null +++ b/packages/icons/icons/small-x.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/icons/src/__generated__/dash-border.tsx b/packages/icons/src/__generated__/dash-border.tsx new file mode 100644 index 0000000000..290295d1ab --- /dev/null +++ b/packages/icons/src/__generated__/dash-border.tsx @@ -0,0 +1,15 @@ +// Generated from icons/dash-border.svg + +import { forwardRef } from "react"; +import type { IconProps } from "../types"; + +// prettier-ignore +export const DashBorderIcon = forwardRef( + ({ color = "currentColor", size = 16, ...props }, forwardedRef) => { + return ( + + ); + } +); + +DashBorderIcon.displayName = "DashBorderIcon"; diff --git a/packages/icons/src/__generated__/dashed-border.tsx b/packages/icons/src/__generated__/dashed-border.tsx new file mode 100644 index 0000000000..bf1cf29f99 --- /dev/null +++ b/packages/icons/src/__generated__/dashed-border.tsx @@ -0,0 +1,15 @@ +// Generated from icons/dashed-border.svg + +import { forwardRef } from "react"; +import type { IconProps } from "../types"; + +// prettier-ignore +export const DashedBorderIcon = forwardRef( + ({ color = "currentColor", size = 16, ...props }, forwardedRef) => { + return ( + + ); + } +); + +DashedBorderIcon.displayName = "DashedBorderIcon"; diff --git a/packages/icons/src/__generated__/dotted-border.tsx b/packages/icons/src/__generated__/dotted-border.tsx new file mode 100644 index 0000000000..06dfe81616 --- /dev/null +++ b/packages/icons/src/__generated__/dotted-border.tsx @@ -0,0 +1,15 @@ +// Generated from icons/dotted-border.svg + +import { forwardRef } from "react"; +import type { IconProps } from "../types"; + +// prettier-ignore +export const DottedBorderIcon = forwardRef( + ({ color = "currentColor", size = 16, ...props }, forwardedRef) => { + return ( + + ); + } +); + +DottedBorderIcon.displayName = "DottedBorderIcon"; diff --git a/packages/icons/src/__generated__/index.ts b/packages/icons/src/__generated__/index.ts index 328975102a..621859fd7b 100644 --- a/packages/icons/src/__generated__/index.ts +++ b/packages/icons/src/__generated__/index.ts @@ -27,9 +27,12 @@ export * from "./chevron-filled-right"; export * from "./chevron-filled-up"; export * from "./code"; export * from "./commit"; +export * from "./dash-border"; export * from "./dash"; +export * from "./dashed-border"; export * from "./div"; export * from "./dot"; +export * from "./dotted-border"; export * from "./drag-handle"; export * from "./eyecon-closed"; export * from "./eyecon-open"; @@ -51,6 +54,7 @@ export * from "./repeat-grid"; export * from "./repeat-row"; export * from "./scroll"; export * from "./slot-component"; +export * from "./small-x"; export * from "./subscript"; export * from "./subtract"; export * from "./superscript"; diff --git a/packages/icons/src/__generated__/small-x.tsx b/packages/icons/src/__generated__/small-x.tsx new file mode 100644 index 0000000000..47e07dcac3 --- /dev/null +++ b/packages/icons/src/__generated__/small-x.tsx @@ -0,0 +1,15 @@ +// Generated from icons/small-x.svg + +import { forwardRef } from "react"; +import type { IconProps } from "../types"; + +// prettier-ignore +export const SmallXIcon = forwardRef( + ({ color = "currentColor", size = 16, ...props }, forwardedRef) => { + return ( + + ); + } +); + +SmallXIcon.displayName = "SmallXIcon";