@times-components/ts-components 1.112.0 → 1.112.1

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.
Files changed (88) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/components/article-audio/ArticleAudio.d.ts +6 -0
  3. package/dist/components/article-audio/ArticleAudio.js +51 -0
  4. package/dist/components/article-audio/ArticleAudio.stories.d.ts +1 -0
  5. package/dist/components/article-audio/ArticleAudio.stories.js +8 -0
  6. package/dist/components/article-audio/__tests__/ArticleAudio.test.d.ts +1 -0
  7. package/dist/components/article-audio/__tests__/ArticleAudio.test.js +129 -0
  8. package/dist/components/article-audio/__tests__/Styles.test.d.ts +2 -0
  9. package/dist/components/article-audio/__tests__/Styles.test.js +45 -0
  10. package/dist/components/article-audio/styles.d.ts +1 -0
  11. package/dist/components/article-audio/styles.js +26 -0
  12. package/dist/components/audio-player-components/AudioPlayer.d.ts +3 -0
  13. package/dist/components/audio-player-components/AudioPlayer.js +180 -0
  14. package/dist/components/audio-player-components/AudioPlayer.stories.d.ts +1 -0
  15. package/dist/components/audio-player-components/AudioPlayer.stories.js +204 -0
  16. package/dist/components/audio-player-components/CollapseIcon.d.ts +3 -0
  17. package/dist/components/audio-player-components/CollapseIcon.js +12 -0
  18. package/dist/components/audio-player-components/PlaybackControls.d.ts +3 -0
  19. package/dist/components/audio-player-components/PlaybackControls.js +32 -0
  20. package/dist/components/audio-player-components/SeekBar.d.ts +3 -0
  21. package/dist/components/audio-player-components/SeekBar.js +8 -0
  22. package/dist/components/audio-player-components/TabletDesktopPlayer.d.ts +3 -0
  23. package/dist/components/audio-player-components/TabletDesktopPlayer.js +37 -0
  24. package/dist/components/audio-player-components/TimeDisplay.d.ts +3 -0
  25. package/dist/components/audio-player-components/TimeDisplay.js +10 -0
  26. package/dist/components/audio-player-components/TitleScroller.d.ts +3 -0
  27. package/dist/components/audio-player-components/TitleScroller.js +8 -0
  28. package/dist/components/audio-player-components/__tests__/AudioPlayer.test.d.ts +1 -0
  29. package/dist/components/audio-player-components/__tests__/AudioPlayer.test.js +196 -0
  30. package/dist/components/audio-player-components/__tests__/CollapseIcon.test.d.ts +1 -0
  31. package/dist/components/audio-player-components/__tests__/CollapseIcon.test.js +44 -0
  32. package/dist/components/audio-player-components/__tests__/PlaybackControls.test.d.ts +1 -0
  33. package/dist/components/audio-player-components/__tests__/PlaybackControls.test.js +129 -0
  34. package/dist/components/audio-player-components/__tests__/SeekBar.test.d.ts +1 -0
  35. package/dist/components/audio-player-components/__tests__/SeekBar.test.js +60 -0
  36. package/dist/components/audio-player-components/__tests__/Styles.test.d.ts +1 -0
  37. package/dist/components/audio-player-components/__tests__/Styles.test.js +510 -0
  38. package/dist/components/audio-player-components/__tests__/TabletDesktopPlayer.test.d.ts +1 -0
  39. package/dist/components/audio-player-components/__tests__/TabletDesktopPlayer.test.js +199 -0
  40. package/dist/components/audio-player-components/__tests__/TimeDisplay.test.d.ts +1 -0
  41. package/dist/components/audio-player-components/__tests__/TimeDisplay.test.js +71 -0
  42. package/dist/components/audio-player-components/__tests__/TitleScroller.test.d.ts +1 -0
  43. package/dist/components/audio-player-components/__tests__/TitleScroller.test.js +47 -0
  44. package/dist/components/audio-player-components/__tests__/Utils.test.d.ts +1 -0
  45. package/dist/components/audio-player-components/__tests__/Utils.test.js +31 -0
  46. package/dist/components/audio-player-components/styles.d.ts +49 -0
  47. package/dist/components/audio-player-components/styles.js +568 -0
  48. package/dist/components/audio-player-components/types.d.ts +83 -0
  49. package/dist/components/audio-player-components/types.js +2 -0
  50. package/dist/components/audio-player-components/utils.d.ts +1 -0
  51. package/dist/components/audio-player-components/utils.js +6 -0
  52. package/dist/fixtures/analytics-actions/__tests__/AnalyticsActions.test.d.ts +1 -0
  53. package/dist/fixtures/analytics-actions/__tests__/AnalyticsActions.test.js +49 -0
  54. package/dist/index.d.ts +1 -0
  55. package/dist/index.js +2 -1
  56. package/jest.config.js +3 -3
  57. package/package.json +3 -3
  58. package/rnw.js +1 -1
  59. package/src/components/article-audio/ArticleAudio.stories.tsx +14 -0
  60. package/src/components/article-audio/ArticleAudio.tsx +93 -0
  61. package/src/components/article-audio/__tests__/ArticleAudio.test.tsx +192 -0
  62. package/src/components/article-audio/__tests__/Styles.test.tsx +61 -0
  63. package/src/components/article-audio/styles.ts +26 -0
  64. package/src/components/audio-player-components/AudioPlayer.stories.tsx +209 -0
  65. package/src/components/audio-player-components/AudioPlayer.tsx +324 -0
  66. package/src/components/audio-player-components/CollapseIcon.tsx +25 -0
  67. package/src/components/audio-player-components/PlaybackControls.tsx +104 -0
  68. package/src/components/audio-player-components/SeekBar.tsx +27 -0
  69. package/src/components/audio-player-components/TabletDesktopPlayer.tsx +157 -0
  70. package/src/components/audio-player-components/TimeDisplay.tsx +18 -0
  71. package/src/components/audio-player-components/TitleScroller.tsx +13 -0
  72. package/src/components/audio-player-components/__tests__/AudioPlayer.test.tsx +267 -0
  73. package/src/components/audio-player-components/__tests__/CollapseIcon.test.tsx +89 -0
  74. package/src/components/audio-player-components/__tests__/PlaybackControls.test.tsx +330 -0
  75. package/src/components/audio-player-components/__tests__/SeekBar.test.tsx +96 -0
  76. package/src/components/audio-player-components/__tests__/Styles.test.tsx +777 -0
  77. package/src/components/audio-player-components/__tests__/TabletDesktopPlayer.test.tsx +304 -0
  78. package/src/components/audio-player-components/__tests__/TimeDisplay.test.tsx +103 -0
  79. package/src/components/audio-player-components/__tests__/TitleScroller.test.tsx +60 -0
  80. package/src/components/audio-player-components/__tests__/Utils.test.tsx +37 -0
  81. package/src/components/audio-player-components/__tests__/__snapshots__/Styles.test.tsx.snap +3 -0
  82. package/src/components/audio-player-components/__tests__/__snapshots__/TitleScroller.test.tsx.snap +19 -0
  83. package/src/components/audio-player-components/styles.ts +631 -0
  84. package/src/components/audio-player-components/types.ts +90 -0
  85. package/src/components/audio-player-components/utils.ts +5 -0
  86. package/src/fixtures/analytics-actions/__tests__/AnalyticsActions.test.tsx +62 -0
  87. package/src/index.ts +1 -0
  88. package/src/types/externs.d.ts +9 -0
