@@ -40,6 +40,7 @@ import { Keyframes } from "./animation-keyframes";
40
40
import { humanizeString } from "~/shared/string-utils" ;
41
41
import { Link2Icon , Link2UnlinkedIcon } from "@webstudio-is/icons" ;
42
42
import { $availableUnitVariables } from "~/builder/features/style-panel/shared/model" ;
43
+ import { AnimationRanges } from "./animation-ranges" ;
43
44
44
45
const fillModeDescriptions : Record <
45
46
NonNullable < ViewAnimation [ "timing" ] [ "fill" ] > ,
@@ -469,22 +470,46 @@ export const AnimationPanelContent = ({
469
470
} }
470
471
/>
471
472
</ Grid >
473
+
472
474
< Grid
473
475
gap = { 1 }
474
476
align = { "center" }
475
477
css = { {
476
- gridTemplateColumns : "1fr 16px 1fr" ,
478
+ gridTemplateAreas : `
479
+ "rangeEndLabel . . animation"
480
+ "rangeEndName rangeEndPercentage connect animation"
481
+ "rangeStartLabel . connect animation"
482
+ "rangeStartName rangeStartPercentage connect animation"
483
+ "durationLabel durationValue . animation"
484
+ ` ,
485
+ gridTemplateColumns : "1.5fr 1fr 16px 34px" ,
477
486
paddingInline : theme . panel . paddingInline ,
478
487
flexShrink : 0 ,
479
488
} }
480
489
>
481
- < Label htmlFor = { fieldIds . rangeStartName } > Range Start</ Label >
482
- < div />
483
- < Label disabled = { ! isRangeEndEnabled } htmlFor = { fieldIds . rangeEndName } >
490
+ < Label
491
+ css = { {
492
+ gridArea : "rangeStartLabel" ,
493
+ } }
494
+ htmlFor = { fieldIds . rangeStartName }
495
+ >
496
+ Range Start
497
+ </ Label >
498
+
499
+ < Label
500
+ css = { {
501
+ gridArea : "rangeEndLabel" ,
502
+ } }
503
+ disabled = { ! isRangeEndEnabled }
504
+ htmlFor = { fieldIds . rangeEndName }
505
+ >
484
506
Range End
485
507
</ Label >
486
508
487
509
< Select
510
+ css = { {
511
+ gridArea : "rangeStartName" ,
512
+ } }
488
513
id = { fieldIds . rangeStartName }
489
514
options = { timelineRangeNames }
490
515
getLabel = { humanizeString }
@@ -550,7 +575,11 @@ export const AnimationPanelContent = ({
550
575
) ;
551
576
} }
552
577
/>
553
- < Grid >
578
+ < Grid
579
+ css = { {
580
+ gridArea : "connect" ,
581
+ } }
582
+ >
554
583
< EnhancedTooltip
555
584
content = { isLinked ? "Unlink range names" : "Link range names" }
556
585
>
@@ -582,6 +611,9 @@ export const AnimationPanelContent = ({
582
611
</ EnhancedTooltip >
583
612
</ Grid >
584
613
< Select
614
+ css = { {
615
+ gridArea : "rangeEndName" ,
616
+ } }
585
617
id = { fieldIds . rangeEndName }
586
618
disabled = { ! isRangeEndEnabled }
587
619
options = { timelineRangeNames }
@@ -648,105 +680,114 @@ export const AnimationPanelContent = ({
648
680
} }
649
681
/>
650
682
651
- < RangeValueInput
652
- id = { fieldIds . rangeStartValue }
653
- value = {
654
- value . timing . rangeStart ?. [ 1 ] ?? {
655
- type : "unit" ,
656
- value : 0 ,
657
- unit : "%" ,
658
- }
659
- }
660
- onChange = { ( rangeStart , isEphemeral ) => {
661
- if ( rangeStart === undefined && isEphemeral ) {
662
- handleChange ( undefined , true ) ;
663
- return ;
683
+ < Box css = { { gridArea : "rangeStartPercentage" } } >
684
+ < RangeValueInput
685
+ id = { fieldIds . rangeStartValue }
686
+ value = {
687
+ value . timing . rangeStart ?. [ 1 ] ?? {
688
+ type : "unit" ,
689
+ value : 0 ,
690
+ unit : "%" ,
691
+ }
664
692
}
693
+ onChange = { ( rangeStart , isEphemeral ) => {
694
+ if ( rangeStart === undefined && isEphemeral ) {
695
+ handleChange ( undefined , true ) ;
696
+ return ;
697
+ }
665
698
666
- const defaultTimelineRangeName = timelineRangeNames [ 0 ] ! ;
667
-
668
- handleChange (
669
- {
670
- ...value ,
671
- timing : {
672
- ...value . timing ,
673
- rangeStart : [
674
- value . timing . rangeStart ?. [ 0 ] ?? defaultTimelineRangeName ,
675
- rangeStart ,
676
- ] ,
699
+ const defaultTimelineRangeName = timelineRangeNames [ 0 ] ! ;
700
+
701
+ handleChange (
702
+ {
703
+ ...value ,
704
+ timing : {
705
+ ...value . timing ,
706
+ rangeStart : [
707
+ value . timing . rangeStart ?. [ 0 ] ?? defaultTimelineRangeName ,
708
+ rangeStart ,
709
+ ] ,
710
+ } ,
677
711
} ,
678
- } ,
679
- isEphemeral
680
- ) ;
681
- } }
682
- />
683
- < div />
684
- < RangeValueInput
685
- id = { fieldIds . rangeEndValue }
686
- disabled = { ! isRangeEndEnabled }
687
- value = {
688
- value . timing . rangeEnd ?. [ 1 ] ?? {
689
- type : "unit" ,
690
- value : 0 ,
691
- unit : "%" ,
692
- }
693
- }
694
- onChange = { ( rangeEnd , isEphemeral ) => {
695
- if ( rangeEnd === undefined && isEphemeral ) {
696
- handleChange ( undefined , true ) ;
697
- return ;
712
+ isEphemeral
713
+ ) ;
714
+ } }
715
+ />
716
+ </ Box >
717
+ < Box css = { { gridArea : "rangeEndPercentage" } } >
718
+ < RangeValueInput
719
+ id = { fieldIds . rangeEndValue }
720
+ disabled = { ! isRangeEndEnabled }
721
+ value = {
722
+ value . timing . rangeEnd ?. [ 1 ] ?? {
723
+ type : "unit" ,
724
+ value : 0 ,
725
+ unit : "%" ,
726
+ }
698
727
}
728
+ onChange = { ( rangeEnd , isEphemeral ) => {
729
+ if ( rangeEnd === undefined && isEphemeral ) {
730
+ handleChange ( undefined , true ) ;
731
+ return ;
732
+ }
699
733
700
- const defaultTimelineRangeName = timelineRangeNames [ 0 ] ! ;
701
-
702
- handleChange (
703
- {
704
- ...value ,
705
- timing : {
706
- ...value . timing ,
707
- rangeEnd : [
708
- value . timing . rangeEnd ?. [ 0 ] ?? defaultTimelineRangeName ,
709
- rangeEnd ,
710
- ] ,
734
+ const defaultTimelineRangeName = timelineRangeNames [ 0 ] ! ;
735
+
736
+ handleChange (
737
+ {
738
+ ...value ,
739
+ timing : {
740
+ ...value . timing ,
741
+ rangeEnd : [
742
+ value . timing . rangeEnd ?. [ 0 ] ?? defaultTimelineRangeName ,
743
+ rangeEnd ,
744
+ ] ,
745
+ } ,
711
746
} ,
712
- } ,
713
- isEphemeral
714
- ) ;
747
+ isEphemeral
748
+ ) ;
749
+ } }
750
+ />
751
+ </ Box >
752
+
753
+ < Label
754
+ css = { {
755
+ gridArea : "durationLabel" ,
715
756
} }
716
- />
717
- </ Grid >
757
+ htmlFor = { fieldIds . duration }
758
+ >
759
+ Duration
760
+ </ Label >
718
761
719
- < Grid
720
- gap = { 1 }
721
- align = { "center" }
722
- css = { {
723
- gridTemplateColumns : "1fr 16px 1fr" ,
724
- paddingInline : theme . panel . paddingInline ,
725
- } }
726
- >
727
- < Label htmlFor = { fieldIds . duration } > Duration</ Label >
728
- < div />
729
- < DurationInput
730
- id = { fieldIds . duration }
731
- value = { value . timing . duration }
732
- onChange = { ( duration , isEphemeral ) => {
733
- if ( duration === undefined && isEphemeral ) {
734
- handleChange ( undefined , true ) ;
735
- return ;
736
- }
762
+ < Box css = { { gridArea : "durationValue" } } >
763
+ < DurationInput
764
+ id = { fieldIds . duration }
765
+ value = { value . timing . duration }
766
+ onChange = { ( duration , isEphemeral ) => {
767
+ if ( duration === undefined && isEphemeral ) {
768
+ handleChange ( undefined , true ) ;
769
+ return ;
770
+ }
737
771
738
- handleChange (
739
- {
740
- ...value ,
741
- timing : {
742
- ...value . timing ,
743
- duration,
772
+ handleChange (
773
+ {
774
+ ...value ,
775
+ timing : {
776
+ ...value . timing ,
777
+ duration,
778
+ } ,
744
779
} ,
745
- } ,
746
- isEphemeral
747
- ) ;
748
- } }
749
- />
780
+ isEphemeral
781
+ ) ;
782
+ } }
783
+ />
784
+ </ Box >
785
+ < Grid css = { { gridArea : "animation" , alignSelf : "stretch" } } >
786
+ < AnimationRanges
787
+ rangeStart = { value . timing . rangeStart }
788
+ rangeEnd = { value . timing . rangeEnd }
789
+ />
790
+ </ Grid >
750
791
</ Grid >
751
792
752
793
< Keyframes
0 commit comments