Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { Meta, StoryObj } from "@storybook/react";
import { AnimationPanelContent } from "./animation-panel-content";
import { theme } from "@webstudio-is/design-system";
import { Box, theme } from "@webstudio-is/design-system";
import { useState } from "react";
import type { ScrollAnimation, ViewAnimation } from "@webstudio-is/sdk";

Expand All @@ -26,27 +26,38 @@ const ScrollAnimationTemplate: Story["render"] = ({ value: initialValue }) => {
const [value, setValue] = useState(initialValue);

return (
<AnimationPanelContent
type="scroll"
value={value}
onChange={(newValue) => {
setValue(newValue as ScrollAnimation);
}}
/>
<Box css={{ width: 240 }}>
<AnimationPanelContent
type="scroll"
value={value}
onChange={(newValue, isEphemeral) => {
if (isEphemeral) {
return;
}

setValue(newValue as ScrollAnimation);
}}
/>
</Box>
);
};

const ViewAnimationTemplate: Story["render"] = ({ value: initialValue }) => {
const [value, setValue] = useState(initialValue);

return (
<AnimationPanelContent
type="view"
value={value}
onChange={(newValue) => {
setValue(newValue as ViewAnimation);
}}
/>
<Box css={{ width: 240 }}>
<AnimationPanelContent
type="view"
value={value}
onChange={(newValue, isEphemeral) => {
if (isEphemeral) {
return;
}
setValue(newValue as ViewAnimation);
}}
/>
</Box>
);
};

