@ndla/ui 37.1.4 → 38.0.0

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 (106) hide show
  1. package/es/Article/Article.js +2 -2
  2. package/es/Article/ArticleHeaderWrapper.js +4 -7
  3. package/es/Article/ArticleNotions.js +16 -17
  4. package/es/Article/ArticleSideBar.js +4 -5
  5. package/es/AudioPlayer/Controls.js +173 -235
  6. package/es/CompetenceGoals/CompetenceGoalsDialog.js +12 -25
  7. package/es/Filter/FilterButtons.js +12 -14
  8. package/es/Filter/FilterListPhone.js +2 -4
  9. package/es/Footer/index.js +1 -2
  10. package/es/LearningPaths/LearningPathMenuModalWrapper.js +10 -6
  11. package/es/Masthead/MastheadSearchModal.js +56 -47
  12. package/es/MyNdla/SettingsMenu.js +6 -6
  13. package/es/NDLAFilm/AboutNdlaFilm.js +3 -3
  14. package/es/ResourcesWrapper/ResourcesTopicTitle.js +19 -23
  15. package/es/SearchTypeResult/PopupFilter.js +14 -20
  16. package/es/SearchTypeResult/components/ItemContexts.js +10 -21
  17. package/es/Topic/Topic.js +23 -23
  18. package/es/User/index.js +1 -3
  19. package/es/index.js +1 -3
  20. package/es/locale/messages-en.js +1 -0
  21. package/es/locale/messages-nb.js +1 -0
  22. package/es/locale/messages-nn.js +1 -0
  23. package/es/locale/messages-se.js +1 -0
  24. package/es/locale/messages-sma.js +1 -0
  25. package/lib/Article/Article.d.ts +2 -2
  26. package/lib/Article/Article.js +2 -2
  27. package/lib/Article/ArticleHeaderWrapper.d.ts +3 -2
  28. package/lib/Article/ArticleHeaderWrapper.js +4 -7
  29. package/lib/Article/ArticleNotions.js +17 -21
  30. package/lib/Article/ArticleSideBar.js +5 -9
  31. package/lib/AudioPlayer/Controls.d.ts +2 -2
  32. package/lib/AudioPlayer/Controls.js +173 -235
  33. package/lib/CompetenceGoals/CompetenceGoalsDialog.d.ts +3 -14
  34. package/lib/CompetenceGoals/CompetenceGoalsDialog.js +11 -26
  35. package/lib/Filter/FilterButtons.js +13 -15
  36. package/lib/Filter/FilterListPhone.js +3 -5
  37. package/lib/Footer/index.d.ts +1 -2
  38. package/lib/Footer/index.js +0 -7
  39. package/lib/LearningPaths/LearningPathMenuModalWrapper.js +9 -8
  40. package/lib/Masthead/MastheadSearchModal.d.ts +1 -1
  41. package/lib/Masthead/MastheadSearchModal.js +58 -46
  42. package/lib/MyNdla/SettingsMenu.js +5 -5
  43. package/lib/NDLAFilm/AboutNdlaFilm.js +2 -2
  44. package/lib/ResourcesWrapper/ResourcesTopicTitle.js +20 -27
  45. package/lib/SearchTypeResult/PopupFilter.js +14 -20
  46. package/lib/SearchTypeResult/components/ItemContexts.js +10 -21
  47. package/lib/Topic/Topic.js +22 -22
  48. package/lib/User/index.d.ts +0 -2
  49. package/lib/User/index.js +1 -13
  50. package/lib/index.d.ts +1 -3
  51. package/lib/index.js +1 -20
  52. package/lib/locale/messages-en.d.ts +1 -0
  53. package/lib/locale/messages-en.js +1 -0
  54. package/lib/locale/messages-nb.d.ts +1 -0
  55. package/lib/locale/messages-nb.js +1 -0
  56. package/lib/locale/messages-nn.d.ts +1 -0
  57. package/lib/locale/messages-nn.js +1 -0
  58. package/lib/locale/messages-se.d.ts +1 -0
  59. package/lib/locale/messages-se.js +1 -0
  60. package/lib/locale/messages-sma.d.ts +1 -0
  61. package/lib/locale/messages-sma.js +1 -0
  62. package/package.json +16 -18
  63. package/src/Article/Article.tsx +4 -4
  64. package/src/Article/ArticleHeaderWrapper.tsx +12 -18
  65. package/src/Article/ArticleNotions.tsx +7 -8
  66. package/src/Article/ArticleSideBar.tsx +3 -3
  67. package/src/AudioPlayer/Controls.tsx +145 -287
  68. package/src/CompetenceGoals/CompetenceGoalsDialog.tsx +13 -38
  69. package/src/Filter/FilterButtons.tsx +4 -5
  70. package/src/Filter/FilterListPhone.tsx +3 -4
  71. package/src/Footer/index.ts +1 -2
  72. package/src/LearningPaths/LearningPathMenuModalWrapper.tsx +10 -6
  73. package/src/Masthead/MastheadSearchModal.tsx +48 -74
  74. package/src/MyNdla/SettingsMenu.tsx +3 -3
  75. package/src/NDLAFilm/AboutNdlaFilm.tsx +3 -3
  76. package/src/ResourcesWrapper/ResourcesTopicTitle.tsx +4 -8
  77. package/src/SearchTypeResult/PopupFilter.tsx +6 -11
  78. package/src/SearchTypeResult/components/ItemContexts.tsx +4 -21
  79. package/src/Topic/Topic.tsx +7 -7
  80. package/src/User/index.ts +0 -2
  81. package/src/index.ts +1 -3
  82. package/src/locale/messages-en.ts +1 -0
  83. package/src/locale/messages-nb.ts +1 -0
  84. package/src/locale/messages-nn.ts +1 -0
  85. package/src/locale/messages-se.ts +1 -0
  86. package/src/locale/messages-sma.ts +1 -0
  87. package/es/Figure/FigureLicenseDialogContent.js +0 -75
  88. package/es/Footer/FooterAuth.js +0 -110
  89. package/es/Masthead/MastheadAuthModal.js +0 -50
  90. package/es/SearchTypeResult/SearchNotionItem.js +0 -208
  91. package/es/User/AuthModal.js +0 -116
  92. package/lib/Figure/FigureLicenseDialogContent.d.ts +0 -22
  93. package/lib/Figure/FigureLicenseDialogContent.js +0 -80
  94. package/lib/Footer/FooterAuth.d.ts +0 -10
  95. package/lib/Footer/FooterAuth.js +0 -114
  96. package/lib/Masthead/MastheadAuthModal.d.ts +0 -13
  97. package/lib/Masthead/MastheadAuthModal.js +0 -56
  98. package/lib/SearchTypeResult/SearchNotionItem.d.ts +0 -29
  99. package/lib/SearchTypeResult/SearchNotionItem.js +0 -215
  100. package/lib/User/AuthModal.d.ts +0 -22
  101. package/lib/User/AuthModal.js +0 -124
  102. package/src/Figure/FigureLicenseDialogContent.tsx +0 -80
  103. package/src/Footer/FooterAuth.tsx +0 -104
  104. package/src/Masthead/MastheadAuthModal.tsx +0 -62
  105. package/src/SearchTypeResult/SearchNotionItem.tsx +0 -228
  106. package/src/User/AuthModal.tsx +0 -123
