@applicaster/quick-brick-player 12.0.0-rc.5 → 12.0.0-rc.51

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -6,21 +6,33 @@ import {
6
6
  ProgressBar,
7
7
  Controls,
8
8
  TransportInfo,
9
+ CountDown,
9
10
  } from "@applicaster/quick-brick-mobile-transport-controls";
10
11
 
11
12
  import { playerManager } from "@applicaster/zapp-react-native-utils/appUtils";
12
13
 
13
- import { useIsTablet } from "@applicaster/zapp-react-native-utils/reactHooks/device/useIsTablet";
14
+ import { useIsTablet } from "@applicaster/zapp-react-native-utils/reactHooks";
14
15
  import {
15
16
  forwardButton,
16
17
  playbackButton,
17
18
  rewindButton,
18
19
  skipToStartButton,
19
20
  skipToLiveButton,
21
+ PADDING_HORIZONTAL,
22
+ speedButton,
23
+ sleepButton,
20
24
  } from "./defaultLayoutsConts";
21
25
  import { AudioDescription } from "../AudioDescription";
22
26
  import { PlayerImageBackground } from "@applicaster/zapp-react-native-ui-components/Components/PlayerImageBackground";
23
27
  import { useLanguageData } from "@applicaster/zapp-react-native-utils/reactHooks/player";
28
+ import { PlayNextData } from "@applicaster/zapp-react-native-ui-components/Components/PlayerContainer/PlayerContainer";
29
+ import { useEffect, useMemo, useState } from "react";
30
+ import {
31
+ useModalAnimationContext,
32
+ AnimationComponent,
33
+ ComponentAnimationType,
34
+ } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
35
+ import DockedLayout from "./DockedLayout";
24
36
 
25
37
  type Dimensions = {
26
38
  width: number;
@@ -42,15 +54,27 @@ type LayoutProps = {
42
54
  isPaused: boolean;
43
55
  isBuffering: boolean;
44
56
  };
57
+ sleepTimerDate: number;
45
58
  value: GetValue;
59
+ playbackSpeedName: string;
60
+ playbackSleepName: string;
46
61
  configuration: { [key: string]: any };
47
62
  onPlaybackButtonPress: () => void;
48
63
  onRewindButtonPress: () => void;
49
64
  onForwardButtonPress: () => void;
65
+ onSpeedButtonPress: () => void;
66
+ onSleepButtonPress: () => void;
67
+ cancelSleepTimer: () => void;
50
68
  onPlayerSeek: (targetTime: number) => void;
51
69
  onSkipLive: () => void;
52
70
  onSkipStart: () => void;
71
+ onCloseVideoModal: () => void;
72
+ maximiseVideoModal: () => void;
53
73
  dimensions: Dimensions;
74
+ playNextData: PlayNextData;
75
+ title: string | number;
76
+ summary: string | number;
77
+ defaultDimensions: Dimensions;
54
78
  };
55
79
 
56
80
  const Styles = {
@@ -60,36 +84,46 @@ const Styles = {
60
84
  alignItems: "center",
61
85
  justifyContent: isPortraitMode ? "center" : "flex-start",
62
86
  }),
