@@ -20,6 +20,7 @@ import {
20
20
FloatingPanel ,
21
21
InputField ,
22
22
DialogTitle ,
23
+ Tooltip ,
23
24
} from "@webstudio-is/design-system" ;
24
25
import {
25
26
EyeClosedIcon ,
@@ -45,15 +46,24 @@ const newAnimationsPerType: {
45
46
view : newViewAnimations ,
46
47
} ;
47
48
48
- type Props = {
49
+ type AnimationsSelectProps = {
49
50
value : AnimationAction ;
50
51
onChange : ( ( value : unknown , isEphemeral : boolean ) => void ) &
51
52
( ( value : undefined , isEphemeral : true ) => void ) ;
53
+ isAnimationEnabled : (
54
+ enabled : [ breakpointId : string , enabled : boolean ] [ ] | undefined
55
+ ) => boolean | undefined ;
56
+ selectedBreakpointId : string ;
52
57
} ;
53
58
54
59
const floatingPanelOffset = { alignmentAxis : - 100 } ;
55
60
56
- export const AnimationsSelect = ( { value, onChange } : Props ) => {
61
+ export const AnimationsSelect = ( {
62
+ value,
63
+ onChange,
64
+ isAnimationEnabled,
65
+ selectedBreakpointId,
66
+ } : AnimationsSelectProps ) => {
57
67
const fieldIds = useIds ( [ "addAnimation" ] as const ) ;
58
68
59
69
const [ newAnimationHint , setNewAnimationHint ] = useState < string | undefined > (
@@ -145,106 +155,134 @@ export const AnimationsSelect = ({ value, onChange }: Props) => {
145
155
</ DropdownMenu >
146
156
< CssValueListArrowFocus dragItemId = { dragItemId } >
147
157
< Grid gap = { 1 } css = { { gridColumn : "span 2" } } ref = { sortableRefCallback } >
148
- { value . animations . map ( ( animation , index ) => (
149
- < FloatingPanel
150
- key = { index }
151
- title = {
152
- < DialogTitle css = { { paddingLeft : theme . spacing [ 6 ] } } >
153
- < InputField
154
- css = { {
155
- width : "100%" ,
156
- fontWeight : `inherit` ,
157
- } }
158
- variant = "chromeless"
159
- value = { animation . name }
160
- autoFocus = { true }
161
- placeholder = "Enter animation name"
162
- onChange = { ( event ) => {
163
- const name = event . currentTarget . value ;
164
- const newAnimations = [ ...value . animations ] ;
165
- newAnimations [ index ] = { ...animation , name } ;
158
+ { value . animations . map ( ( animation , index ) => {
159
+ const isEnabled = isAnimationEnabled ( animation . enabled ) ?? true ;
166
160
167
- const newValue = {
168
- ...value ,
169
- animations : newAnimations ,
170
- } ;
171
-
172
- handleChange ( newValue , false ) ;
173
- } }
174
- />
175
- </ DialogTitle >
176
- }
177
- content = {
178
- < AnimationPanelContent
179
- type = { value . type }
180
- value = { animation }
181
- onChange = { ( animation , isEphemeral ) => {
182
- if ( animation === undefined ) {
183
- // Reset ephemeral state
184
- handleChange ( undefined , true ) ;
185
- return ;
186
- }
187
-
188
- const newAnimations = [ ...value . animations ] ;
189
- newAnimations [ index ] = animation ;
190
- const newValue = {
191
- ...value ,
192
- animations : newAnimations ,
193
- } ;
194
- handleChange ( newValue , isEphemeral ) ;
195
- } }
196
- />
197
- }
198
- offset = { floatingPanelOffset }
199
- >
200
- < CssValueListItem
161
+ return (
162
+ < FloatingPanel
201
163
key = { index }
202
- label = {
203
- < Label disabled = { false } truncate >
204
- { animation . name ?? "Unnamed" }
205
- </ Label >
206
- }
207
- hidden = { false }
208
- draggable
209
- active = { dragItemId === String ( index ) }
210
- state = { undefined }
211
- index = { index }
212
- id = { String ( index ) }
213
- buttons = {
214
- < >
215
- < SmallToggleButton
216
- pressed = { false }
217
- onPressedChange = { ( ) => {
218
- alert ( "Not implemented" ) ;
164
+ title = {
165
+ < DialogTitle css = { { paddingLeft : theme . spacing [ 6 ] } } >
166
+ < InputField
167
+ css = { {
168
+ width : "100%" ,
169
+ fontWeight : `inherit` ,
219
170
} }
220
- variant = "normal"
221
- tabIndex = { - 1 }
222
- icon = {
223
- // eslint-disable-next-line no-constant-condition
224
- false ? < EyeClosedIcon /> : < EyeOpenIcon />
225
- }
226
- />
227
-
228
- < SmallIconButton
229
- variant = "destructive"
230
- tabIndex = { - 1 }
231
- icon = { < MinusIcon /> }
232
- onClick = { ( ) => {
171
+ variant = "chromeless"
172
+ value = { animation . name }
173
+ autoFocus = { true }
174
+ placeholder = "Enter animation name"
175
+ onChange = { ( event ) => {
176
+ const name = event . currentTarget . value ;
233
177
const newAnimations = [ ...value . animations ] ;
234
- newAnimations . splice ( index , 1 ) ;
178
+ newAnimations [ index ] = { ... animation , name } ;
235
179
236
180
const newValue = {
237
181
...value ,
238
182
animations : newAnimations ,
239
183
} ;
184
+
240
185
handleChange ( newValue , false ) ;
241
186
} }
242
187
/>
243
- </ >
188
+ </ DialogTitle >
244
189
}
245
- />
246
- </ FloatingPanel >
247
- ) ) }
190
+ content = {
191
+ < AnimationPanelContent
192
+ type = { value . type }
193
+ value = { animation }
194
+ onChange = { ( animation , isEphemeral ) => {
195
+ if ( animation === undefined ) {
196
+ // Reset ephemeral state
197
+ handleChange ( undefined , true ) ;
198
+ return ;
199
+ }
200
+
201
+ const newAnimations = [ ...value . animations ] ;
202
+ newAnimations [ index ] = animation ;
203
+ const newValue = {
204
+ ...value ,
205
+ animations : newAnimations ,
206
+ } ;
207
+ handleChange ( newValue , isEphemeral ) ;
208
+ } }
209
+ />
210
+ }
211
+ offset = { floatingPanelOffset }
212
+ >
213
+ < CssValueListItem
214
+ key = { index }
215
+ label = {
216
+ < Label disabled = { false } truncate >
217
+ { animation . name ?? "Unnamed" }
218
+ </ Label >
219
+ }
220
+ hidden = { ! isEnabled }
221
+ draggable
222
+ active = { dragItemId === String ( index ) }
223
+ state = { undefined }
224
+ index = { index }
225
+ id = { String ( index ) }
226
+ buttons = {
227
+ < >
228
+ < Tooltip
229
+ content = {
230
+ isEnabled
231
+ ? "Disable animation at breakpoint"
232
+ : "Enable animation at breakpoint"
233
+ }
234
+ >
235
+ < SmallToggleButton
236
+ pressed = { ! isEnabled }
237
+ onPressedChange = { ( ) => {
238
+ const enabledMap = new Map ( animation . enabled ) ;
239
+ enabledMap . set ( selectedBreakpointId , ! isEnabled ) ;
240
+
241
+ const enabled = [ ...enabledMap ] ;
242
+
243
+ const newAnimations = [ ...value . animations ] ;
244
+ const newAnimation = {
245
+ ...animation ,
246
+ enabled : enabled . every ( ( [ _ , enabled ] ) => enabled )
247
+ ? undefined
248
+ : [ ...enabledMap ] ,
249
+ } ;
250
+
251
+ newAnimations [ index ] = newAnimation ;
252
+
253
+ const newValue = {
254
+ ...value ,
255
+ animations : newAnimations ,
256
+ } ;
257
+ handleChange ( newValue , false ) ;
258
+ } }
259
+ variant = "normal"
260
+ tabIndex = { - 1 }
261
+ icon = { isEnabled ? < EyeOpenIcon /> : < EyeClosedIcon /> }
262
+ />
263
+ </ Tooltip >
264
+
265
+ < SmallIconButton
266
+ variant = "destructive"
267
+ tabIndex = { - 1 }
268
+ icon = { < MinusIcon /> }
269
+ onClick = { ( ) => {
270
+ const newAnimations = [ ...value . animations ] ;
271
+ newAnimations . splice ( index , 1 ) ;
272
+
273
+ const newValue = {
274
+ ...value ,
275
+ animations : newAnimations ,
276
+ } ;
277
+ handleChange ( newValue , false ) ;
278
+ } }
279
+ />
280
+ </ >
281
+ }
282
+ />
283
+ </ FloatingPanel >
284
+ ) ;
285
+ } ) }
248
286
{ placementIndicator }
249
287
</ Grid >
250
288
</ CssValueListArrowFocus >
0 commit comments