@@ -0,0 +1,631 @@
1
+ import styled, { createGlobalStyle } from 'styled-components';
2
+ import { breakpoints, colours, fonts } from '@times-components/ts-styleguide';
3
+
4
+ // Global Styles - box-sizing
5
+ export const GlobalStyle = createGlobalStyle`
6
+ *, *::before, *::after {
7
+ box-sizing: border-box;
8
+ }
9
+ `;
10
+
11
+ // Define thumbColor variable
12
+ const thumbColor = '#1573A2';
13
+
14
+ // Container
15
+ export const AudioPlayerContainer = styled.div<{
16
+ isExpanded: boolean;
17
+ isModalOpen: boolean;
18
+ }>`
19
+ position: fixed;
20
+ bottom: 0;
21
+ left: 0;
22
+ width: 100%;
23
+ height: ${({ isExpanded, isModalOpen }) => {
24
+ if (!isExpanded) {
25
+ return '48px';
26
+ }
27
+ return isModalOpen ? '370px' : '221px';
28
+ }};
29
+ background-color: ${colours.functional.white};
30
+ color: ${colours.functional.primary};
31
+ box-shadow: 0px -2px 4px 0px #0000001a;
32
+ border-top-left-radius: 10px;
33
+ border-top-right-radius: 10px;
34
+ transition: height 0.3s ease, transform 0.3s ease;
35
+ overflow: hidden;
36
+ display: flex;
37
+ flex-direction: column;
38
+ align-items: center;
39
+ padding: 16px;
40
+ transform: ${({ isExpanded }) =>
41
+ isExpanded ? 'translateY(0)' : 'translateY(calc(100% - 48px))'};
42
+
43
+ @media (max-width: ${breakpoints.small}) {
44
+ width: 100%;
45
+ }
46
+ `;
47
+
48
+ // Row
49
+ export const Row = styled.div`
50
+ width: 100%;
51
+ display: flex;
52
+ justify-content: center;
53
+ align-items: center;
54
+ `;
55
+
56
+ // Collapse Button
57
+ export const CollapseButton = styled.button`
58
+ background: none;
59
+ border: none;
60
+ cursor: pointer;
61
+ padding: 0;
62
+ `;
63
+
64
+ // Title Scroller
65
+ export const Title = styled.div`
66
+ font-family: ${fonts.supporting};
67
+ font-size: 16px;
68
+ font-weight: 700;
69
+ text-align: center;
70
+ white-space: nowrap;
71
+ overflow: hidden;
72
+ position: relative;
73
+ width: 90%;
74
+ margin-top: 16px;
75
+
76
+ & > div {
77
+ display: inline-block;
78
+ padding-left: 100%;
79
+ animation: scroll 10s linear infinite;
80
+ }
81
+
82
+ @keyframes scroll {
83
+ 0% {
84
+ transform: translateX(0);
85
+ }
86
+ 100% {
87
+ transform: translateX(-100%);
88
+ }
89
+ }
90
+ `;
91
+
92
+ // Seek Bar
93
+ interface StyledSeekBarProps {
94
+ progress: number;
95
+ }
96
+
97
+ export const StyledSeekBar = styled.input<StyledSeekBarProps>`
98
+ width: 90%;
99
+ height: 4px;
100
+ border-radius: 2px;
101
+ background: ${({ progress }) =>
102
+ `linear-gradient(to right, ${thumbColor} 0%, ${thumbColor} ${progress}%, ${
103
+ colours.functional.whiteGrey
104
+ } ${progress}%, ${colours.functional.whiteGrey} 100%)`};
105
+ outline: none;
106
+ appearance: none;
107
+ margin: 16px 0 6px 0;
108
+
109
+ &::-webkit-slider-thumb {
110
+ appearance: none;
111
+ width: 16px;
112
+ height: 16px;
113
+ border-radius: 50%;
114
+ background: ${thumbColor};
115
+ cursor: pointer;
116
+ border: 1px solid ${thumbColor};
117
+ margin-top: -6px;
118
+ transition: background 0.3s ease;
119
+ }
120
+
121
+ &::-moz-range-thumb {
122
+ width: 16px;
123
+ height: 16px;
124
+ border-radius: 50%;
125
+ background: ${thumbColor};
126
+ cursor: pointer;
127
+ border: 1px solid ${thumbColor};
128
+ transition: background 0.3s ease;
129
+ }
130
+
131
+ &::-webkit-slider-runnable-track {
132
+ height: 4px;
133
+ background: transparent;
134
+ border: none;
135
+ }
136
+
137
+ &::-moz-range-track {
138
+ height: 4px;
139
+ background: transparent;
140
+ border: none;
141
+ }
142
+
143
+ &:disabled {
144
+ opacity: 0.5;
145
+ cursor: not-allowed;
146
+ }
147
+ `;
148
+
149
+ // Time Display
150
+ export const StyledTimeDisplay = styled.div`
151
+ font-family: ${fonts.supporting};
152
+ font-size: 14px;
153
+ font-weight: 500;
154
+ text-align: right;
155
+ width: 90%;
156
+ display: flex;
157
+ justify-content: space-between;
158
+ margin-top: 6px;
159
+ margin-bottom: 30px;
160
+ `;
161
+
162
+ // Controls Container
163
+ export const Controls = styled.div`
164
+ width: 90%;
165
+ display: flex;
166
+ justify-content: center;
167
+ align-items: center;
168
+ position: relative;
169
+
170
+ @media (max-width: ${breakpoints.small}) {
171
+ gap: 16px;
172
+ }
173
+ `;
174
+
175
+ // Playback Buttons Container
176
+ export const PlaybackButtonsContainer = styled.div`
177
+ display: flex;
178
+ justify-content: center;
179
+ align-items: center;
180
+ gap: 8px;
181
+ @media (min-width: ${breakpoints.small}) {
182
+ gap: 16px;
183
+ }
184
+ `;
185
+
186
+ // Control Button (Rewind and Forward)
187
+ export const ControlButton = styled.button`
188
+ background: none;
189
+ border: none;
190
+ cursor: pointer;
191
+ padding: 0;
192
+
193
+ svg {
194
+ width: 24px;
195
+ height: 24px;
196
+ fill: ${colours.functional.primary};
197
+ }
198
+
199
+ &:disabled {
200
+ opacity: 0.5;
201
+ cursor: not-allowed;
202
+ }
203
+ `;
204
+
205
+ // Play/Pause Button
206
+ export const PlayPauseButton = styled.button`
207
+ width: 48px;
208
+ height: 48px;
209
+ border: none;
210
+ border-radius: 50%;
211
+ background-color: #01000d;
212
+ display: flex;
213
+ justify-content: center;
214
+ align-items: center;
215
+ cursor: pointer;
216
+ padding: 0;
217
+ position: relative;
218
+
219
+ &:hover {
220
+ background-color: #02020f;
221
+ }
222
+
223
+ &:disabled {
224
+ opacity: 0.5;
225
+ cursor: not-allowed;
226
+ }
227
+
228
+ svg {
229
+ width: 24px;
230
+ height: 24px;
231
+ position: absolute;
232
+ }
233
+ `;
234
+
235
+ // Speed Button
236
+ export const SpeedButton = styled.button`
237
+ background: none;
238
+ border: 1px solid ${colours.functional.primary};
239
+ cursor: pointer;
240
+ font-family: ${fonts.supporting};
241
+ font-size: 14px;
242
+ font-weight: 500;
243
+ color: ${colours.functional.primary};
244
+ margin-left: 16px;
245
+ position: absolute;
246
+ right: -10px;
247
+ padding: 8px 16px;
248
+
249
+ @media (min-width: ${breakpoints.small}) {
250
+ position: absolute;
251
+ right: 0;
252
+ margin-left: 0;
253
+ }
254
+
255
+ &:hover {
256
+ background-color: ${colours.functional.border};
257
+ }
258
+
259
+ &:disabled {
260
+ opacity: 0.5;
261
+ cursor: not-allowed;
262
+ }
263
+ `;
264
+
265
+ // Speed Select Modal
266
+ export const SpeedSelectModal = styled.div<{ isMobile?: boolean }>`
267
+ background: ${colours.functional.white};
268
+ z-index: 1000;
269
+ display: flex;
270
+ flex-direction: column;
271
+ overflow: hidden;
272
+
273
+ ${({ isMobile }) =>
274
+ isMobile
275
+ ? `
276
+ position: absolute;
277
+ top: 40px;
278
+ left: 0;
279
+ width: 100%;
280
+ height: calc(100% - 40px);
281
+ border: none;
282
+ padding: 16px;
283
+ `
284
+ : `
285
+ position: absolute;
286
+ bottom: calc(100% + 18px);
287
+ left: 50%;
288
+ transform: translateX(-50%);
289
+ width: 160px;
290
+ height: 256px;
291
+ border: 1px solid ${colours.functional.greyLabel};
292
+ padding: 16px 0px;
293
+ box-shadow: 0px 20px 32px 0px #0A0A0A14;
294
+ overflow: unset;
295
+
296
+ &::after {
297
+ content: '';
298
+ position: absolute;
299
+ top: 100%;
300
+ left: 50%;
301
+ transform: translateX(-50%);
302
+ border-width: 16px 16px 0 16px;
303
+ border-style: solid;
304
+ border-color: ${
305
+ colours.functional.white
306
+ } transparent transparent transparent;
307
+ width: 0;
308
+ height: 0;
309
+ }
310
+ `};
311
+ `;
312
+
313
+ // Speed Options Container
314
+ export const SpeedOptionsContainer = styled.div`
315
+ flex: 1;
316
+ width: 100%;
317
+ display: flex;
318
+ flex-direction: column;
319
+ align-items: center;
320
+ `;
321
+
322
+ // Speed Option Item
323
+ export const SpeedOptionItem = styled.div<{
324
+ selected: boolean;
325
+ isMobile?: boolean;
326
+ }>`
327
+ display: flex;
328
+ justify-content: space-between;
329
+ align-items: center;
330
+ background: ${({ selected }) =>
331
+ selected ? colours.functional.bannerBackground : 'transparent'};
332
+ padding: 8px 12px;
333
+ cursor: pointer;
334
+ width: ${({ isMobile }) => (isMobile ? '80%;' : '100%')};
335
+ font-family: ${fonts.supporting};
336
+ font-size: 16px;
337
+ font-weight: 500;
338
+ color: ${({ selected }) =>
339
+ selected ? colours.functional.brandColour : colours.functional.secondary};
340
+
341
+ svg {
342
+ width: 20px;
343
+ height: 20px;
344
+ fill: ${colours.functional.brandColour};
345
+ }
346
+
347
+ &:hover {
348
+ background: ${({ selected }) =>
349
+ selected
350
+ ? colours.functional.bannerBackground
351
+ : colours.functional.border};
352
+ }
353
+ `;
354
+
355
+ // Close Button in Modal
356
+ export const CloseButton = styled.button`
357
+ background: none;
358
+ border: none;
359
+ cursor: pointer;
360
+ font-family: ${fonts.supporting};
361
+ font-size: 16px;
362
+ font-weight: 500;
363
+ color: ${colours.functional.primary};
364
+ padding: 12px 0;
365
+ align-self: center;
366
+
367
+ &:hover {
368
+ text-decoration: underline;
369
+ }
370
+ `;
371
+
372
+ // Volume Control
373
+ export const VolumeControlContainer = styled.div`
374
+ display: flex;
375
+ align-items: center;
376
+ width: 90%;
377
+ padding: 5px 0;
378
+ `;
379
+
380
+ // Volume Label
381
+ export const VolumeLabel = styled.label`
382
+ margin-right: 10px;
383
+ font-family: ${fonts.supporting};
384
+ font-size: 14px;
385
+ font-weight: 500;
386
+ `;
387
+
388
+ // Volume Slider
389
+ export const VolumeSlider = styled.input`
390
+ width: 100%;
391
+ height: 4px;
392
+ border-radius: 2px;
393
+ background: ${colours.functional.whiteGrey};
394
+ outline: none;
395
+ appearance: none;
396
+
397
+ &::-webkit-slider-thumb {
398
+ appearance: none;
399
+ width: 16px;
400
+ height: 16px;
401
+ border-radius: 50%;
402
+ background: ${thumbColor};
403
+ cursor: pointer;
404
+ border: 1px solid ${thumbColor};
405
+ margin-top: -6px;
406
+ }
407
+
408
+ &::-moz-range-thumb {
409
+ width: 16px;
410
+ height: 16px;
411
+ border-radius: 50%;
412
+ background: ${thumbColor};
413
+ cursor: pointer;
414
+ border: 1px solid ${thumbColor};
415
+ }
416
+
417
+ &::-webkit-slider-runnable-track {
418
+ height: 4px;
419
+ background: ${colours.functional.whiteGrey};
420
+ border: none;
421
+ }
422
+
423
+ &::-moz-range-track {
424
+ height: 4px;
425
+ background: ${colours.functional.whiteGrey};
426
+ border: none;
427
+ }
428
+ `;
429
+
430
+ // Tablet/Desktop Wrapper
431
+ export const TabletDesktopWrapper = styled.div`
432
+ width: 100%;
433
+ padding: 16px 20px;
434
+ position: fixed;
435
+ bottom: 0;
436
+ left: 0;
437
+ background-color: ${colours.functional.white};
438
+ box-shadow: 0px -2px 4px 0px #0000001a;
439
+ display: flex;
440
+ align-items: center;
441
+ justify-content: center;
442
+ z-index: 1000;
443
+ `;
444
+
445
+ // Inner Wrapper
446
+ export const TabletDesktopInnerWrapper = styled.div`
447
+ max-width: 1440px;
448
+ margin: 0 auto;
449
+ width: 100%;
450
+ display: flex;
451
+ align-items: center;
452
+ justify-content: space-between;
453
+ `;
454
+
455
+ // Left Controls
456
+ export const LeftControls = styled.div`
457
+ display: flex;
458
+ align-items: center;
459
+ `;
460
+
461
+ // Center Controls
462
+ export const CenterControls = styled.div`
463
+ display: flex;
464
+ align-items: center;
465
+ flex-grow: 1;
466
+ margin: 0 16px;
467
+ `;
468
+
469
+ // Right Controls
470
+ export const RightControls = styled.div`
471
+ display: flex;
472
+ align-items: center;
473
+ `;
474
+
475
+ // Tablet/Desktop Play/Pause Button
476
+ export const TabletDesktopPlayPauseButton = styled.button`
477
+ background: none;
478
+ border: none;
479
+ cursor: pointer;
480
+ padding: 0 8px;
481
+
482
+ svg {
483
+ width: 32px;
484
+ height: 32px;
485
+ fill: ${colours.functional.primary};
486
+ }
487
+ `;
488
+
489
+ // Tablet/Desktop Status Text
490
+ export const TabletDesktopStatusText = styled.span`
491
+ font-family: ${fonts.supporting};
492
+ font-size: 16px;
493
+ font-weight: 500;
494
+ margin: 0 16px;
495
+ `;
496
+
497
+ // Tablet/Desktop Volume Control
498
+ export const TabletDesktopVolumeControlContainer = styled.div`
499
+ display: flex;
500
+ align-items: center;
501
+ margin: 0 16px;
502
+ `;
503
+
504
+ export const TabletDesktopVolumeButton = styled.button`
505
+ background: none;
506
+ border: none;
507
+ cursor: pointer;
508
+ padding: 0 8px;
509
+
510
+ svg {
511
+ width: 24px;
512
+ height: 24px;
513
+ fill: ${colours.functional.primary};
514
+ }
515
+ `;
516
+
517
+ export const TabletDesktopVolumeSlider = styled.input`
518
+ width: 100px;
519
+ margin-left: 8px;
520
+ height: 4px;
521
+ background: ${colours.functional.whiteGrey};
522
+ outline: none;
523
+ appearance: none;
524
+
525
+ &::-webkit-slider-thumb {
526
+ appearance: none;
527
+ width: 12px;
528
+ height: 12px;
529
+ background: ${thumbColor};
530
+ cursor: pointer;
531
+ border-radius: 50%;
532
+ border: 1px solid ${thumbColor};
533
+ margin-top: -4px;
534
+ }
535
+ `;
536
+
537
+ // Tablet/Desktop Time Display
538
+ export const TabletDesktopTimeDisplay = styled.div`
539
+ display: flex;
540
+ align-items: center;
541
+ font-family: ${fonts.supporting};
542
+ font-size: 14px;
543
+ font-weight: 500;
544
+
545
+ span {
546
+ margin: 0 4px;
547
+ }
548
+ `;
549
+
550
+ // Tablet/Desktop Seek Bar
551
+ interface TabletDesktopSeekBarProps {
552
+ progress: number;
553
+ }
554
+
555
+ export const TabletDesktopSeekBar = styled.input<TabletDesktopSeekBarProps>`
556
+ flex-grow: 1;
557
+ height: 4px;
558
+ background: ${({ progress }) =>
559
+ `linear-gradient(to right, ${thumbColor} 0%, ${thumbColor} ${progress}%, ${
560
+ colours.functional.whiteGrey
561
+ } ${progress}%, ${colours.functional.whiteGrey} 100%)`};
562
+ outline: none;
563
+ appearance: none;
564
+ margin: 0 8px;
565
+
566
+ &::-webkit-slider-thumb {
567
+ appearance: none;
568
+ width: 12px;
569
+ height: 12px;
570
+ background: ${thumbColor};
571
+ cursor: pointer;
572
+ border-radius: 50%;
573
+ border: 1px solid ${thumbColor};
574
+ margin-top: -4px;
575
+ }
576
+
577
+ &::-moz-range-thumb {
578
+ width: 12px;
579
+ height: 12px;
580
+ background: ${thumbColor};
581
+ cursor: pointer;
582
+ border-radius: 50%;
583
+ border: 1px solid ${thumbColor};
584
+ }
585
+
586
+ &:disabled {
587
+ opacity: 0.5;
588
+ cursor: not-allowed;
589
+ }
590
+ `;
591
+
592
+ // Tablet/Desktop Speed Button
593
+ export const TabletDesktopSpeedButton = styled.button`
594
+ background: none;
595
+ border: 1px solid ${colours.functional.primary};
596
+ cursor: pointer;
597
+ font-family: ${fonts.supporting};
598
+ font-size: 14px;
599
+ font-weight: 500;
600
+ color: ${colours.functional.primary};
601
+ padding: 8px 16px;
602
+ margin: 0 16px;
603
+
604
+ &:hover {
605
+ background-color: ${colours.functional.border};
606
+ }
607
+
608
+ &:disabled {
609
+ opacity: 0.5;
610
+ cursor: not-allowed;
611
+ }
612
+ `;
613
+
614
+ // Speed Button Container
615
+ export const SpeedButtonContainer = styled.div`
616
+ position: relative;
617
+ `;
618
+
619
+ // Tablet/Desktop Close Button
620
+ export const TabletDesktopCloseButton = styled.button`
621
+ background: none;
622
+ border: none;
623
+ cursor: pointer;
624
+ padding: 0 8px;
625
+
626
+ svg {
627
+ width: 24px;
628
+ height: 24px;
629
+ fill: ${colours.functional.primary};
630
+ }
631
+ `;
@@ -0,0 +1,90 @@
1
+ export interface StickyAudioPlayerProps {
2
+ src: string;
3
+ title?: string;
4
+ autoPlay?: boolean;
5
+ initialVolume?: number;
6
+ playbackRate?: number;
7
+ isPlayingProp?: boolean;
8
+ isExpandedProp?: boolean;
9
+ allowTogglePlay?: boolean;
10
+ allowSeek?: boolean;
11
+ allowVolumeChange?: boolean;
12
+ allowPlaybackRateChange?: boolean;
13
+ allowExpandCollapse?: boolean;
14
+ onPlay?: () => void;
15
+ onPause?: () => void;
16
+ onEnded?: () => void;
17
+ onTimeUpdate?: (currentTime: number) => void;
18
+ onVolumeChange?: (volume: number) => void;
19
+ onPlaybackRateChange?: (rate: number) => void;
20
+ onSeek?: (time: number) => void;
21
+ onClose?: () => void;
22
+ }
23
+
24
+ export interface CollapseIconProps {
25
+ isExpanded: boolean;
26
+ toggleExpand: () => void;
27
+ allowExpandCollapse: boolean;
28
+ }
29
+
30
+ export interface TitleScrollerProps {
31
+ title: string;
32
+ }
33
+
34
+ export interface SeekBarProps {
35
+ currentTime: number;
36
+ duration: number;
37
+ onSeek: (time: number) => void;
38
+ allowSeek: boolean;
39
+ }
40
+
41
+ export interface TimeDisplayProps {
42
+ currentTime: number;
43
+ duration: number;
44
+ }
45
+
46
+ export interface PlaybackControlsProps {
47
+ isPlaying: boolean;
48
+ togglePlayPause: () => void;
49
+ rewind: () => void;
50
+ forward: () => void;
51
+ speed: number;
52
+ onSpeedChange: (rate: number) => void;
53
+ allowTogglePlay: boolean;
54
+ allowSeek: boolean;
55
+ allowPlaybackRateChange: boolean;
56
+ isSpeedModalOpen: boolean;
57
+ setIsSpeedModalOpen: (open: boolean) => void;
58
+ isMobile?: boolean;
59
+ }
60
+
61
+ export interface TabletDesktopPlayerProps {
62
+ audioRef: React.RefObject<HTMLAudioElement>;
63
+ isPlaying: boolean;
64
+ togglePlayPause: () => void;
65
+ currentTime: number;
66
+ duration: number;
67
+ allowTogglePlay: boolean;
68
+ allowSeek: boolean;
69
+ allowVolumeChange: boolean;
70
+ volume: number;
71
+ setVolume: (volume: number) => void;
72
+ handleSeek: (time: number) => void;
73
+ handleVolumeChange: (volume: number) => void;
74
+ speed: number;
75
+ handleSpeedChange: (rate: number) => void;
76
+ allowPlaybackRateChange: boolean;
77
+ isSpeedModalOpen: boolean;
78
+ setIsSpeedModalOpen: (open: boolean) => void;
79
+ speedOptions: number[];
80
+ handleSpeedSelect: (speed: number) => void;
81
+ isVolumeSliderVisible: boolean;
82
+ setIsVolumeSliderVisible: (visible: boolean) => void;
83
+ onClose?: () => void;
84
+ allowExpandCollapse?: boolean;
85
+ isMobile?: boolean;
86
+ }
87
+
88
+ export interface AudioPlayerHandle {
89
+ parentControlToggle: () => void;
90
+ }
@@ -0,0 +1,5 @@
1
+ export const formatTime = (seconds: number): string => {
2
+ const mins = Math.floor(seconds / 60);
3
+ const secs = Math.floor(seconds % 60);
4
+ return `${mins}:${secs < 10 ? '0' : ''}${secs}`;
5
+ };