@@ -8,179 +8,85 @@
8
8
 
9
9
  import React, { useEffect, useRef, useState } from 'react';
10
10
  import styled from '@emotion/styled';
11
- import { Menu, MenuButton, MenuItem, MenuPopover, MenuItems, MenuItemProps } from '@reach/menu-button';
12
- import { SliderInput, SliderTrack, SliderRange, SliderHandle, SliderOrientation } from '@reach/slider';
13
- import { Popover } from '@headlessui/react';
11
+ import { Root, Trigger, Item, Content, DropdownMenuPortal } from '@radix-ui/react-dropdown-menu';
12
+ import { Root as SliderRoot, Track, Range, SliderThumb } from '@radix-ui/react-slider';
13
+ import { Root as PopoverRoot, PopoverContent, PopoverTrigger, PopoverPortal } from '@radix-ui/react-popover';
14
14
  import { Play, Pause, VolumeUp } from '@ndla/icons/common';
15
15
  import { breakpoints, colors, fonts, misc, mq, spacing } from '@ndla/core';
16
16
  import { useTranslation } from 'react-i18next';
17
17
  import { Back15, Forward15 } from '@ndla/icons/action';
18
+ import { ButtonV2, IconButtonV2 } from '@ndla/button';
18
19
 
19
20
  const ControlsWrapper = styled.div`
20
21
  border: 1px solid ${colors.brand.lighter};
21
22
  display: flex;
22
23
  align-items: center;
23
24
  justify-content: center;
24
- background: #ffffff;
25
+ background: ${colors.white};
25
26
  font-family: ${fonts.sans};
27
+ gap: ${spacing.xsmall};
28
+ padding: ${spacing.small} ${spacing.normal};
26
29
  ${mq.range({ until: breakpoints.tabletWide })} {
27
- flex-wrap: wrap;
28
- }
29
- padding: ${spacing.small};
30
- ${mq.range({ from: breakpoints.tabletWide })} {
31
- padding: ${spacing.small} ${spacing.normal};
30
+ display: grid;
31
+ padding: ${spacing.small};
32
+ grid-template-columns: 1fr repeat(5, auto) 1fr;
33
+ grid-template-areas:
34
+ 'track track track track track track track'
35
+ '. speed backwards play forwards volume .';
32
36
  }
33
37
  `;
