-
Notifications
You must be signed in to change notification settings - Fork 708
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add transform section under style-panel with ui controls (#3718)
## Description Adds the primary `translate`, `scale`, `rotate`, skew` properties under transform section. Related to #3411 ## Steps for reproduction - Add multiple properties under the transform section. - Update values of each property from the UI. - Hide/Delete each individual property ## Todo - [x] Need to discuss if the `isExperiemental` flag need to be removed before merging the branch. ## Code Review - [x] hi @kof, I need you to do - conceptual review (architecture, feature-correctness) - detailed review (read every line) - test it on preview ## Before requesting a review - [x] made a self-review - [x] added inline comments where things may be not obvious (the "why", not "what") ## Before merging - [x] tested locally and on preview environment (preview dev login: 5de6) - [x] added tests - [ ] if any new env variables are added, added them to `.env` file --------- Co-authored-by: Oleg Isonen <[email protected]>
- Loading branch information
1 parent
31bdec9
commit 5b46f79
Showing
17 changed files
with
1,650 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
135 changes: 135 additions & 0 deletions
135
apps/builder/app/builder/features/style-panel/sections/transforms/transform-rotate.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
import { Flex, Grid, Label } from "@webstudio-is/design-system"; | ||
import { | ||
updateRotateOrSkewPropertyValue, | ||
type TransformPanelProps, | ||
} from "./transform-utils"; | ||
import { | ||
XAxisRotateIcon, | ||
YAxisRotateIcon, | ||
ZAxisRotateIcon, | ||
} from "@webstudio-is/icons"; | ||
import { CssValueInputContainer } from "../../shared/css-value-input"; | ||
import { | ||
toValue, | ||
UnitValue, | ||
type FunctionValue, | ||
type StyleValue, | ||
} from "@webstudio-is/css-engine"; | ||
import type { StyleUpdateOptions } from "../../shared/use-style-data"; | ||
import { parseCssValue } from "@webstudio-is/css-data"; | ||
import { extractRotatePropertiesFromTransform } from "./transform-utils"; | ||
|
||
export const RotatePanelContent = (props: TransformPanelProps) => { | ||
const { propertyValue, setProperty, currentStyle } = props; | ||
const { rotateX, rotateY, rotateZ } = | ||
extractRotatePropertiesFromTransform(propertyValue); | ||
|
||
const handlePropertyUpdate = ( | ||
index: number, | ||
prop: string, | ||
value: StyleValue, | ||
options?: StyleUpdateOptions | ||
) => { | ||
let newValue: UnitValue = { type: "unit", value: 0, unit: "deg" }; | ||
|
||
if (value.type === "unit") { | ||
newValue = value; | ||
} | ||
|
||
if (value.type === "tuple" && value.value[0].type === "unit") { | ||
newValue = value.value[0]; | ||
} | ||
|
||
const newFunctionValue: FunctionValue = { | ||
type: "function", | ||
name: prop, | ||
args: { type: "layers", value: [newValue] }, | ||
}; | ||
|
||
const newPropertyValue = updateRotateOrSkewPropertyValue({ | ||
panel: "rotate", | ||
index, | ||
currentStyle, | ||
value: newFunctionValue, | ||
propertyValue, | ||
}); | ||
|
||
const rotate = parseCssValue("transform", toValue(newPropertyValue)); | ||
if (rotate.type === "invalid") { | ||
return; | ||
} | ||
|
||
setProperty("transform")(rotate, options); | ||
}; | ||
|
||
return ( | ||
<Flex direction="column" gap={2}> | ||
<Grid | ||
gap={1} | ||
css={{ alignItems: "center", gridTemplateColumns: "auto 1fr 1fr" }} | ||
> | ||
<XAxisRotateIcon /> | ||
<Label> Rotate X</Label> | ||
<CssValueInputContainer | ||
key="rotateX" | ||
styleSource="local" | ||
property="rotate" | ||
value={ | ||
rotateX?.type === "function" && rotateX.args.type === "layers" | ||
? rotateX.args.value[0] | ||
: { type: "unit", value: 0, unit: "deg" } | ||
} | ||
keywords={[]} | ||
setValue={(value, options) => { | ||
handlePropertyUpdate(0, "rotateX", value, options); | ||
}} | ||
deleteProperty={() => {}} | ||
/> | ||
</Grid> | ||
<Grid | ||
gap={1} | ||
css={{ alignItems: "center", gridTemplateColumns: "auto 1fr 1fr" }} | ||
> | ||
<YAxisRotateIcon /> | ||
<Label> Rotate Y</Label> | ||
<CssValueInputContainer | ||
key="rotateY" | ||
styleSource="local" | ||
property="rotate" | ||
value={ | ||
rotateY?.type === "function" && rotateY.args.type === "layers" | ||
? rotateY.args.value[0] | ||
: { type: "unit", value: 0, unit: "deg" } | ||
} | ||
keywords={[]} | ||
setValue={(value, options) => { | ||
handlePropertyUpdate(1, "rotateY", value, options); | ||
}} | ||
deleteProperty={() => {}} | ||
/> | ||
</Grid> | ||
<Grid | ||
gap={1} | ||
css={{ alignItems: "center", gridTemplateColumns: "auto 1fr 1fr" }} | ||
> | ||
<ZAxisRotateIcon /> | ||
<Label> Rotate Z</Label> | ||
<CssValueInputContainer | ||
key="rotateZ" | ||
styleSource="local" | ||
property="rotate" | ||
value={ | ||
rotateZ?.type === "function" && rotateZ.args.type === "layers" | ||
? rotateZ.args.value[0] | ||
: { type: "unit", value: 0, unit: "deg" } | ||
} | ||
keywords={[]} | ||
setValue={(value, options) => { | ||
handlePropertyUpdate(2, "rotateZ", value, options); | ||
}} | ||
deleteProperty={() => {}} | ||
/> | ||
</Grid> | ||
</Flex> | ||
); | ||
}; |
109 changes: 109 additions & 0 deletions
109
apps/builder/app/builder/features/style-panel/sections/transforms/transform-scale.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
import { Flex, Grid, Label } from "@webstudio-is/design-system"; | ||
import { | ||
StyleValue, | ||
toValue, | ||
type StyleProperty, | ||
} from "@webstudio-is/css-engine"; | ||
import { CssValueInputContainer } from "../../shared/css-value-input"; | ||
import type { StyleUpdateOptions } from "../../shared/use-style-data"; | ||
import { | ||
updateTransformTuplePropertyValue, | ||
type TransformPanelProps, | ||
} from "./transform-utils"; | ||
import { XAxisIcon, YAxisIcon, ZAxisIcon } from "@webstudio-is/icons"; | ||
import { parseCssValue } from "@webstudio-is/css-data"; | ||
|
||
// We use fakeProperty to pass for the CssValueInputContainer. | ||
// As we know during parsing, the syntax for scale is wrong in the css-data package. | ||
// https://github.com/mdn/data/pull/746 | ||
// https://developer.mozilla.org/en-US/docs/Web/CSS/opacity#syntax | ||
// number | percentage | ||
const fakeProperty = "opacity"; | ||
const property: StyleProperty = "scale"; | ||
|
||
export const ScalePanelContent = (props: TransformPanelProps) => { | ||
const { propertyValue, setProperty } = props; | ||
const [scaleX, scaleY, scaleZ] = propertyValue.value; | ||
|
||
const handlePropertyUpdate = ( | ||
index: number, | ||
value: StyleValue, | ||
options?: StyleUpdateOptions | ||
) => { | ||
if (value.type !== "unit") { | ||
return; | ||
} | ||
|
||
const newValue = updateTransformTuplePropertyValue( | ||
index, | ||
value, | ||
propertyValue | ||
); | ||
|
||
const scale = parseCssValue(property, toValue(newValue)); | ||
if (scale.type === "invalid") { | ||
return; | ||
} | ||
|
||
setProperty(property)(scale, options); | ||
}; | ||
|
||
return ( | ||
<Flex direction="column" gap={2}> | ||
<Grid | ||
gap={1} | ||
css={{ alignItems: "center", gridTemplateColumns: "auto 1fr 1fr" }} | ||
> | ||
<XAxisIcon /> | ||
<Label> Scale X</Label> | ||
<CssValueInputContainer | ||
key="scaleX" | ||
styleSource="local" | ||
property={fakeProperty} | ||
value={scaleX} | ||
keywords={[]} | ||
setValue={(newValue, options) => { | ||
handlePropertyUpdate(0, newValue, options); | ||
}} | ||
deleteProperty={() => {}} | ||
/> | ||
</Grid> | ||
<Grid | ||
gap={1} | ||
css={{ alignItems: "center", gridTemplateColumns: "auto 1fr 1fr" }} | ||
> | ||
<YAxisIcon /> | ||
<Label> Scale Y</Label> | ||
<CssValueInputContainer | ||
key="scaleY" | ||
styleSource="local" | ||
property={fakeProperty} | ||
value={scaleY} | ||
keywords={[]} | ||
setValue={(newValue, options) => { | ||
handlePropertyUpdate(1, newValue, options); | ||
}} | ||
deleteProperty={() => {}} | ||
/> | ||
</Grid> | ||
<Grid | ||
gap={1} | ||
css={{ alignItems: "center", gridTemplateColumns: "auto 1fr 1fr" }} | ||
> | ||
<ZAxisIcon /> | ||
<Label> Scale Z</Label> | ||
<CssValueInputContainer | ||
key="scaleZ" | ||
styleSource="local" | ||
property={fakeProperty} | ||
value={scaleZ} | ||
keywords={[]} | ||
setValue={(newValue, options) => { | ||
handlePropertyUpdate(2, newValue, options); | ||
}} | ||
deleteProperty={() => {}} | ||
/> | ||
</Grid> | ||
</Flex> | ||
); | ||
}; |
113 changes: 113 additions & 0 deletions
113
apps/builder/app/builder/features/style-panel/sections/transforms/transform-skew.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
import { Flex, Label, Grid } from "@webstudio-is/design-system"; | ||
import { | ||
updateRotateOrSkewPropertyValue, | ||
extractSkewPropertiesFromTransform, | ||
type TransformPanelProps, | ||
} from "./transform-utils"; | ||
import { XAxisIcon, YAxisIcon } from "@webstudio-is/icons"; | ||
import { CssValueInputContainer } from "../../shared/css-value-input"; | ||
import type { StyleUpdateOptions } from "../../shared/use-style-data"; | ||
import { | ||
StyleValue, | ||
toValue, | ||
UnitValue, | ||
type FunctionValue, | ||
} from "@webstudio-is/css-engine"; | ||
import { parseCssValue } from "@webstudio-is/css-data"; | ||
|
||
// We use fakeProperty to pass for the CssValueInputContainer. | ||
// https://developer.mozilla.org/en-US/docs/Web/CSS/rotate#formal_syntax | ||
// angle | ||
const fakeProperty = "rotate"; | ||
|
||
export const SkewPanelContent = (props: TransformPanelProps) => { | ||
const { propertyValue, setProperty, currentStyle } = props; | ||
const { skewX, skewY } = extractSkewPropertiesFromTransform(propertyValue); | ||
|
||
const handlePropertyUpdate = ( | ||
index: number, | ||
prop: string, | ||
value: StyleValue, | ||
options?: StyleUpdateOptions | ||
) => { | ||
let newValue: UnitValue = { type: "unit", value: 0, unit: "deg" }; | ||
|
||
if (value.type === "unit") { | ||
newValue = value; | ||
} | ||
|
||
if (value.type === "tuple" && value.value[0].type === "unit") { | ||
newValue = value.value[0]; | ||
} | ||
|
||
const newFunctionValue: FunctionValue = { | ||
type: "function", | ||
name: prop, | ||
args: { type: "layers", value: [newValue] }, | ||
}; | ||
|
||
const newPropertyValue = updateRotateOrSkewPropertyValue({ | ||
panel: "skew", | ||
index, | ||
currentStyle, | ||
value: newFunctionValue, | ||
propertyValue, | ||
}); | ||
|
||
const skew = parseCssValue("transform", toValue(newPropertyValue)); | ||
if (skew.type === "invalid") { | ||
return; | ||
} | ||
|
||
setProperty("transform")(skew, options); | ||
}; | ||
|
||
return ( | ||
<Flex direction="column" gap={2}> | ||
<Grid | ||
gap={1} | ||
css={{ alignItems: "center", gridTemplateColumns: "auto 1fr 1fr" }} | ||
> | ||
<XAxisIcon /> | ||
<Label> Skew X</Label> | ||
<CssValueInputContainer | ||
key="skewX" | ||
styleSource="local" | ||
property={fakeProperty} | ||
value={ | ||
skewX?.type === "function" && skewX.args.type === "layers" | ||
? skewX.args.value[0] | ||
: { type: "unit", value: 0, unit: "deg" } | ||
} | ||
keywords={[]} | ||
setValue={(value, options) => { | ||
handlePropertyUpdate(0, "skewX", value, options); | ||
}} | ||
deleteProperty={() => {}} | ||
/> | ||
</Grid> | ||
<Grid | ||
gap={1} | ||
css={{ alignItems: "center", gridTemplateColumns: "auto 1fr 1fr" }} | ||
> | ||
<YAxisIcon /> | ||
<Label> Skew Y</Label> | ||
<CssValueInputContainer | ||
key="skewY" | ||
styleSource="local" | ||
property={fakeProperty} | ||
value={ | ||
skewY?.type === "function" && skewY.args.type === "layers" | ||
? skewY.args.value[0] | ||
: { type: "unit", value: 0, unit: "deg" } | ||
} | ||
keywords={[]} | ||
setValue={(value, options) => { | ||
handlePropertyUpdate(1, "skewY", value, options); | ||
}} | ||
deleteProperty={() => {}} | ||
/> | ||
</Grid> | ||
</Flex> | ||
); | ||
}; |
Oops, something went wrong.