@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
package/CHANGELOG.md CHANGED
@@ -3,6 +3,14 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [1.112.1](https://github.com/newsuk/times-components/compare/@times-components/ts-components@1.112.0...@times-components/ts-components@1.112.1) (2024-12-03)
7
+
8
+ **Note:** Version bump only for package @times-components/ts-components
9
+
10
+
11
+
12
+
13
+
6
14
  # [1.112.0](https://github.com/newsuk/times-components/compare/@times-components/ts-components@1.111.0...@times-components/ts-components@1.112.0) (2024-12-02)
7
15
 
8
16
 
@@ -0,0 +1,6 @@
1
+ import { FC } from 'react';
2
+ export interface ArticleAudioProps {
3
+ audioSrc: string;
4
+ }
5
+ export declare const ArticleAudio: FC<ArticleAudioProps>;
6
+ export default ArticleAudio;
@@ -0,0 +1,51 @@
1
+ import React, { useState, useRef } from 'react';
2
+ import { AudioButton } from './styles';
3
+ import { AudioPlayer } from '../audio-player-components/AudioPlayer';
4
+ import { PlayIcon, PauseIcon } from '@times-components/icons';
5
+ export const ArticleAudio = ({ audioSrc }) => {
6
+ const [audioState, setAudioState] = useState('not-started');
7
+ const [isAudioPlayerVisible, setisAudioPlayerVisible] = useState(false);
8
+ const [duration, setDuration] = useState(null);
9
+ const audioRef = useRef(null);
10
+ const handleLoadedMetadata = () => {
11
+ if (audioRef.current) {
12
+ const totalSeconds = Math.floor(audioRef.current.duration);
13
+ const minutes = Math.floor(totalSeconds / 60) + 1;
14
+ setDuration(`${minutes}`);
15
+ }
16
+ };
17
+ const handlePlayPause = () => {
18
+ setisAudioPlayerVisible(true);
19
+ if (audioState === 'playing') {
20
+ setAudioState('paused');
21
+ }
22
+ else {
23
+ setAudioState('playing');
24
+ }
25
+ };
26
+ const hidePlayer = () => {
27
+ setisAudioPlayerVisible(false);
28
+ };
29
+ return (React.createElement("div", null,
30
+ React.createElement("audio", { ref: audioRef, src: audioSrc, onLoadedMetadata: handleLoadedMetadata, preload: "metadata" }),
31
+ React.createElement(AudioButton, { onClick: handlePlayPause, style: {
32
+ backgroundColor: audioState !== 'not-started' ? '#1D1D1B' : 'unset',
33
+ color: audioState === 'not-started' ? '#333' : '#fff'
34
+ } },
35
+ audioState === 'playing' ? (React.createElement(React.Fragment, null,
36
+ React.createElement(PauseIcon, { width: 16, height: 16, fill: "#fff" }),
37
+ " Playing")) : audioState === 'paused' ? (React.createElement(React.Fragment, null,
38
+ React.createElement(PlayIcon, { width: 16, height: 16, fill: "#fff" }),
39
+ " Paused")) : (React.createElement(React.Fragment, null,
40
+ React.createElement(PlayIcon, { width: 16, height: 16 }),
41
+ " Listen")),
42
+ React.createElement("span", { style: {
43
+ color: audioState === 'not-started' ? '#696969' : '#fff'
44
+ } },
45
+ ' ',
46
+ duration,
47
+ " min")),
48
+ isAudioPlayerVisible && (React.createElement(AudioPlayer, { src: audioSrc, isPlayingProp: audioState === 'playing', onPlay: () => setAudioState('playing'), onPause: () => setAudioState('paused'), onEnded: () => setAudioState('not-started'), onClose: () => hidePlayer() }))));
49
+ };
50
+ export default ArticleAudio;
51
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQXJ0aWNsZUF1ZGlvLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2NvbXBvbmVudHMvYXJ0aWNsZS1hdWRpby9BcnRpY2xlQXVkaW8udHN4Il0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxFQUFFLEVBQU0sUUFBUSxFQUFFLE1BQU0sRUFBRSxNQUFNLE9BQU8sQ0FBQztBQUNwRCxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sVUFBVSxDQUFDO0FBQ3ZDLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSx3Q0FBd0MsQ0FBQztBQUNyRSxPQUFPLEVBQUUsUUFBUSxFQUFFLFNBQVMsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBSzlELE1BQU0sQ0FBQyxNQUFNLFlBQVksR0FBMEIsQ0FBQyxFQUFFLFFBQVEsRUFBRSxFQUFFLEVBQUU7SUFDbEUsTUFBTSxDQUFDLFVBQVUsRUFBRSxhQUFhLENBQUMsR0FBRyxRQUFRLENBRTFDLGFBQWEsQ0FBQyxDQUFDO0lBQ2pCLE1BQU0sQ0FBQyxvQkFBb0IsRUFBRSx1QkFBdUIsQ0FBQyxHQUFHLFFBQVEsQ0FDOUQsS0FBSyxDQUNOLENBQUM7SUFDRixNQUFNLENBQUMsUUFBUSxFQUFFLFdBQVcsQ0FBQyxHQUFHLFFBQVEsQ0FBZ0IsSUFBSSxDQUFDLENBQUM7SUFFOUQsTUFBTSxRQUFRLEdBQUcsTUFBTSxDQUEwQixJQUFJLENBQUMsQ0FBQztJQUV2RCxNQUFNLG9CQUFvQixHQUFHLEdBQUcsRUFBRTtRQUNoQyxJQUFJLFFBQVEsQ0FBQyxPQUFPLEVBQUU7WUFDcEIsTUFBTSxZQUFZLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxDQUFDO1lBQzNELE1BQU0sT0FBTyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsWUFBWSxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsQ0FBQztZQUNsRCxXQUFXLENBQUMsR0FBRyxPQUFPLEVBQUUsQ0FBQyxDQUFDO1NBQzNCO0lBQ0gsQ0FBQyxDQUFDO0lBRUYsTUFBTSxlQUFlLEdBQUcsR0FBRyxFQUFFO1FBQzNCLHVCQUF1QixDQUFDLElBQUksQ0FBQyxDQUFDO1FBRTlCLElBQUksVUFBVSxLQUFLLFNBQVMsRUFBRTtZQUM1QixhQUFhLENBQUMsUUFBUSxDQUFDLENBQUM7U0FDekI7YUFBTTtZQUNMLGFBQWEsQ0FBQyxTQUFTLENBQUMsQ0FBQztTQUMxQjtJQUNILENBQUMsQ0FBQztJQUVGLE1BQU0sVUFBVSxHQUFHLEdBQUcsRUFBRTtRQUN0Qix1QkFBdUIsQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUNqQyxDQUFDLENBQUM7SUFFRixPQUFPLENBQ0w7UUFDRSwrQkFDRSxHQUFHLEVBQUUsUUFBUSxFQUNiLEdBQUcsRUFBRSxRQUFRLEVBQ2IsZ0JBQWdCLEVBQUUsb0JBQW9CLEVBQ3RDLE9BQU8sRUFBQyxVQUFVLEdBQ2xCO1FBQ0Ysb0JBQUMsV0FBVyxJQUNWLE9BQU8sRUFBRSxlQUFlLEVBQ3hCLEtBQUssRUFBRTtnQkFDTCxlQUFlLEVBQUUsVUFBVSxLQUFLLGFBQWEsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxPQUFPO2dCQUNuRSxLQUFLLEVBQUUsVUFBVSxLQUFLLGFBQWEsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxNQUFNO2FBQ3REO1lBRUEsVUFBVSxLQUFLLFNBQVMsQ0FBQyxDQUFDLENBQUMsQ0FDMUI7Z0JBQ0Usb0JBQUMsU0FBUyxJQUFDLEtBQUssRUFBRSxFQUFFLEVBQUUsTUFBTSxFQUFFLEVBQUUsRUFBRSxJQUFJLEVBQUMsTUFBTSxHQUFHOzJCQUMvQyxDQUNKLENBQUMsQ0FBQyxDQUFDLFVBQVUsS0FBSyxRQUFRLENBQUMsQ0FBQyxDQUFDLENBQzVCO2dCQUNFLG9CQUFDLFFBQVEsSUFBQyxLQUFLLEVBQUUsRUFBRSxFQUFFLE1BQU0sRUFBRSxFQUFFLEVBQUUsSUFBSSxFQUFDLE1BQU0sR0FBRzswQkFDOUMsQ0FDSixDQUFDLENBQUMsQ0FBQyxDQUNGO2dCQUNFLG9CQUFDLFFBQVEsSUFBQyxLQUFLLEVBQUUsRUFBRSxFQUFFLE1BQU0sRUFBRSxFQUFFLEdBQUk7MEJBQ2xDLENBQ0o7WUFDRCw4QkFDRSxLQUFLLEVBQUU7b0JBQ0wsS0FBSyxFQUFFLFVBQVUsS0FBSyxhQUFhLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsTUFBTTtpQkFDekQ7Z0JBRUEsR0FBRztnQkFDSCxRQUFRO3VCQUNKLENBQ0s7UUFDYixvQkFBb0IsSUFBSSxDQUN2QixvQkFBQyxXQUFXLElBQ1YsR0FBRyxFQUFFLFFBQVEsRUFDYixhQUFhLEVBQUUsVUFBVSxLQUFLLFNBQVMsRUFDdkMsTUFBTSxFQUFFLEdBQUcsRUFBRSxDQUFDLGFBQWEsQ0FBQyxTQUFTLENBQUMsRUFDdEMsT0FBTyxFQUFFLEdBQUcsRUFBRSxDQUFDLGFBQWEsQ0FBQyxRQUFRLENBQUMsRUFDdEMsT0FBTyxFQUFFLEdBQUcsRUFBRSxDQUFDLGFBQWEsQ0FBQyxhQUFhLENBQUMsRUFDM0MsT0FBTyxFQUFFLEdBQUcsRUFBRSxDQUFDLFVBQVUsRUFBRSxHQUMzQixDQUNILENBQ0csQ0FDUCxDQUFDO0FBQ0osQ0FBQyxDQUFDO0FBRUYsZUFBZSxZQUFZLENBQUMifQ==
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ import { storiesOf } from '@storybook/react';
3
+ import { ArticleAudio } from './ArticleAudio';
4
+ storiesOf('Typescript Component/Article Audio', module).add('Article Audio', () => {
5
+ return (React.createElement("div", { style: { padding: '10px' } },
6
+ React.createElement(ArticleAudio, { audioSrc: "https://www.kozco.com/tech/LRMonoPhase4.mp3" })));
7
+ });
8
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQXJ0aWNsZUF1ZGlvLnN0b3JpZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvY29tcG9uZW50cy9hcnRpY2xlLWF1ZGlvL0FydGljbGVBdWRpby5zdG9yaWVzLnRzeCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssTUFBTSxPQUFPLENBQUM7QUFDMUIsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBQzdDLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUU5QyxTQUFTLENBQUMsb0NBQW9DLEVBQUUsTUFBTSxDQUFDLENBQUMsR0FBRyxDQUN6RCxlQUFlLEVBQ2YsR0FBRyxFQUFFO0lBQ0gsT0FBTyxDQUNMLDZCQUFLLEtBQUssRUFBRSxFQUFFLE9BQU8sRUFBRSxNQUFNLEVBQUU7UUFDN0Isb0JBQUMsWUFBWSxJQUFDLFFBQVEsRUFBQyw2Q0FBNkMsR0FBRyxDQUNuRSxDQUNQLENBQUM7QUFDSixDQUFDLENBQ0YsQ0FBQyJ9
@@ -0,0 +1 @@
1
+ import '@testing-library/jest-dom/extend-expect';
@@ -0,0 +1,129 @@
1
+ import React from 'react';
2
+ import { render, fireEvent, act } from '@testing-library/react';
3
+ import '@testing-library/jest-dom/extend-expect';
4
+ import { ArticleAudio } from '../ArticleAudio';
5
+ jest.mock('../styles', () => ({
6
+ AudioButton: ({ children, onClick, style }) => (React.createElement("button", { "data-testid": "audio-button", onClick: onClick, style: style }, children))
7
+ }));
8
+ jest.mock('@times-components/icons', () => ({
9
+ __esModule: true,
10
+ PlayIcon: ({ color }) => (React.createElement("svg", { "data-testid": "play-icon", style: { color: color || '#333' } })),
11
+ PauseIcon: ({ color }) => (React.createElement("svg", { "data-testid": "pause-icon", style: { color: color || '#333' } }))
12
+ }));
13
+ jest.mock('../../audio-player-components/AudioPlayer', () => ({
14
+ AudioPlayer: ({ onPlay, onPause, onEnded, onClose }) => (React.createElement("div", { "data-testid": "audio-player" },
15
+ React.createElement("button", { onClick: onPlay }, "Play"),
16
+ React.createElement("button", { onClick: onPause }, "Pause"),
17
+ React.createElement("button", { onClick: onEnded }, "Ended"),
18
+ React.createElement("button", { onClick: onClose }, "Close")))
19
+ }));
20
+ describe('ArticleAudio', () => {
21
+ beforeEach(() => {
22
+ // Mock the duration of the audio element
23
+ Object.defineProperty(HTMLMediaElement.prototype, 'duration', {
24
+ get() {
25
+ return 120; // 2 minutes
26
+ }
27
+ });
28
+ });
29
+ afterEach(() => {
30
+ jest.clearAllMocks();
31
+ });
32
+ test('renders audio button with correct initial state', () => {
33
+ const { getByTestId, getByText, container } = render(React.createElement(ArticleAudio, { audioSrc: "https://www.kozco.com/tech/LRMonoPhase4.mp3" }));
34
+ // Trigger the 'loadedmetadata' event to set the duration
35
+ const audio = container.querySelector('audio');
36
+ act(() => {
37
+ fireEvent.loadedMetadata(audio);
38
+ });
39
+ const audioButton = getByTestId('audio-button');
40
+ expect(audioButton).toBeInTheDocument();
41
+ expect(audioButton.style.backgroundColor).toBe('');
42
+ expect(audioButton).toHaveStyle('color: #333');
43
+ // The initial state should display 'Listen' and the duration
44
+ expect(getByText('Listen')).toBeInTheDocument();
45
+ expect(getByText('3 min')).toBeInTheDocument();
46
+ // Since audioState is 'not-started', duration color should be '#696969'
47
+ const durationSpan = getByText('3 min');
48
+ expect(durationSpan).toHaveStyle('color: #696969');
49
+ });
50
+ test('hides AudioPlayer when close button is clicked (using mocked AudioPlayer)', () => {
51
+ const { getByTestId, queryByTestId, container, getByText } = render(React.createElement(ArticleAudio, { audioSrc: "https://www.kozco.com/tech/LRMonoPhase4.mp3" }));
52
+ // Trigger the 'loadedmetadata' event to set the duration
53
+ const audio = container.querySelector('audio');
54
+ act(() => {
55
+ fireEvent.loadedMetadata(audio);
56
+ });
57
+ // Initially, the AudioPlayer should not be visible
58
+ expect(queryByTestId('audio-player')).not.toBeInTheDocument();
59
+ // Click the audio button to start playback
60
+ const audioButton = getByTestId('audio-button');
61
+ fireEvent.click(audioButton);
62
+ // The mocked AudioPlayer should now be visible
63
+ expect(getByTestId('audio-player')).toBeInTheDocument();
64
+ // Use the mocked Close button inside the AudioPlayer to close it
65
+ const closeButton = getByText('Close');
66
+ fireEvent.click(closeButton);
67
+ // The AudioPlayer should no longer be visible
68
+ expect(queryByTestId('audio-player')).not.toBeInTheDocument();
69
+ });
70
+ test('handles play and pause', () => {
71
+ const { getByTestId, getByText, container } = render(React.createElement(ArticleAudio, { audioSrc: "https://www.kozco.com/tech/LRMonoPhase4.mp3" }));
72
+ // Trigger the 'loadedmetadata' event to set the duration
73
+ const audio = container.querySelector('audio');
74
+ act(() => {
75
+ fireEvent.loadedMetadata(audio);
76
+ });
77
+ const audioButton = getByTestId('audio-button');
78
+ // Simulate clicking the play button
79
+ fireEvent.click(audioButton);
80
+ // Now, audioState should be 'playing'
81
+ expect(audioButton).toHaveStyle('background-color: #1D1D1B');
82
+ expect(audioButton).toHaveStyle('color: #fff');
83
+ expect(getByText('Playing')).toBeInTheDocument();
84
+ // Since audioState is 'playing', duration color should be '#fff'
85
+ const durationSpan = getByText('3 min');
86
+ expect(durationSpan).toHaveStyle('color: #fff');
87
+ // Simulate clicking the pause button
88
+ fireEvent.click(audioButton);
89
+ expect(getByText('Paused')).toBeInTheDocument();
90
+ expect(audioButton).toHaveStyle('background-color: #1D1D1B');
91
+ expect(audioButton).toHaveStyle('color: #fff');
92
+ // Simulate clicking the play button again
93
+ fireEvent.click(audioButton);
94
+ expect(getByText('Playing')).toBeInTheDocument();
95
+ });
96
+ test('shows AudioPlayer when audio is played', () => {
97
+ const { getByTestId, queryByTestId, container } = render(React.createElement(ArticleAudio, { audioSrc: "https://www.kozco.com/tech/LRMonoPhase4.mp3" }));
98
+ // Trigger the 'loadedmetadata' event to set the duration
99
+ const audio = container.querySelector('audio');
100
+ act(() => {
101
+ fireEvent.loadedMetadata(audio);
102
+ });
103
+ expect(queryByTestId('audio-player')).not.toBeInTheDocument();
104
+ const audioButton = getByTestId('audio-button');
105
+ fireEvent.click(audioButton);
106
+ expect(getByTestId('audio-player')).toBeInTheDocument();
107
+ });
108
+ test('updates audioState based on AudioPlayer callbacks', () => {
109
+ const { getByTestId, getByText, container } = render(React.createElement(ArticleAudio, { audioSrc: "https://www.kozco.com/tech/LRMonoPhase4.mp3" }));
110
+ // Trigger the 'loadedmetadata' event to set the duration
111
+ const audio = container.querySelector('audio');
112
+ act(() => {
113
+ fireEvent.loadedMetadata(audio);
114
+ });
115
+ const audioButton = getByTestId('audio-button');
116
+ fireEvent.click(audioButton); // Start playing
117
+ expect(getByText('Playing')).toBeInTheDocument();
118
+ const pauseButton = getByText('Pause');
119
+ fireEvent.click(pauseButton);
120
+ expect(getByText('Paused')).toBeInTheDocument();
121
+ const playButton = getByText('Play');
122
+ fireEvent.click(playButton);
123
+ expect(getByText('Playing')).toBeInTheDocument();
124
+ const endedButton = getByText('Ended');
125
+ fireEvent.click(endedButton);
126
+ expect(getByText('Listen')).toBeInTheDocument();
127
+ });
128
+ });
129
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQXJ0aWNsZUF1ZGlvLnRlc3QuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvY29tcG9uZW50cy9hcnRpY2xlLWF1ZGlvL19fdGVzdHNfXy9BcnRpY2xlQXVkaW8udGVzdC50c3giXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE1BQU0sT0FBTyxDQUFDO0FBQzFCLE9BQU8sRUFBRSxNQUFNLEVBQUUsU0FBUyxFQUFFLEdBQUcsRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBQ2hFLE9BQU8seUNBQXlDLENBQUM7QUFDakQsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBRS9DLElBQUksQ0FBQyxJQUFJLENBQUMsV0FBVyxFQUFFLEdBQUcsRUFBRSxDQUFDLENBQUM7SUFDNUIsV0FBVyxFQUFFLENBQUMsRUFBRSxRQUFRLEVBQUUsT0FBTyxFQUFFLEtBQUssRUFBTyxFQUFFLEVBQUUsQ0FBQyxDQUNsRCwrQ0FBb0IsY0FBYyxFQUFDLE9BQU8sRUFBRSxPQUFPLEVBQUUsS0FBSyxFQUFFLEtBQUssSUFDOUQsUUFBUSxDQUNGLENBQ1Y7Q0FDRixDQUFDLENBQUMsQ0FBQztBQUVKLElBQUksQ0FBQyxJQUFJLENBQUMseUJBQXlCLEVBQUUsR0FBRyxFQUFFLENBQUMsQ0FBQztJQUMxQyxVQUFVLEVBQUUsSUFBSTtJQUNoQixRQUFRLEVBQUUsQ0FBQyxFQUFFLEtBQUssRUFBTyxFQUFFLEVBQUUsQ0FBQyxDQUM1Qiw0Q0FBaUIsV0FBVyxFQUFDLEtBQUssRUFBRSxFQUFFLEtBQUssRUFBRSxLQUFLLElBQUksTUFBTSxFQUFFLEdBQUksQ0FDbkU7SUFDRCxTQUFTLEVBQUUsQ0FBQyxFQUFFLEtBQUssRUFBTyxFQUFFLEVBQUUsQ0FBQyxDQUM3Qiw0Q0FBaUIsWUFBWSxFQUFDLEtBQUssRUFBRSxFQUFFLEtBQUssRUFBRSxLQUFLLElBQUksTUFBTSxFQUFFLEdBQUksQ0FDcEU7Q0FDRixDQUFD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
@@ -0,0 +1,2 @@
1
+ import '@testing-library/jest-dom/extend-expect';
2
+ import 'jest-styled-components';
@@ -0,0 +1,45 @@
1
+ import React from 'react';
2
+ import { render } from '@testing-library/react';
3
+ import '@testing-library/jest-dom/extend-expect';
4
+ import 'jest-styled-components';
5
+ import { AudioButton } from '../styles';
6
+ describe('AudioButton', () => {
7
+ test('renders correctly with default styles', () => {
8
+ const { getByTestId } = render(React.createElement(AudioButton, { "data-testid": "audio-button" }, "Test Button"));
9
+ const button = getByTestId('audio-button');
10
+ expect(button).toHaveStyleRule('background-color', 'unset');
11
+ expect(button).toHaveStyleRule('border-radius', '0');
12
+ expect(button).toHaveStyleRule('padding', '7px 11px');
13
+ expect(button).toHaveStyleRule('border', '1px solid #333333');
14
+ expect(button).toHaveStyleRule('display', 'flex');
15
+ expect(button).toHaveStyleRule('align-items', 'center');
16
+ expect(button).toHaveStyleRule('color', '#333333');
17
+ expect(button).toHaveStyleRule('font-family', 'Roboto');
18
+ expect(button).toHaveStyleRule('font-weight', '500');
19
+ expect(button).toHaveStyleRule('font-size', '14px');
20
+ expect(button).toHaveStyleRule('line-height', '18px');
21
+ });
22
+ test('renders svg child with correct styles', () => {
23
+ const { getByTestId } = render(React.createElement(AudioButton, { "data-testid": "audio-button" },
24
+ React.createElement("svg", { "data-testid": "icon" })));
25
+ const button = getByTestId('audio-button');
26
+ expect(button).toHaveStyleRule('margin-right', '8px', {
27
+ modifier: 'svg'
28
+ });
29
+ });
30
+ test('renders span child with correct styles', () => {
31
+ const { getByTestId } = render(React.createElement(AudioButton, { "data-testid": "audio-button" },
32
+ React.createElement("span", { "data-testid": "span" }, "Test Span")));
33
+ const button = getByTestId('audio-button');
34
+ expect(button).toHaveStyleRule('margin-left', '4px', {
35
+ modifier: 'span'
36
+ });
37
+ expect(button).toHaveStyleRule('font-size', '12px', {
38
+ modifier: 'span'
39
+ });
40
+ expect(button).toHaveStyleRule('color', '#696969', {
41
+ modifier: 'span'
42
+ });
43
+ });
44
+ });
45
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiU3R5bGVzLnRlc3QuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvY29tcG9uZW50cy9hcnRpY2xlLWF1ZGlvL19fdGVzdHNfXy9TdHlsZXMudGVzdC50c3giXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE1BQU0sT0FBTyxDQUFDO0FBQzFCLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUNoRCxPQUFPLHlDQUF5QyxDQUFDO0FBQ2pELE9BQU8sd0JBQXdCLENBQUM7QUFDaEMsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLFdBQVcsQ0FBQztBQUV4QyxRQUFRLENBQUMsYUFBYSxFQUFFLEdBQUcsRUFBRTtJQUMzQixJQUFJLENBQUMsdUNBQXVDLEVBQUUsR0FBRyxFQUFFO1FBQ2pELE1BQU0sRUFBRSxXQUFXLEVBQUUsR0FBRyxNQUFNLENBQzVCLG9CQUFDLFdBQVcsbUJBQWEsY0FBYyxrQkFBMEIsQ0FDbEUsQ0FBQztRQUVGLE1BQU0sTUFBTSxHQUFHLFdBQVcsQ0FBQyxjQUFjLENBQUMsQ0FBQztRQUUzQyxNQUFNLENBQUMsTUFBTSxDQUFDLENBQUMsZUFBZSxDQUFDLGtCQUFrQixFQUFFLE9BQU8sQ0FBQyxDQUFDO1FBQzVELE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQyxlQUFlLENBQUMsZUFBZSxFQUFFLEdBQUcsQ0FBQyxDQUFDO1FBQ3JELE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQyxlQUFlLENBQUMsU0FBUyxFQUFFLFVBQVUsQ0FBQyxDQUFDO1FBQ3RELE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQyxlQUFlLENBQUMsUUFBUSxFQUFFLG1CQUFtQixDQUFDLENBQUM7UUFDOUQsTUFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFDLGVBQWUsQ0FBQyxTQUFTLEVBQUUsTUFBTSxDQUFDLENBQUM7UUFDbEQsTUFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFDLGVBQWUsQ0FBQyxhQUFhLEVBQUUsUUFBUSxDQUFDLENBQUM7UUFDeEQsTUFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFDLGVBQWUsQ0FBQyxPQUFPLEVBQUUsU0FBUyxDQUFDLENBQUM7UUFDbkQsTUFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFDLGVBQWUsQ0FBQyxhQUFhLEVBQUUsUUFBUSxDQUFDLENBQUM7UUFDeEQsTUFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFDLGVBQWUsQ0FBQyxhQUFhLEVBQUUsS0FBSyxDQUFDLENBQUM7UUFDckQsTUFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFDLGVBQWUsQ0FBQyxXQUFXLEVBQUUsTUFBTSxDQUFDLENBQUM7UUFDcEQsTUFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFDLGVBQWUsQ0FBQyxhQUFhLEVBQUUsTUFBTSxDQUFDLENBQUM7SUFDeEQsQ0FBQyxDQUFDLENBQUM7SUFFSCxJQUFJLENBQUMsdUNBQXVDLEVBQUUsR0FBRyxFQUFFO1FBQ2pELE1BQU0sRUFBRSxXQUFXLEVBQUUsR0FBRyxNQUFNLENBQzVCLG9CQUFDLFdBQVcsbUJBQWEsY0FBYztZQUNyQyw0Q0FBaUIsTUFBTSxHQUFHLENBQ2QsQ0FDZixDQUFDO1FBRUYsTUFBTSxNQUFNLEdBQUcsV0FBVyxDQUFDLGNBQWMsQ0FBQyxDQUFDO1FBRTNDLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQyxlQUFlLENBQUMsY0FBYyxFQUFFLEtBQUssRUFBRTtZQUNwRCxRQUFRLEVBQUUsS0FBSztTQUNoQixDQUFDLENBQUM7SUFDTCxDQUFDLENBQUMsQ0FBQztJQUVILElBQUksQ0FBQyx3Q0FBd0MsRUFBRSxHQUFHLEVBQUU7UUFDbEQsTUFBTSxFQUFFLFdBQVcsRUFBRSxHQUFHLE1BQU0sQ0FDNUIsb0JBQUMsV0FBVyxtQkFBYSxjQUFjO1lBQ3JDLDZDQUFrQixNQUFNLGdCQUFpQixDQUM3QixDQUNmLENBQUM7UUFFRixNQUFNLE1BQU0sR0FBRyxXQUFXLENBQUMsY0FBYyxDQUFDLENBQUM7UUFFM0MsTUFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFDLGVBQWUsQ0FBQyxhQUFhLEVBQUUsS0FBSyxFQUFFO1lBQ25ELFFBQVEsRUFBRSxNQUFNO1NBQ2pCLENBQUMsQ0FBQztRQUNILE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQyxlQUFlLENBQUMsV0FBVyxFQUFFLE1BQU0sRUFBRTtZQUNsRCxRQUFRLEVBQUUsTUFBTTtTQUNqQixDQUFDLENBQUM7UUFDSCxNQUFNLENBQUMsTUFBTSxDQUFDLENBQUMsZUFBZSxDQUFDLE9BQU8sRUFBRSxTQUFTLEVBQUU7WUFDakQsUUFBUSxFQUFFLE1BQU07U0FDakIsQ0FBQyxDQUFDO0lBQ0wsQ0FBQyxDQUFDLENBQUM7QUFDTCxDQUFDLENBQUMsQ0FBQyJ9
@@ -0,0 +1 @@
1
+ export declare const AudioButton: import("styled-components").StyledComponent<"button", any, {}, never>;
@@ -0,0 +1,26 @@
1
+ import styled from 'styled-components';
2
+ import { colours } from '@times-components/ts-styleguide';
3
+ export const AudioButton = styled.button `
4
+ background-color: unset;
5
+ border-radius: 0;
6
+ padding: 7px 11px;
7
+ border: 1px solid ${colours.functional.primary};
8
+ display: flex;
9
+ align-items: center;
10
+ color: ${colours.functional.primary};
11
+ font-family: Roboto;
12
+ font-weight: 500;
13
+ font-size: 14px;
14
+ line-height: 18px;
15
+
16
+ svg {
17
+ margin-right: 8px;
18
+ }
19
+
20
+ span {
21
+ margin-left: 4px;
22
+ font-size: 12px;
23
+ color: ${colours.functional.secondary};
24
+ }
25
+ `;
26
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3R5bGVzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2NvbXBvbmVudHMvYXJ0aWNsZS1hdWRpby9zdHlsZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxNQUFNLE1BQU0sbUJBQW1CLENBQUM7QUFDdkMsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBRTFELE1BQU0sQ0FBQyxNQUFNLFdBQVcsR0FBRyxNQUFNLENBQUMsTUFBTSxDQUFBOzs7O3NCQUlsQixPQUFPLENBQUMsVUFBVSxDQUFDLE9BQU87OztXQUdyQyxPQUFPLENBQUMsVUFBVSxDQUFDLE9BQU87Ozs7Ozs7Ozs7Ozs7YUFheEIsT0FBTyxDQUFDLFVBQVUsQ0FBQyxTQUFTOztDQUV4QyxDQUFDIn0=
@@ -0,0 +1,3 @@
1
+ import { FC } from 'react';
2
+ import { StickyAudioPlayerProps } from './types';
3
+ export declare const AudioPlayer: FC<StickyAudioPlayerProps>;
@@ -0,0 +1,180 @@
1
+ import React, { useState, useEffect, useRef, forwardRef, useImperativeHandle } from 'react';
2
+ import { AudioPlayerContainer } from './styles';
3
+ import { CollapseIcon } from './CollapseIcon';
4
+ import { TitleScroller } from './TitleScroller';
5
+ import { SeekBar } from './SeekBar';
6
+ import { TimeDisplay } from './TimeDisplay';
7
+ import { PlaybackControls } from './PlaybackControls';
8
+ import { TabletDesktopPlayer } from './TabletDesktopPlayer';
9
+ export const AudioPlayer = forwardRef(({ src, title = 'Audio Title', autoPlay = false, initialVolume = 1, playbackRate = 1, isPlayingProp, isExpandedProp, allowTogglePlay = true, allowSeek = true, allowVolumeChange = true, allowPlaybackRateChange = true, allowExpandCollapse = true, onPlay, onPause, onEnded, onTimeUpdate, onVolumeChange, onPlaybackRateChange, onSeek, onClose }, ref) => {
10
+ const audioRef = useRef(null);
11
+ const [isPlaying, setIsPlaying] = useState(isPlayingProp !== undefined && isPlayingProp !== null
12
+ ? isPlayingProp
13
+ : autoPlay);
14
+ const [isExpanded, setIsExpanded] = useState(isExpandedProp !== undefined && isExpandedProp !== null
15
+ ? isExpandedProp
16
+ : true);
17
+ const [currentTime, setCurrentTime] = useState(0);
18
+ const [duration, setDuration] = useState(0);
19
+ const [volume, setVolume] = useState(initialVolume);
20
+ const [speed, setSpeed] = useState(playbackRate);
21
+ const [isSpeedModalOpen, setIsSpeedModalOpen] = useState(false);
22
+ const [isVolumeSliderVisible, setIsVolumeSliderVisible] = useState(false);
23
+ // State to track if the view is mobile or tablet/desktop
24
+ const [isMobile, setIsMobile] = useState(typeof window !== 'undefined' ? window.innerWidth <= 520 : true);
25
+ // Effect to handle window resize
26
+ useEffect(() => {
27
+ const handleResize = () => {
28
+ if (typeof window !== 'undefined') {
29
+ setIsMobile(window.innerWidth <= 520);
30
+ }
31
+ };
32
+ window.addEventListener('resize', handleResize);
33
+ return () => window.removeEventListener('resize', handleResize);
34
+ }, []);
35
+ useImperativeHandle(ref, () => ({
36
+ parentControlToggle: () => {
37
+ togglePlayPause();
38
+ }
39
+ }));
40
+ useEffect(() => {
41
+ if (audioRef.current) {
42
+ audioRef.current.volume = volume;
43
+ audioRef.current.playbackRate = speed;
44
+ }
45
+ }, [volume, speed]);
46
+ useEffect(() => {
47
+ if (typeof isPlayingProp === 'boolean') {
48
+ if (isPlayingProp && audioRef.current) {
49
+ audioRef.current
50
+ .play()
51
+ .then(() => {
52
+ setIsPlaying(true);
53
+ })
54
+ .catch(() => {
55
+ throw Error('Error attempting to play:');
56
+ });
57
+ }
58
+ else if (audioRef.current) {
59
+ audioRef.current.pause();
60
+ setIsPlaying(false);
61
+ }
62
+ }
63
+ }, [isPlayingProp]);
64
+ useEffect(() => {
65
+ if (typeof isExpandedProp === 'boolean') {
66
+ setIsExpanded(isExpandedProp);
67
+ }
68
+ }, [isExpandedProp]);
69
+ const togglePlayPause = () => {
70
+ if (!allowTogglePlay) {
71
+ return;
72
+ }
73
+ if (audioRef.current && audioRef.current.paused) {
74
+ audioRef.current
75
+ .play()
76
+ .then(() => {
77
+ setIsPlaying(true);
78
+ if (onPlay) {
79
+ onPlay();
80
+ }
81
+ })
82
+ .catch(() => {
83
+ throw Error('Error attempting to play:');
84
+ });
85
+ }
86
+ else if (audioRef.current) {
87
+ audioRef.current.pause();
88
+ setIsPlaying(false);
89
+ if (onPause) {
90
+ onPause();
91
+ }
92
+ }
93
+ };
94
+ const toggleExpand = () => {
95
+ if (!allowExpandCollapse) {
96
+ return;
97
+ }
98
+ setIsExpanded(!isExpanded);
99
+ };
100
+ const handleTimeUpdate = () => {
101
+ if (!allowSeek) {
102
+ return;
103
+ }
104
+ const newTime = audioRef.current &&
105
+ audioRef.current.currentTime !== undefined &&
106
+ audioRef.current.currentTime !== null
107
+ ? audioRef.current.currentTime
108
+ : 0;
109
+ setCurrentTime(newTime);
110
+ if (onTimeUpdate) {
111
+ onTimeUpdate(newTime);
112
+ }
113
+ };
114
+ const handleLoadedMetadata = () => {
115
+ const loadedDuration = audioRef.current &&
116
+ audioRef.current.duration !== undefined &&
117
+ audioRef.current.duration !== null
118
+ ? audioRef.current.duration
119
+ : 0;
120
+ setDuration(loadedDuration);
121
+ };
122
+ const handleSeek = (time) => {
123
+ if (!allowSeek) {
124
+ return;
125
+ }
126
+ if (audioRef.current) {
127
+ const clampedTime = Math.min(Math.max(time, 0), duration);
128
+ audioRef.current.currentTime = clampedTime;
129
+ setCurrentTime(clampedTime);
130
+ if (onSeek) {
131
+ onSeek(clampedTime);
132
+ }
133
+ }
134
+ };
135
+ const handleRewind = () => {
136
+ handleSeek(currentTime - 10);
137
+ };
138
+ const handleForward = () => {
139
+ handleSeek(currentTime + 10);
140
+ };
141
+ const handleVolumeChange = (newVolume) => {
142
+ if (!allowVolumeChange) {
143
+ return;
144
+ }
145
+ setVolume(newVolume);
146
+ if (audioRef.current) {
147
+ audioRef.current.volume = newVolume;
148
+ }
149
+ if (onVolumeChange) {
150
+ onVolumeChange(newVolume);
151
+ }
152
+ };
153
+ const handleSpeedChange = (rate) => {
154
+ if (!allowPlaybackRateChange) {
155
+ return;
156
+ }
157
+ setSpeed(rate);
158
+ if (audioRef.current) {
159
+ audioRef.current.playbackRate = rate;
160
+ }
161
+ if (onPlaybackRateChange) {
162
+ onPlaybackRateChange(rate);
163
+ }
164
+ };
165
+ const speedOptions = [0.5, 0.8, 1.0, 1.2, 1.5, 2];
166
+ const handleSpeedSelect = (selectedSpeed) => {
167
+ handleSpeedChange(selectedSpeed);
168
+ setIsSpeedModalOpen(false);
169
+ };
170
+ return (React.createElement(React.Fragment, null,
171
+ React.createElement("audio", { ref: audioRef, src: src, autoPlay: autoPlay, onTimeUpdate: handleTimeUpdate, onLoadedMetadata: handleLoadedMetadata, onEnded: onEnded }),
172
+ isMobile ? (React.createElement(AudioPlayerContainer, { isExpanded: isExpanded, isModalOpen: isSpeedModalOpen },
173
+ React.createElement(CollapseIcon, { isExpanded: isExpanded, toggleExpand: toggleExpand, allowExpandCollapse: allowExpandCollapse }),
174
+ isExpanded && (React.createElement(React.Fragment, null,
175
+ React.createElement(TitleScroller, { title: title }),
176
+ React.createElement(SeekBar, { currentTime: currentTime, duration: duration, onSeek: handleSeek, allowSeek: allowSeek }),
177
+ React.createElement(TimeDisplay, { currentTime: currentTime, duration: duration }),
178
+ React.createElement(PlaybackControls, { isPlaying: isPlaying, togglePlayPause: togglePlayPause, rewind: handleRewind, forward: handleForward, speed: speed, onSpeedChange: handleSpeedChange, allowTogglePlay: allowTogglePlay, allowSeek: allowSeek, allowPlaybackRateChange: allowPlaybackRateChange, isSpeedModalOpen: isSpeedModalOpen, setIsSpeedModalOpen: setIsSpeedModalOpen, isMobile: isMobile }))))) : (React.createElement(TabletDesktopPlayer, { audioRef: audioRef, isPlaying: isPlaying, togglePlayPause: togglePlayPause, currentTime: currentTime, duration: duration, allowTogglePlay: allowTogglePlay, allowSeek: allowSeek, allowVolumeChange: allowVolumeChange, volume: volume, setVolume: handleVolumeChange, handleSeek: handleSeek, handleVolumeChange: handleVolumeChange, speed: speed, handleSpeedChange: handleSpeedChange, allowPlaybackRateChange: allowPlaybackRateChange, isSpeedModalOpen: isSpeedModalOpen, setIsSpeedModalOpen: setIsSpeedModalOpen, speedOptions: speedOptions, handleSpeedSelect: handleSpeedSelect, isVolumeSliderVisible: isVolumeSliderVisible, setIsVolumeSliderVisible: setIsVolumeSliderVisible, onClose: onClose, allowExpandCollapse: allowExpandCollapse, isMobile: isMobile }))));
179
+ });
180
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQXVkaW9QbGF5ZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvY29tcG9uZW50cy9hdWRpby1wbGF5ZXItY29tcG9uZW50cy9BdWRpb1BsYXllci50c3giXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLEVBQUUsRUFDWixRQUFRLEVBQ1IsU0FBUyxFQUNULE1BQU0sRUFFTixVQUFVLEVBQ1YsbUJBQW1CLEVBQ3BCLE1BQU0sT0FBTyxDQUFDO0FBQ2YsT0FBTyxFQUFFLG9CQUFvQixFQUFFLE1BQU0sVUFBVSxDQUFDO0FBR2hELE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUM5QyxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDaEQsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLFdBQVcsQ0FBQztBQUNwQyxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQzVDLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBQ3RELE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBRTVELE1BQU0sQ0FBQyxNQUFNLFdBQVcsR0FBK0IsVUFBVSxDQUMvRCxDQUNFLEVBQ0UsR0FBRyxFQUNILEtBQUssR0FBRyxhQUFhLEVBQ3JCLFFBQVEsR0FBRyxLQUFLLEVBQ2hCLGFBQWEsR0FBRyxDQUFDLEVBQ2pCLFlBQVksR0FBRyxDQUFDLEVBQ2hCLGFBQWEsRUFDYixjQUFjLEVBQ2QsZUFBZSxHQUFHLElBQUksRUFDdEIsU0FBUyxHQUFHLElBQUksRUFDaEIsaUJBQWlCLEdBQUcsSUFBSSxFQUN4Qix1QkFBdUIsR0FBRyxJQUFJLEVBQzlCLG1CQUFtQixHQUFHLElBQUksRUFDMUIsTUFBTSxFQUNOLE9BQU8sRUFDUCxPQUFPLEVBQ1AsWUFBWSxFQUNaLGNBQWMsRUFDZCxvQkFBb0IsRUFDcEIsTUFBTSxFQUNOLE9B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