34
38
 
35
- const PlayButton = styled.button`
36
- background: ${colors.brand.lighter};
37
- border: none;
38
- display: flex;
39
- align-items: center;
40
- justify-content: center;
41
- padding: 0;
42
- cursor: pointer;
43
- color: ${colors.brand.primary};
44
- width: 55px;
45
- height: 55px;
46
- border-radius: 50%;
47
- transition: ${misc.transition.default};
48
- margin-right: ${spacing.small};
39
+ const PlayButton = styled(IconButtonV2)`
49
40
  ${mq.range({ until: breakpoints.tabletWide })} {
50
- order: 4;
51
- margin-left: ${spacing.small};
52
- }
53
-
54
- &:hover,
55
- &:active,
56
- &:focus {
57
- background: ${colors.brand.primary};
58
- color: #ffffff;
59
- }
60
-
61
- .c-icon {
62
- width: 24px;
63
- height: 24px;
64
- }
65
- `;
66
-
67
- const ForwardRewindButton = styled.button`
68
- background-color: inherit;
69
- background-position: center;
70
- background-repeat: no-repeat;
71
- width: 42px;
72
- height: 42px;
73
- border: 0;
74
- border-radius: 50%;
75
- cursor: pointer;
76
- font-weight: bold;
77
- font-size: 9px;
78
- line-height: 23px;
79
- color: ${colors.brand.dark};
80
- font-family: ${fonts.sans};
81
- transition: ${misc.transition.default};
82
-
83
- &:hover {
84
- background-color: ${colors.brand.greyLighter};
41
+ grid-area: play;
85
42
  }
86
43
  `;
87
44
 
88
- const Forward15SecButton = styled(ForwardRewindButton)`
89
- svg {
90
- fill: ${colors.brand.primary};
91
- width: 24px;
92
- height: 24px;
93
- }
45
+ const Forward15SecButton = styled(IconButtonV2)`
94
46
  ${mq.range({ until: breakpoints.tabletWide })} {
95
- order: 3;
47
+ grid-area: forwards;
96
48
  }
97
49
  `;
98
- const Back15SecButton = styled(ForwardRewindButton)`
99
- svg {
100
- fill: ${colors.brand.primary};
101
- width: 24px;
102
- height: 24px;
103
- }
50
+ const Back15SecButton = styled(IconButtonV2)`
104
51
  ${mq.range({ until: breakpoints.tabletWide })} {
105
- order: 5;
52
+ grid-area: backwards;
106
53
  }
107
54
  `;
108
55
 
109
- const SpeedWrapper = styled.div`
110
- position: relative;
111
- display: flex;
112
- justify-content: center;
56
+ const SpeedButton = styled(ButtonV2)`
113
57
  ${mq.range({ until: breakpoints.tabletWide })} {
114
- order: 2;
58
+ grid-area: speed;
115
59
  }
116
60
  `;
117
- const SpeedButton = styled(MenuButton)`
118
- height: 32px;
119
- border: 0;
120
- background: none;
121
- cursor: pointer;
122
- font-weight: 600;
123
- font-size: 12px;
124
- text-align: center;
125
- width: 52px;
126
- &:hover,
127
- &:active,
128
- &:focus,
129
- &[aria-expanded='true'] {
130
- background: ${colors.brand.greyLighter};
131
- border-radius: 27px;
132
- color: ${colors.text.primary};
133
- }
134
- `;
135
-
136
- const SpeedMenu = styled(MenuPopover)`
137
- position: absolute;
138
- bottom: 36px;
139
- z-index: 99;
140
- `;
141
61
 