Expand Down Expand Up @@ -82,7 +93,7 @@ export const ViewAnimationStory: Story = {
name: "view-animation",
timing: {
rangeStart: ["entry", { type: "unit", value: 0, unit: "%" }],
rangeEnd: ["exit", { type: "unit", value: 100, unit: "%" }],
rangeEnd: ["entry", { type: "unit", value: 100, unit: "%" }],
},
keyframes: [
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import { Keyframes } from "./animation-keyframes";
import { humanizeString } from "~/shared/string-utils";
import { Link2Icon, Link2UnlinkedIcon } from "@webstudio-is/icons";
import { $availableUnitVariables } from "~/builder/features/style-panel/shared/model";
import { AnimationRanges } from "./animation-ranges";

const fillModeDescriptions: Record<
NonNullable<ViewAnimation["timing"]["fill"]>,
Expand Down Expand Up @@ -469,22 +470,46 @@ export const AnimationPanelContent = ({
}}
/>
</Grid>

<Grid
gap={1}
align={"center"}
css={{
gridTemplateColumns: "1fr 16px 1fr",
gridTemplateAreas: `
"rangeEndLabel . . animation"
"rangeEndName rangeEndPercentage connect animation"
"rangeStartLabel . connect animation"
"rangeStartName rangeStartPercentage connect animation"
"durationLabel durationValue . animation"
`,
gridTemplateColumns: "1.5fr 1fr 16px 34px",
paddingInline: theme.panel.paddingInline,
flexShrink: 0,
}}
>
<Label htmlFor={fieldIds.rangeStartName}>Range Start</Label>
<div />
<Label disabled={!isRangeEndEnabled} htmlFor={fieldIds.rangeEndName}>
<Label
css={{
gridArea: "rangeStartLabel",
}}
htmlFor={fieldIds.rangeStartName}
>
Range Start
</Label>

<Label
css={{
gridArea: "rangeEndLabel",
}}
disabled={!isRangeEndEnabled}
htmlFor={fieldIds.rangeEndName}
>
Range End
</Label>

<Select
css={{
gridArea: "rangeStartName",
}}
id={fieldIds.rangeStartName}
options={timelineRangeNames}
getLabel={humanizeString}
Expand Down Expand Up @@ -550,7 +575,11 @@ export const AnimationPanelContent = ({
);
}}
/>
<Grid>
<Grid
css={{
gridArea: "connect",
}}
>
<EnhancedTooltip
content={isLinked ? "Unlink range names" : "Link range names"}
>
Expand Down Expand Up @@ -582,6 +611,9 @@ export const AnimationPanelContent = ({
</EnhancedTooltip>
</Grid>
<Select
css={{
gridArea: "rangeEndName",
}}
id={fieldIds.rangeEndName}
disabled={!isRangeEndEnabled}
options={timelineRangeNames}
Expand Down Expand Up @@ -648,105 +680,114 @@ export const AnimationPanelContent = ({
}}
/>

<RangeValueInput
id={fieldIds.rangeStartValue}
value={
value.timing.rangeStart?.[1] ?? {
type: "unit",
value: 0,
unit: "%",
}
}
onChange={(rangeStart, isEphemeral) => {
if (rangeStart === undefined && isEphemeral) {
handleChange(undefined, true);
return;
<Box css={{ gridArea: "rangeStartPercentage" }}>
<RangeValueInput
id={fieldIds.rangeStartValue}
value={
value.timing.rangeStart?.[1] ?? {
type: "unit",
value: 0,
unit: "%",
}
}
onChange={(rangeStart, isEphemeral) => {
if (rangeStart === undefined && isEphemeral) {
handleChange(undefined, true);
return;
}

const defaultTimelineRangeName = timelineRangeNames[0]!;

handleChange(
{
...value,
timing: {
...value.timing,
rangeStart: [
value.timing.rangeStart?.[0] ?? defaultTimelineRangeName,
rangeStart,
],
const defaultTimelineRangeName = timelineRangeNames[0]!;

handleChange(
{
...value,
timing: {
...value.timing,
rangeStart: [
value.timing.rangeStart?.[0] ?? defaultTimelineRangeName,
rangeStart,
],
},
},
},
isEphemeral
);
}}
/>
<div />
<RangeValueInput
id={fieldIds.rangeEndValue}
disabled={!isRangeEndEnabled}
value={
value.timing.rangeEnd?.[1] ?? {
type: "unit",
value: 0,
unit: "%",
}
}
onChange={(rangeEnd, isEphemeral) => {
if (rangeEnd === undefined && isEphemeral) {
handleChange(undefined, true);
return;
isEphemeral
);
}}
/>
</Box>
<Box css={{ gridArea: "rangeEndPercentage" }}>
<RangeValueInput
id={fieldIds.rangeEndValue}
disabled={!isRangeEndEnabled}
value={
value.timing.rangeEnd?.[1] ?? {
type: "unit",
value: 0,
unit: "%",
}
}
onChange={(rangeEnd, isEphemeral) => {
if (rangeEnd === undefined && isEphemeral) {
handleChange(undefined, true);
return;
}

const defaultTimelineRangeName = timelineRangeNames[0]!;

handleChange(
{
...value,
timing: {
...value.timing,
rangeEnd: [
value.timing.rangeEnd?.[0] ?? defaultTimelineRangeName,
rangeEnd,
],
const defaultTimelineRangeName = timelineRangeNames[0]!;

handleChange(
{
...value,
timing: {
...value.timing,
rangeEnd: [
value.timing.rangeEnd?.[0] ?? defaultTimelineRangeName,
rangeEnd,
],
},
},
},
isEphemeral
);
isEphemeral
);
}}
/>
</Box>

<Label
css={{
gridArea: "durationLabel",
}}
/>
</Grid>
htmlFor={fieldIds.duration}
>
Duration
</Label>

<Grid
gap={1}
align={"center"}
css={{
gridTemplateColumns: "1fr 16px 1fr",
paddingInline: theme.panel.paddingInline,
}}
>
<Label htmlFor={fieldIds.duration}>Duration</Label>
<div />
<DurationInput
id={fieldIds.duration}
value={value.timing.duration}
onChange={(duration, isEphemeral) => {
if (duration === undefined && isEphemeral) {
handleChange(undefined, true);
return;
}
<Box css={{ gridArea: "durationValue" }}>
<DurationInput
id={fieldIds.duration}
value={value.timing.duration}
onChange={(duration, isEphemeral) => {
if (duration === undefined && isEphemeral) {
handleChange(undefined, true);
return;
}

handleChange(
{
...value,
timing: {
...value.timing,
duration,
handleChange(
{
...value,
timing: {
...value.timing,
duration,
},
},
},
isEphemeral
);
}}
/>
isEphemeral
);
}}
/>
</Box>
<Grid css={{ gridArea: "animation", alignSelf: "stretch" }}>
<AnimationRanges
rangeStart={value.timing.rangeStart}
rangeEnd={value.timing.rangeEnd}
/>
</Grid>
</Grid>

<Keyframes
Expand Down
Loading