From edceea27600f87a80147a373c9df16ba6fa17bad Mon Sep 17 00:00:00 2001 From: Ivan Starkov Date: Wed, 26 Mar 2025 18:59:54 +0300 Subject: [PATCH] experimental: Link animation range names (#5056) ## Description image ## Steps for reproduction 1. click button 2. expect xyz ## Code Review - [ ] 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 - [ ] made a self-review - [ ] added inline comments where things may be not obvious (the "why", not "what") ## Before merging - [ ] tested locally and on preview environment (preview dev login: 0000) - [ ] updated [test cases](https://github.com/webstudio-is/webstudio/blob/main/apps/builder/docs/test-cases.md) document - [ ] added tests - [ ] if any new env variables are added, added them to `.env` file --- .../animation/animation-panel-content.tsx | 214 +++++++++++------- 1 file changed, 137 insertions(+), 77 deletions(-) diff --git a/apps/builder/app/builder/features/settings-panel/props-section/animation/animation-panel-content.tsx b/apps/builder/app/builder/features/settings-panel/props-section/animation/animation-panel-content.tsx index 36810ffa9a..234e49e529 100644 --- a/apps/builder/app/builder/features/settings-panel/props-section/animation/animation-panel-content.tsx +++ b/apps/builder/app/builder/features/settings-panel/props-section/animation/animation-panel-content.tsx @@ -1,11 +1,13 @@ import { useState } from "react"; import { Box, + EnhancedTooltip, Flex, Grid, InputField, Label, Select, + SmallToggleButton, theme, toast, } from "@webstudio-is/design-system"; @@ -34,6 +36,7 @@ import { } from "@webstudio-is/css-engine"; import { Keyframes } from "./animation-keyframes"; import { humanizeString } from "~/shared/string-utils"; +import { Link2Icon, Link2UnlinkedIcon } from "@webstudio-is/icons"; const fillModeDescriptions: Record< NonNullable, @@ -215,11 +218,27 @@ type AnimationPanelContentProps = { ((value: undefined, isEphemeral: true) => void); }; +const defaultRangeStart = { + type: "unit", + value: 0, + unit: "%", +}; + +const defaultRangeEnd = { + type: "unit", + value: 100, + unit: "%", +}; + export const AnimationPanelContent = ({ onChange, value, type, }: AnimationPanelContentProps) => { + const [isLinked, setIsLinked] = useState( + value.timing.rangeStart?.[0] === value.timing.rangeEnd?.[0] + ); + const fieldIds = useIds([ "rangeStartName", "rangeStartValue", @@ -302,12 +321,13 @@ export const AnimationPanelContent = ({ gap={1} align={"center"} css={{ - gridTemplateColumns: "1fr 1fr", + gridTemplateColumns: "1fr 16px 1fr", paddingInline: theme.panel.paddingInline, flexShrink: 0, }} > +
+ + + { + setIsLinked(pressed); + if (pressed) { + handleChange( + { + ...value, + timing: { + ...value.timing, + rangeEnd: pressed + ? [ + value.timing.rangeStart?.[0] ?? "entry", + value.timing.rangeEnd?.[1] ?? defaultRangeEnd, + ] + : value.timing.rangeEnd, + }, + }, + false + ); + } + }} + variant="normal" + icon={isLinked ? : } + /> + + + ( - - { - timelineRangeDescriptions[ - timelineRangeName as keyof typeof timelineRangeDescriptions - ] - } - - )} - onItemHighlight={(timelineRangeName) => { - if (timelineRangeName === undefined) { - handleChange(undefined, true); - return; - } - handleChange( - { - ...value, - timing: { - ...value.timing, - rangeEnd: [ - timelineRangeName, - value.timing.rangeEnd?.[1] ?? { - type: "unit", - value: 0, - unit: "%", - }, - ], - }, - }, - true - ); - }} - onChange={(timelineRangeName) => { - handleChange( - { - ...value, - timing: { - ...value.timing, - rangeEnd: [ - timelineRangeName, - value.timing.rangeEnd?.[1] ?? { - type: "unit", - value: 0, - unit: "%", - }, - ], - }, - }, - false - ); - }} - /> +