142
- const SpeedList = styled(MenuItems)`
143
- background: #ffffff;
62
+ const SpeedList = styled(Content)`
63
+ background: ${colors.white};
144
64
  border: 1px solid ${colors.brand.lighter};
145
- border-radius: 5px;
65
+ border-radius: ${misc.borderRadius};
146
66
  padding: 5px 10px;
147
67
  display: flex;
148
68
  flex-direction: column;
149
69
  justify-content: center;
150
- align-items: stretch;
151
70
  `;
152
71
 
153
- interface SpeedValueButtonProps extends MenuItemProps {
154
- selected?: boolean;
155
- }
156
-
157
- const SpeedValueButton = styled(MenuItem)<SpeedValueButtonProps>`
72
+ const SpeedValueButton = styled(Item)`
158
73
  height: 28px;
159
- position: relative;
160
- background: none;
161
- border: 0;
162
74
  padding: 0 14px;
163
75
  cursor: pointer;
164
- font-weight: 600;
165
- font-size: 14px;
76
+ font-weight: ${fonts.weight.semibold};
77
+ ${fonts.sizes('14px')};
166
78
  color: ${colors.text.light};
167
79
  display: flex;
168
80
  justify-content: center;
169
- align-items: center;
170
81
  &:hover,
171
82
  &:active,
172
83
  &:focus,
173
- &[data-selected] {
84
+ &[data-highlighted] {
174
85
  background: ${colors.brand.greyLighter};
175
86
  border-radius: 5px;
87
+ outline: none;
176
88
  color: ${colors.text.primary};
177
89
  }
178
- ${(props) =>
179
- props.selected &&
180
- `
181
- color: ${colors.text.primary};
182
-
183
- `}
184
90
  `;
185
91
 
186
92
  const SpeedSelectedMark = styled.span`
@@ -188,142 +94,105 @@ const SpeedSelectedMark = styled.span`
188
94
  background: #d1372e;
189
95
  width: 6px;
190
96
  height: 6px;
191
- display: inline-block;
192
- align-self: flex-start;
193
97
  margin: 6px 0 0 2px;
194
98
  `;
195
99
 
196
100
  const Time = styled.div`
197
- font-size: 16px;
101
+ ${fonts.sizes('16px')};
198
102
  `;
199
103
 
200
104
  const ProgressWrapper = styled.div`
201
- flex: 1 1 auto;
105
+ flex: 1;
202
106
  display: flex;
203
107
  align-items: center;
204
- margin: 0 ${spacing.small};
108
+ gap: ${spacing.small};
205
109
  ${mq.range({ until: breakpoints.tabletWide })} {
206
- order: 1;
207
- width: 100%;
208
- margin: 0;
209
- margin-bottom: ${spacing.normal};
110
+ grid-area: track;
210
111
  }
211
112
  `;
212
- const SliderWrapper = styled.div`
113
+
114
+ const SliderWrapper = styled(SliderRoot)`
213
115
  cursor: pointer;
214
- flex: 1 1 auto;
215
- margin: 0 ${spacing.small};
116
+ flex: 1;
117
+ position: relative;
118
+ display: flex;
119
+ align-items: center;
120
+ user-select: none;
121
+ touch-action: none;
216
122
  `;
217
123
 
218
- const ProgressBackground = styled(SliderTrack)`
124
+ const StyledTrack = styled(Track)`
219
125
  height: 4px;
220
126
  width: 100%;
221
127
  background: ${colors.brand.lighter};
222
128
  border-radius: 7px;
223
129
  `;
224
130
 
225
- const ProgressPlayed = styled(SliderRange)`
131
+ const StyledRange = styled(Range)`
132
+ position: absolute;
226
133
  height: 4px;
227
134
  background: #5cbc80;
228
135
  border-radius: 7px;
229
136
  `;
230
137
 
231
- const ProgressHandle = styled(SliderHandle)`
138
+ const StyledThumb = styled(SliderThumb)`
139
+ display: block;
232
140
  width: 20px;
233
141
  height: 20px;
234
142
  background: #5cbc80;
235
143
  border-radius: 50%;