63
- tabletLayout: {
64
- width: 463,
87
+ playerImageWrapper: {
88
+ width: "100%",
65
89
  maxHeight: 750,
66
90
  marginTop: 80,
91
+ },
92
+ tabletLayout: {
93
+ width: 463,
67
94
  marginBottom: 80,
68
95
  },
69
96
  controls: (isTablet: boolean, isLiveShowFullControls: boolean) => ({
70
97
  height: isTablet ? 64 : 50,
71
- marginHorizontal: isLiveShowFullControls ? 10 : 24,
72
- justifyContent: isLiveShowFullControls ? "space-between" : "center",
98
+ marginHorizontal: 10,
99
+ justifyContent: isLiveShowFullControls ? "space-between" : "space-evenly",
73
100
  }),
74
101
  backgroundImageContainer: (dimensions: Dimensions, isTablet: boolean) => {
102
+ const mobileValue = dimensions.width
103
+ ? dimensions.width - PADDING_HORIZONTAL * 2
104
+ : 330;
105
+
75
106
  return {
76
- width: isTablet ? 463 : dimensions.width,
77
- height: isTablet ? 463 : dimensions.width,
107
+ width: isTablet ? 463 : mobileValue,
108
+ height: isTablet ? 463 : mobileValue,
78
109
  };
79
110
  },
80
- backgroundImageContainerImageStyle: (isTablet) => ({
81
- borderRadius: isTablet ? 24 : 10,
111
+ backgroundImageContainerImageStyle: (
112
+ isTablet,
113
+ docked,
114
+ startComponentsAnimation,
115
+ isActiveGesture
116
+ ) => ({
117
+ borderRadius:
118
+ (startComponentsAnimation && isActiveGesture) || docked
119
+ ? 0
120
+ : isTablet
121
+ ? 24
122
+ : 10,
82
123
  }),
83
- playerContainer: (docked: boolean, style) => {
84
- const combinedStyle = {
85
- flex: 1,
86
- };
87
124
 
88
- if (docked) {
89
- combinedStyle["height"] = style.height;
90
- }
91
-
92
- return combinedStyle;
125
+ paddingHorizontal: {
126
+ paddingHorizontal: PADDING_HORIZONTAL,
93
127
  },
94
128
 
95
129
  controlsMobile: {
@@ -103,6 +137,12 @@ const Styles = {
103
137
  separator: {
104
138
  height: 20,
105
139
  },
140
+ flexDirectionRow: {
141
+ flexDirection: "row",
142
+ },
143
+ alignItemsCenter: {
144
+ alignItems: "center",
145
+ },
106
146
  };
107
147
 
108
148
  export default function DefaultLayout(props: LayoutProps) {
@@ -117,22 +157,38 @@ export default function DefaultLayout(props: LayoutProps) {
117
157
  onPlayerSeek,
118
158
  onSkipStart,
119
159
  onSkipLive,
160
+ onSpeedButtonPress,
161
+ onSleepButtonPress,
162
+ playbackSpeedName,
163
+ playbackSleepName,
120
164
  configuration,
121
165
  dimensions,
166
+ cancelSleepTimer,
167
+ sleepTimerDate,
168
+ title,
169
+ summary,
170
+ defaultDimensions,
122
171
  } = props;
123
172
 
124
173
  const isTablet = useIsTablet();
125
174
  const { width, height } = dimensions;
126
175
  const isPortraitMode = width < height;
127
176
  const isLiveContent = playerState.isLive;
177
+ const docked = layoutState.docked;
128
178
 
129
179
  const languageData = useLanguageData("audio-player");
130
180
 
181
+ const showCounter = useMemo(() => sleepTimerDate > 0, [sleepTimerDate]);
182
+
131
183
  const controller = playerManager.getActivePlayer();
132
184
  const liveButton = Boolean(value("live_badge_enabled"));
185
+ const sleepTitle = value("playback_sleep_countdown_label");
133
186
 
134
- let showFullControls =
135
- controller?.hasContentDuration?.() && !controller?.isAd();
187
+ const [timeLeft, setTimeLeft] = useState(
188
+ sleepTimerDate !== 0 ? sleepTimerDate - Date.now() : 0
189
+ );
190
+
191
+ let showFullControls = !controller?.isAd();
136
192
 
137
193
  if (isLiveContent) {
138
194
  const seekEnabled = Boolean(value("liveSeekingEnabled"));
@@ -163,8 +219,27 @@ export default function DefaultLayout(props: LayoutProps) {
163
219
  return [play];
164
220
  }
165
221
 
166
- const rewind = rewindButton({ isTablet, onPress: onRewindButtonPress });
167
- const forward = forwardButton({ isTablet, onPress: onForwardButtonPress });
222
+ const rewind = rewindButton({
223
+ isTablet,
224
+ onPress: controller?.hasContentDuration?.() ? onRewindButtonPress : null,
225
+ });
226
+
227
+ const forward = forwardButton({
228
+ isTablet,
229
+ onPress: controller?.hasContentDuration?.() ? onForwardButtonPress : null,
230
+ });
231
+
232
+ const speed = speedButton({
233
+ isTablet,
234
+ onPress: onSpeedButtonPress,
235
+ name: playbackSpeedName,
236
+ });
237
+
238
+ const sleep = sleepButton({
239
+ isTablet,
240
+ onPress: onSleepButtonPress,
241
+ name: playbackSleepName,
242
+ });
168
243
 
169
244
  if (isLiveContent) {
170
245
  const skipToStart = skipToStartButton({
@@ -180,7 +255,8 @@ export default function DefaultLayout(props: LayoutProps) {
180
255
  return [skipToStart, rewind, play, forward, skipToLive];
181
256
  }
182
257
 
183
- return [rewind, play, forward];
258
+ // Temporary empty button until we add sleep button. It will ensure the buttons will not break in their position
259
+ return [speed, rewind, play, forward, sleep];
184
260
  }, [
185
261
  playerState,
186
262
  liveButton,
@@ -188,12 +264,48 @@ export default function DefaultLayout(props: LayoutProps) {
188
264
  onPlaybackButtonPress,
189
265
  onRewindButtonPress,
190
266
  onForwardButtonPress,
267
+ onSpeedButtonPress,
191
268
  showFullControls,
192
269
  onSkipStart,
193
270
  onSkipLive,
194
271
  isLiveContent,
272
+ playbackSpeedName,
273
+ playbackSleepName,
274
+ controller,
195
275
  ]);
196
276
 
277
+ useEffect(() => {
278
+ if (showCounter && sleepTimerDate !== 0) {
279
+ // Setting the initial timeLeft based on sleepTimerDate
280
+ setTimeLeft(sleepTimerDate - Date.now());
281
+
282
+ // Setting up an interval to update the remaining time every second
283
+ const intervalId = setInterval(() => {
284
+ setTimeLeft(() => {
285
+ const newTimeLeft = sleepTimerDate - Date.now();
286
+
287
+ // If the new remaining time is less than or equal to 0, clear the interval and trigger the cancelSleepTimer function
288
+ if (newTimeLeft <= 0) {
289
+ clearInterval(intervalId);
290
+
291
+ cancelSleepTimer();
292
+
293
+ return 0;
294
+ } else {
295
+ // Otherwise, update the state with the new remaining time
296
+ return newTimeLeft;
297
+ }
298
+ });
299
+ }, 1000);
300
+
301
+ // Clearing the interval when the component unmounts or dependencies change
302
+ return () => clearInterval(intervalId);
303
+ } else {
304
+ // Ensure the timeLeft state is set correctly if showCounter is false
305
+ setTimeLeft(0);
306
+ }
307
+ }, [sleepTimerDate, showCounter, cancelSleepTimer]);
308
+
197
309
  const Separator = () => <View style={Styles.separator} />;
198
310
 
199
311
  const liveSeekingEnabled = value("liveSeekingEnabled");
@@ -201,62 +313,120 @@ export default function DefaultLayout(props: LayoutProps) {
201
313
  const needsToShowProgressBar =
202
314
  (isLiveContent && liveSeekingEnabled) || !isLiveContent;
203
315
 
316
+ const defaultImageDimensions = React.useMemo(
317
+ () =>
318
+ defaultDimensions &&
319
+ Styles.backgroundImageContainer(defaultDimensions, isTablet),
320
+ [defaultDimensions]
321
+ );
322
+
323
+ const { isActiveGesture, startComponentsAnimation } =
324
+ useModalAnimationContext();
325
+
204
326
  return (
205
327
  <View
206
328
  style={
207
329
  isTablet ? Styles.tabletContainer(isPortraitMode) : Styles.container
208
330
  }
209
331
  >
210
- <TransportInfo
211
- content={entry}
212
- value={value}
213
- visible={true}
214
- languageData={languageData}
215
- layoutState={layoutState}
216
- actionButtons={actionButtons}
217
- />
218
- <View
219
- style={
220
- isTablet ? Styles.tabletContainer(isPortraitMode) : Styles.container
221
- }
332
+ <AnimationComponent animationType={ComponentAnimationType.componentFade}>
333
+ <TransportInfo
334
+ content={entry}
335
+ value={value}
336
+ visible={true}
337
+ languageData={languageData}
338
+ layoutState={layoutState}
339
+ actionButtons={actionButtons}
340
+ />
341
+ </AnimationComponent>
342
+ <AnimationComponent
343
+ animationType={ComponentAnimationType.moveUpComponent}
344
+ style={isTablet ? Styles.playerImageWrapper : null}
222
345
  >
223
- <View style={isTablet ? Styles.tabletLayout : null}>
346
+ <AnimationComponent
347
+ animationType={ComponentAnimationType.moveComponentHorizontal}
348
+ additionalData={{
349
+ disableAnimatedComponent: !isTablet,
350
+ moveValue: (dimensions.width - 463) / 2,
351
+ extraAnimation: !isTablet
352
+ ? {
353
+ [ComponentAnimationType.audioPlayerPaddingHorizontal]: {
354
+ style: Styles.paddingHorizontal,
355
+ },
356
+ }
357
+ : null,
358
+ }}
359
+ style={isTablet ? Styles.alignItemsCenter : null}
360
+ >
224
361
  <PlayerImageBackground
225
- configuration={configuration}
226
362
  entry={entry}
227
363
  style={Styles.backgroundImageContainer(dimensions, isTablet)}
228
- imageStyle={Styles.backgroundImageContainerImageStyle(isTablet)}
229
- />
230
- <AudioDescription
231
- content={entry}
232
- value={value}
233
- layoutState={layoutState}
234
- />
235
- <Separator />
236
- {needsToShowProgressBar && (
237
- <View>
238
- <ProgressBar
239
- content={entry}
240
- value={value}
241
- visible={true}
242
- layoutState={layoutState}
243
- onPlayerSeek={onPlayerSeek}
244
- playerState={playerState}
245
- disableFullscreen={true}
246
- sliderStyle={2}
247
- />
248
- <Separator />
249
- </View>
250
- )}
251
- <Controls
252
- value={value}
253
- visible={true}
254
- keepAlive={null}
255
- buttons={controlButtons}
256
- style={Styles.controls(isTablet, isLiveContent && showFullControls)}
257
- playerState={playerState}
364
+ imageStyle={Styles.backgroundImageContainerImageStyle(
365
+ isTablet,
366
+ docked,
367
+ startComponentsAnimation,
368
+ isActiveGesture
369
+ )}
370
+ defaultImageDimensions={defaultImageDimensions}
258
371
  />
259
- </View>
372
+ </AnimationComponent>
373
+
374
+ <DockedLayout {...props} />
375
+ </AnimationComponent>
376
+ <View
377
+ style={[
378
+ Styles.paddingHorizontal,
379
+ isTablet ? Styles.tabletLayout : null,
380
+ ]}
381
+ >
382
+ {!docked && (
383
+ <AnimationComponent
384
+ animationType={ComponentAnimationType.componentFade}
385
+ >
386
+ <AudioDescription
387
+ title={title}
388
+ summary={summary}
389
+ value={value}
390
+ layoutState={layoutState}
391
+ />
392
+ <Separator />
393
+ {needsToShowProgressBar && (
394
+ <View>
395
+ <ProgressBar
396
+ content={entry}
397
+ value={value}
398
+ visible={true}
399
+ layoutState={layoutState}
400
+ onPlayerSeek={onPlayerSeek}
401
+ playerState={playerState}
402
+ disableFullscreen={true}
403
+ sliderStyle={2}
404
+ />
405
+
406
+ {showCounter && timeLeft >= 0 && (
407
+ <CountDown
408
+ timeLeft={timeLeft}
409
+ value={value}
410
+ title={sleepTitle}
411
+ />
412
+ )}
413
+
414
+ <Separator />
415
+ </View>
416
+ )}
417
+ <Controls
418
+ value={value}
419
+ visible={true}
420
+ keepAlive={null}
421
+ buttons={controlButtons}
422
+ style={Styles.controls(
423
+ isTablet,
424
+ isLiveContent && showFullControls
425
+ )}
426
+ playerState={playerState}
427
+ />
428
+ </AnimationComponent>
429
+ )}
260
430
  </View>
261
431
  </View>
262
432
  );
@@ -1,4 +1,4 @@
1
- import React from "react";
1
+ import * as React from "react";
2
2
  import {
3
3
  StyleSheet,
4
4
  TouchableWithoutFeedback,
@@ -6,7 +6,7 @@ import {
6
6
  ViewStyle,
7
7
  } from "react-native";
8
8
  import * as R from "ramda";
9
- import { useDimensions } from "@applicaster/zapp-react-native-utils/reactHooks";
9
+ import { useIsTablet } from "@applicaster/zapp-react-native-utils/reactHooks";
10
10
 
11
11
  import {
12
12
  ContentInfo,
@@ -15,8 +15,13 @@ import {
15
15
  Button,
16
16
  } from "@applicaster/quick-brick-mobile-transport-controls";
17
17
 
18
- import { PlayerImageBackground } from "@applicaster/zapp-react-native-ui-components/Components/PlayerImageBackground";
19
18
  import { PlayNextData } from "@applicaster/zapp-react-native-ui-components/Components/PlayerContainer/PlayerContainer";
19
+ import {
20
+ useModalAnimationContext,
21
+ AnimationComponent,
22
+ ComponentAnimationType,
23
+ PlayerAnimationStateEnum,
24
+ } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
20
25
 
21
26
  type Dimensions = {
22
27
  width: number;
@@ -48,6 +53,8 @@ type LayoutProps = {
48
53
  maximiseVideoModal: () => void;
49
54
  dimensions: Dimensions;
50
55
  playNextData: PlayNextData;
56
+ title: string | number;
57
+ summary: string | number;
51
58
  };
52
59
 
53
60
  const styles = StyleSheet.create({
@@ -102,14 +109,26 @@ const backgroundColorStyle = (value: GetValue): ViewStyle => ({
102
109
  backgroundColor: value("docked_player_background_color"),
103
110
  });
104
111
 
105
- const playerDimensionsStyle = ({
106
- height,
107
- }: PlayerDimensionsProp): ViewStyle => ({
108
- paddingLeft: height || 100,
112
+ const playerDimensionsStyle = (
113
+ minimisedHeight: number,
114
+ addPadding: boolean
115
+ ): ViewStyle => ({
116
+ paddingLeft: addPadding ? minimisedHeight || 100 : 0,
117
+ });
118
+
119
+ const animatedContainerStyle = (docked: boolean): ViewStyle => ({
120
+ top: docked ? 2 : null,
121
+ position: "absolute",
122
+ width: "100%",
123
+ zIndex: docked ? 1 : -1,
109
124
  });
110
125
 
111
- const backgroundImageStyle = (dimensions: Dimensions): ViewStyle => ({
112
- height: dimensions.height,
126
+ const backgroundImageStyle = (
127
+ dimensions: Dimensions,
128
+ minimisedHeight: number,
129
+ isActiveGesture: boolean
130
+ ): ViewStyle => ({
131
+ height: isActiveGesture ? minimisedHeight : dimensions.height,
113
132
  aspectRatio: 1,
114
133
  position: "absolute",
115
134
  });
@@ -191,23 +210,42 @@ export default function DockedLayout(props: LayoutProps) {
191
210
  dimensions,
192
211
  entry,
193
212
  onCloseVideoModal,
194
- maximiseVideoModal,
195
213
  onPlayerSeek,
196
214
  playerState,
197
215
  configuration,
198
216
  playNextData,
217
+ title,
218
+ summary,
199
219
  } = props;
200
220
 
201
- const {
202
- deviceInfo: { isTablet },
203
- } = useDimensions("screen", { deviceInfo: true });
221
+ const isTablet = useIsTablet();
204
222
 
205
223
  const visible = true;
206
224
  const liveButton = Boolean(value("live_badge_enabled"));
207
225
 
226
+ const {
227
+ isActiveGesture,
228
+ setPlayerAnimationState,
229
+ startComponentsAnimation,
230
+ minimisedHeight,
231
+ } = useModalAnimationContext();
232
+
233
+ const maximazeVideoModal = React.useCallback(
234
+ () => setPlayerAnimationState(PlayerAnimationStateEnum.maximaze),
235
+ []
236
+ );
237
+
238
+ if (!layoutState.docked && !startComponentsAnimation) return null;
239
+
208
240
  return (
209
- <View style={styles.container}>
210
- {!playerState.isLive && (
241
+ <AnimationComponent
242
+ animationType={ComponentAnimationType.componentAppears}
243
+ style={[
244
+ styles.container,
245
+ animatedContainerStyle(isActiveGesture || layoutState.docked),
246
+ ]}
247
+ >
248
+ {!playerState.isLive && layoutState.docked && (
211
249
  <ProgressBar
212
250
  content={entry}
213
251
  value={value}
@@ -215,18 +253,27 @@ export default function DockedLayout(props: LayoutProps) {
215
253
  layoutState={layoutState}
216
254
  onPlayerSeek={onPlayerSeek}
217
255
  playerState={playerState}
256
+ docked
218
257
  />
219
258
  )}
220
259
 
221
260
  <View style={styles.content}>
222
- <PlayerImageBackground
223
- configuration={configuration}
224
- entry={entry}
225
- style={backgroundImageStyle(dimensions)}
261
+ <View
262
+ style={backgroundImageStyle(
263
+ dimensions,
264
+ minimisedHeight,
265
+ isActiveGesture
266
+ )}
226
267
  />
227
- <TouchableWithoutFeedback onPress={maximiseVideoModal}>
268
+ <TouchableWithoutFeedback onPress={maximazeVideoModal}>
228
269
  <View
229
- style={[styles.touchableArea, playerDimensionsStyle(dimensions)]}
270
+ style={[
271
+ styles.touchableArea,
272
+ playerDimensionsStyle(
273
+ minimisedHeight,
274
+ isActiveGesture || layoutState.docked
275
+ ),
276
+ ]}
230
277
  >
231
278
  <View
232
279
  style={[
@@ -234,7 +281,11 @@ export default function DockedLayout(props: LayoutProps) {
234
281
  !configuration.magic_background && backgroundColorStyle(value),
235
282
  ]}
236
283
  >
237
- <ContentInfo content={entry} value={value} docked />
284
+ <ContentInfo
285
+ content={{ ...entry, title, summary }}
286
+ value={value}
287
+ docked
288
+ />
238
289
  </View>
239
290
  </View>
240
291
  </TouchableWithoutFeedback>
@@ -266,6 +317,6 @@ export default function DockedLayout(props: LayoutProps) {
266
317
  />
267
318
  </View>
268
319
  </View>
269
- </View>
320
+ </AnimationComponent>
270
321
  );
271
322
  }
@@ -19,6 +19,8 @@ const playbackButtonMargins = (
19
19
  ): number =>
20
20
  isLiveShowFullControls ? (isTablet ? 65 : 10) : isTablet ? 95 : 40;
21
21
 
22
+ export const PADDING_HORIZONTAL = 15;
23
+
22
24
  export const playbackButton = ({
23
25
  playerState,
24
26
  liveButton,
@@ -53,8 +55,9 @@ type ButtonsProps = {
53
55
  onPress: () => void;
54
56
  isTablet: boolean;
55
57
  style?: any;
58
+ name?: string;
56
59
  };
57
- type ButtonsByNameProps = ButtonsProps & { name: string };
60
+ type ButtonsByNameProps = ButtonsProps & { name?: string };
58
61
 
59
62
  const rewindButtonByName = ({
60
63
  name,
@@ -79,6 +82,28 @@ const skipButtonByName = ({
79
82
  style,
80
83
  });
81
84
 
85
+ const speedButtonByName = ({
86
+ name = "speed_1",
87
+ onPress,
88
+ style,
89
+ }: ButtonsByNameProps): ControlsButton => ({
90
+ size: "small",
91
+ icon: name,
92
+ onPress,
93
+ style,
94
+ });
95
+
96
+ const sleepButtonByName = ({
97
+ name = "sleep_timer",
98
+ onPress,
99
+ style,
100
+ }: ButtonsByNameProps): ControlsButton => ({
101
+ size: "small",
102
+ icon: name,
103
+ onPress,
104
+ style,
105
+ });
106
+
82
107
  export const rewindButton = (props: ButtonsProps): ControlsButton =>
83
108
  rewindButtonByName({ ...props, name: "rewind" });
84
109
 
@@ -90,3 +115,9 @@ export const skipToStartButton = (props: ButtonsProps): ControlsButton =>
90
115
 
91
116
  export const skipToLiveButton = (props: ButtonsProps): ControlsButton =>
92
117
  skipButtonByName({ ...props, name: "skip_live" });
118
+
119
+ export const speedButton = (props: ButtonsProps): ControlsButton =>
120
+ speedButtonByName({ ...props });
121
+
122
+ export const sleepButton = (props: ButtonsProps): ControlsButton =>
123
+ sleepButtonByName({ ...props });