236
- top: -8px;
144
+ outline: none;
237
145
  `;
238
146
 
239
- const VolumeWrapper = styled(Popover)`
147
+ const VolumeWrapper = styled(PopoverRoot)`
240
148
  position: relative;
241
149
  display: flex;
242
150
  justify-content: center;
243
151
  ${mq.range({ until: breakpoints.tabletWide })} {
244
- order: 6;
152
+ grid-area: volume;
245
153
  }
246
154
  `;
247
155
 
248
- const WardButtonWrapper = styled.div<{ order: number }>`
249
- position: relative;
250
- display: flex;
251
- justify-content: center;
252
- ${mq.range({ until: breakpoints.tabletWide })} {
253
- ${(props) =>
254
- `
255
- order: ${props.order};
256
- `}
257
- }
258
- `;
259
-
260
- const VolumeButton = styled(Popover.Button)`
261
- background-color: inherit;
262
- width: 48px;
263
- height: 48px;
264
- border-radius: 50%;
265
- border: 0;
266
- background-position: center;
267
- background-repeat: no-repeat;
268
- cursor: pointer;
269
-
270
- svg {
271
- fill: ${colors.brand.primary};
272
- width: 32px;
273
- height: 32px;
274
- }
275
-
276
- &:hover,
277
- &:active,
278
- &:focus,
279
- &[aria-expanded='true'] {
280
- background-color: ${colors.brand.greyLighter};
281
- }
282
- `;
283
-
284
- const VolumeList = styled(Popover.Panel)`
285
- position: absolute;
286
- bottom: 52px;
287
- z-index: 99;
156
+ const VolumeList = styled(PopoverContent)`
288
157
  box-shadow: 0 14px 20px -5px rgba(32, 88, 143, 0.17);
289
158
  border-radius: 60px;
290
- background: #ffffff;
159
+ background: ${colors.white};
160
+ padding: ${spacing.small};
291
161
  border: 1px solid ${colors.brand.lighter};
292
- display: flex;
293
- flex-direction: column;
294
- justify-content: center;
295
- width: 32px;
296
162
  height: 128px;
297
163
  `;
298
164
 
299
- const VolumeSliderWrapper = styled.div`
165
+ const VolumeSliderWrapper = styled(SliderRoot)`
300
166
  cursor: pointer;
301
- flex: 1 1 auto;
167
+ height: 100%;
168
+ position: relative;
302
169
  display: flex;
303
- justify-content: center;
304
- padding: 16px 0;
170
+ flex-direction: column;
171
+ align-items: center;
172
+ user-select: none;
173
+ touch-action: none;
305
174
  `;
306
175
 
307
- const VolumeSliderBackground = styled(SliderTrack)`
176
+ const VolumeSliderBackground = styled(Track)`
308
177
  height: 100%;
309
178
  width: 5px;
310
179
  background: ${colors.brand.lighter};
311
180
  border-radius: 7px;
312
181
  `;
313
182
 
314
- const VolumeSliderSelected = styled(SliderRange)`
183
+ const VolumeSliderSelected = styled(Range)`
184
+ position: absolute;
315
185
  width: 5px;
316
186
  background: ${colors.brand.secondary};
317
187
  border-radius: 7px;
318
- bottom: 0;
319
188
  `;
320
189
 
321
- const VolumeSliderHandle = styled(SliderHandle)`
190
+ const VolumeSliderHandle = styled(SliderThumb)`
191
+ display: block;
322
192
  width: 20px;
323
193
  height: 20px;
324
194
  background: ${colors.brand.primary};
325
195
  border-radius: 50%;
326
- left: -8px;
327
196
  `;
328
197
 
329
198
  const formatTime = (seconds: number) => {
@@ -336,16 +205,15 @@ const formatTime = (seconds: number) => {
336
205
 
337
206
  const speedValues = [0.5, 0.75, 1, 1.25, 1.5, 1.75, 2];
338
207
 
339
- type Props = {
208
+ interface Props {
340
209
  src: string;
341
210
  title: string;
342
- };
211
+ }
343
212
 
344
213
  const Controls = ({ src, title }: Props) => {
345
214
  const { t } = useTranslation();
346
215
  const [speedValue, setSpeedValue] = useState(1);
347
216
  const [volumeValue, setVolumeValue] = useState(100);
348
- const [sliderValue, setSliderValue] = useState(0);
349
217
  const [currentTime, setCurrentTime] = useState(0);
350
218
  const [remainingTime, setRemainingTime] = useState(0);
351
219
  const [playing, setPlaying] = useState(false);
@@ -362,8 +230,6 @@ const Controls = ({ src, title }: Props) => {
362
230
  const audioElement = audioRef.current;
363
231
  const handleTimeUpdate = () => {
364
232
  const { currentTime, duration } = audioElement;
365
- const percent = Math.round((currentTime / duration) * 100);
366
- setSliderValue(percent);
367
233
  setCurrentTime(Math.round(currentTime));
368
234
  setRemainingTime(Math.round(duration - currentTime));
369
235
  };
@@ -372,7 +238,6 @@ const Controls = ({ src, title }: Props) => {
372
238
  const { currentTime, duration } = audioElement;
373
239
  setCurrentTime(Math.round(currentTime));
374
240
  setRemainingTime(Math.round(duration - currentTime));
375
- setRemainingTime(Math.round(duration - currentTime));
376
241
  };
377
242
 
378
243
  const handleTimeEnded = () => {
@@ -408,16 +273,16 @@ const Controls = ({ src, title }: Props) => {
408
273
  }
409
274
  };
410
275
 
411
- const handleSliderChange = (value: number) => {
276
+ const handleSliderChange = (value: number[]) => {
412
277
  if (audioRef.current) {
413
- audioRef.current.currentTime = (value / 100) * audioRef.current.duration;
278
+ audioRef.current.currentTime = value[0];
414
279
  }
415
280
  };
416
281
 
417
- const handleVolumeSliderChange = (value: number) => {
282
+ const handleVolumeSliderChange = (values: number[]) => {
418
283
  if (audioRef.current) {
419
- audioRef.current.volume = value / 100;
420
- setVolumeValue(value);
284
+ audioRef.current.volume = values[0] / 100;
285
+ setVolumeValue(values[0]);
421
286
  }
422
287
  };
423
288
 
@@ -426,102 +291,95 @@ const Controls = ({ src, title }: Props) => {
426
291
  {/* eslint-disable-next-line jsx-a11y/media-has-caption */}
427
292
  <audio ref={audioRef} src={src} title={title} preload="metadata" />
428
293
  <ControlsWrapper>
429
- <PlayButton type="button" onClick={togglePlay} title="play" aria-label="play">
430
- <span aria-hidden>
431
- {playing ? (
432
- <Pause role="img" aria-label="Pause" title="Pause" />
433
- ) : (
434
- <Play role="img" aria-label="Play" title="Play" />
435
- )}
436
- </span>
294
+ <PlayButton
295
+ aria-label={t(playing ? t('audio.pause') : t('audio.play'))}
296
+ colorTheme="lighter"
297
+ size="normal"
298
+ onClick={togglePlay}
299
+ >
300
+ {playing ? <Pause /> : <Play />}
437
301
  </PlayButton>
438
- <WardButtonWrapper order={3}>
439
- <Back15SecButton
440
- type="button"
441
- title={t('audio.controls.rewind15sec')}
442
- aria-label={t('audio.controls.rewind15sec')}
443
- onClick={() => {
444
- onSeekSeconds(-15);
445
- }}
446
- >
447
- <Back15 />
448
- </Back15SecButton>
449
- </WardButtonWrapper>
450
-
451
- <SpeedWrapper>
452
- <Menu>
302
+ <Back15SecButton
303
+ variant="ghost"
304
+ colorTheme="greyLighter"
305
+ title={t('audio.controls.rewind15sec')}
306
+ aria-label={t('audio.controls.rewind15sec')}
307
+ onClick={() => onSeekSeconds(-15)}
308
+ >
309
+ <Back15 />
310
+ </Back15SecButton>
311
+
312
+ <Root>
313
+ <Trigger asChild>
453
314
  <SpeedButton
454
- type="button"
455
- as="button"
315
+ shape="pill"
316
+ variant="ghost"
317
+ size="normal"
318
+ colorTheme="greyLighter"
456
319
  title={t('audio.controls.selectSpeed')}
457
320
  aria-label={t('audio.controls.selectSpeed')}
458
321
  >
459
322
  {speedValue}x
460
323
  </SpeedButton>
461
- <SpeedMenu as="div" portal={false}>
462
- <div>
463
- <SpeedList as="div">
464
- {speedValues.map((speed) => (
465
- <SpeedValueButton
466
- type="button"
467
- //@ts-ignore
468
- as="button"
469
- key={speed}
470
- selected={speed === speedValue}
471
- onSelect={() => {
472
- setSpeedValue(speed);
473
- }}
474
- >
475
- {speed}x{speed === speedValue && <SpeedSelectedMark />}
476
- </SpeedValueButton>
477
- ))}
478
- </SpeedList>
479
- </div>
480
- </SpeedMenu>
481
- </Menu>
482
- </SpeedWrapper>
483
- <WardButtonWrapper order={5}>
484
- <Forward15SecButton
485
- type="button"
486
- title={t('audio.controls.forward15sec')}
487
- aria-label={t('audio.controls.forward15sec')}
488
- onClick={() => {
489
- onSeekSeconds(15);
490
- }}
491
- >
492
- <Forward15 />
493
- </Forward15SecButton>
494
- </WardButtonWrapper>
324
+ </Trigger>
325
+ <DropdownMenuPortal>
326
+ <SpeedList side="top">
327
+ {speedValues.map((speed) => (
328
+ <SpeedValueButton key={speed} onSelect={() => setSpeedValue(speed)}>
329
+ {speed}x{speed === speedValue && <SpeedSelectedMark />}
330
+ </SpeedValueButton>
331
+ ))}
332
+ </SpeedList>
333
+ </DropdownMenuPortal>
334
+ </Root>
335
+ <Forward15SecButton
336
+ colorTheme="greyLighter"
337
+ variant="ghost"
338
+ title={t('audio.controls.forward15sec')}
339
+ aria-label={t('audio.controls.forward15sec')}
340
+ onClick={() => onSeekSeconds(15)}
341
+ >
342
+ <Forward15 />
343
+ </Forward15SecButton>
495
344
  <ProgressWrapper>
496
345
  <Time>{formatTime(currentTime)}</Time>
497
- <SliderWrapper>
498
- <SliderInput onChange={handleSliderChange} value={sliderValue}>
499
- <ProgressBackground as="div">
500
- <ProgressPlayed as="div" />
501
- <ProgressHandle as="div" />
502
- </ProgressBackground>
503
- </SliderInput>
346
+ <SliderWrapper
347
+ value={[audioRef.current?.currentTime ?? 0]}
348
+ defaultValue={[0]}
349
+ step={1}
350
+ max={audioRef.current?.duration ?? 0}
351
+ onValueChange={handleSliderChange}
352
+ >
353
+ <StyledTrack>
354
+ <StyledRange />
355
+ </StyledTrack>
356
+ <StyledThumb />
504
357
  </SliderWrapper>
505
358
  <Time>-{formatTime(remainingTime)}</Time>
506
359
  </ProgressWrapper>
507
360
  <VolumeWrapper>
508
- <VolumeButton aria-label={t('audio.controls.adjustVolume')}>
509
- <VolumeUp />
510
- </VolumeButton>
511
- <VolumeList>
512
- <VolumeSliderWrapper>
513
- <SliderInput
514
- orientation={SliderOrientation.Vertical}
515
- onChange={handleVolumeSliderChange}
516
- value={volumeValue}
361
+ <PopoverTrigger asChild>
362
+ <IconButtonV2 variant="ghost" colorTheme="greyLighter" aria-label={t('audio.controls.adjustVolume')}>
363
+ <VolumeUp />
364
+ </IconButtonV2>
365
+ </PopoverTrigger>
366
+ <PopoverPortal>
367
+ <VolumeList side="top">
368
+ <VolumeSliderWrapper
369
+ orientation="vertical"
370
+ value={[volumeValue]}
371
+ min={0}
372
+ defaultValue={[100]}
373
+ step={1}
374
+ onValueChange={handleVolumeSliderChange}
517
375
  >
518
- <VolumeSliderBackground as="div">
519
- <VolumeSliderSelected as="div" />
520
- <VolumeSliderHandle as="div" />
376
+ <VolumeSliderBackground>
377
+ <VolumeSliderSelected />
521
378
  </VolumeSliderBackground>
522
- </SliderInput>
523
- </VolumeSliderWrapper>
524
- </VolumeList>
379
+ <VolumeSliderHandle />
380
+ </VolumeSliderWrapper>
381
+ </VolumeList>
382
+ </PopoverPortal>
525
383
  </VolumeWrapper>
526
384
  </ControlsWrapper>
527
385
  </div>