@ndla/ui 55.0.12-alpha.0 → 55.0.13-alpha.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 (192) hide show
  1. package/dist/all-aout.js +0 -0
  2. package/dist/all.css +1 -0
  3. package/dist/panda.buildinfo.json +170 -0
  4. package/dist/styles.css +686 -0
  5. package/es/Article/Article.js +3 -4
  6. package/es/Article/ArticleByline.js +9 -9
  7. package/es/Article/ArticleFootNotes.js +4 -4
  8. package/es/AudioPlayer/AudioPlayer.js +142 -163
  9. package/es/AudioPlayer/Controls.js +187 -203
  10. package/es/AudioPlayer/SpeechControl.js +13 -11
  11. package/es/BlogPost/BlogPost.js +85 -23
  12. package/es/CampaignBlock/CampaignBlock.js +3 -4
  13. package/es/CodeBlock/CodeBlock.js +88 -96
  14. package/es/ContactBlock/ContactBlock.js +54 -40
  15. package/es/ContentLoader/index.js +7 -7
  16. package/es/CopyParagraphButton/CopyParagraphButton.js +4 -4
  17. package/es/Embed/AudioEmbed.js +5 -9
  18. package/es/Embed/BrightcoveEmbed.js +12 -15
  19. package/es/Embed/CodeEmbed.js +58 -10
  20. package/es/Embed/ConceptEmbed.js +15 -20
  21. package/es/Embed/ContentLinkEmbed.js +1 -1
  22. package/es/Embed/EmbedErrorPlaceholder.js +32 -17
  23. package/es/Embed/ExternalEmbed.js +7 -10
  24. package/es/Embed/FootnoteEmbed.js +3 -3
  25. package/es/Embed/H5pEmbed.js +1 -2
  26. package/es/Embed/IframeEmbed.js +8 -9
  27. package/es/Embed/ImageEmbed.js +167 -122
  28. package/es/Embed/RelatedContentEmbed.js +8 -10
  29. package/es/Embed/UuDisclaimerEmbed.js +2 -2
  30. package/es/Embed/conceptComponents.js +9 -9
  31. package/es/ErrorMessage/ErrorMessage.js +1 -1
  32. package/es/FactBox/FactBox.js +2 -2
  33. package/es/FileList/File.js +1 -1
  34. package/es/FileList/Format.js +3 -3
  35. package/es/FrontpageArticle/FrontpageArticle.js +1 -1
  36. package/es/Gloss/Gloss.js +9 -11
  37. package/es/Gloss/GlossExample.js +3 -4
  38. package/es/Grid/Grid.js +1 -1
  39. package/es/Image/Image.js +7 -8
  40. package/es/Image/ImageLink.js +1 -1
  41. package/es/KeyFigure/KeyFigure.js +2 -2
  42. package/es/LanguageSelector/LanguageSelector.js +2 -2
  43. package/es/LetterFilter/LetterFilter.js +1 -1
  44. package/es/LicenseByline/EmbedByline.js +5 -6
  45. package/es/LicenseByline/LicenseDescription.js +1 -1
  46. package/es/LicenseByline/LicenseLink.js +1 -2
  47. package/es/Messages/MessageBox.js +1 -1
  48. package/es/Notion/Notion.js +2 -2
  49. package/es/Notion/NotionImage.js +12 -57
  50. package/es/RelatedArticleList/RelatedArticleList.js +3 -3
  51. package/es/ResourceBox/ResourceBox.js +12 -17
  52. package/es/Search/ActiveFilters.js +1 -1
  53. package/es/Search/ContentTypeResult.js +9 -6
  54. package/es/Search/ContentTypeResultStyles.js +1 -1
  55. package/es/Search/IsPathToHighlight.js +1 -1
  56. package/es/Search/SearchField.js +6 -8
  57. package/es/Search/SearchResult.js +14 -19
  58. package/es/Search/SearchResultSleeve.js +14 -16
  59. package/es/SnackBar/SnackbarProvider.js +8 -11
  60. package/es/TagSelector/TagSelector.js +1 -1
  61. package/es/TagSelector/ariaMessages.js +6 -6
  62. package/es/TreeStructure/AddFolderButton.js +4 -6
  63. package/es/TreeStructure/ComboboxButton.js +4 -7
  64. package/es/TreeStructure/FolderItem.js +12 -15
  65. package/es/TreeStructure/FolderItems.js +3 -3
  66. package/es/TreeStructure/TreeStructure.js +9 -12
  67. package/es/TreeStructure/helperFunctions.js +1 -1
  68. package/es/ZendeskButton/ZendeskButton.js +55 -0
  69. package/es/i18n/formatNestedMessages.js +1 -1
  70. package/es/index.js +2 -1
  71. package/es/locale/messages-en.js +9 -8
  72. package/es/locale/messages-nb.js +9 -8
  73. package/es/locale/messages-nn.js +9 -8
  74. package/es/locale/messages-se.js +9 -8
  75. package/es/locale/messages-sma.js +9 -8
  76. package/es/styles.css +686 -0
  77. package/es/utils/relativeUrl.js +3 -3
  78. package/lib/Article/Article.js +3 -4
  79. package/lib/Article/ArticleByline.js +9 -9
  80. package/lib/Article/ArticleFootNotes.js +4 -4
  81. package/lib/AudioPlayer/AudioPlayer.d.ts +1 -2
  82. package/lib/AudioPlayer/AudioPlayer.js +142 -162
  83. package/lib/AudioPlayer/Controls.js +190 -205
  84. package/lib/AudioPlayer/SpeechControl.js +13 -11
  85. package/lib/BlogPost/BlogPost.d.ts +2 -2
  86. package/lib/BlogPost/BlogPost.js +85 -24
  87. package/lib/CampaignBlock/CampaignBlock.js +3 -4
  88. package/lib/CodeBlock/CodeBlock.d.ts +5 -8
  89. package/lib/CodeBlock/CodeBlock.js +88 -96
  90. package/lib/ContactBlock/ContactBlock.js +55 -43
  91. package/lib/ContentLoader/index.js +7 -7
  92. package/lib/CopyParagraphButton/CopyParagraphButton.js +4 -4
  93. package/lib/Embed/AudioEmbed.js +5 -9
  94. package/lib/Embed/BrightcoveEmbed.js +12 -15
  95. package/lib/Embed/CodeEmbed.js +56 -8
  96. package/lib/Embed/ConceptEmbed.js +15 -20
  97. package/lib/Embed/ContentLinkEmbed.js +1 -1
  98. package/lib/Embed/EmbedErrorPlaceholder.d.ts +4 -3
  99. package/lib/Embed/EmbedErrorPlaceholder.js +32 -18
  100. package/lib/Embed/ExternalEmbed.js +7 -10
  101. package/lib/Embed/FootnoteEmbed.js +3 -3
  102. package/lib/Embed/H5pEmbed.js +1 -2
  103. package/lib/Embed/IframeEmbed.js +8 -9
  104. package/lib/Embed/ImageEmbed.d.ts +1 -2
  105. package/lib/Embed/ImageEmbed.js +167 -123
  106. package/lib/Embed/RelatedContentEmbed.js +8 -10
  107. package/lib/Embed/UuDisclaimerEmbed.js +2 -2
  108. package/lib/Embed/conceptComponents.js +9 -9
  109. package/lib/ErrorMessage/ErrorMessage.js +1 -1
  110. package/lib/FactBox/FactBox.js +2 -2
  111. package/lib/FileList/File.js +1 -1
  112. package/lib/FileList/Format.js +3 -3
  113. package/lib/FrontpageArticle/FrontpageArticle.js +1 -1
  114. package/lib/Gloss/Gloss.js +9 -11
  115. package/lib/Gloss/GlossExample.js +3 -4
  116. package/lib/Grid/Grid.js +1 -1
  117. package/lib/Image/Image.js +7 -8
  118. package/lib/Image/ImageLink.js +1 -1
  119. package/lib/KeyFigure/KeyFigure.js +2 -2
  120. package/lib/LanguageSelector/LanguageSelector.js +2 -2
  121. package/lib/LetterFilter/LetterFilter.js +1 -1
  122. package/lib/LicenseByline/EmbedByline.js +5 -6
  123. package/lib/LicenseByline/LicenseDescription.js +1 -1
  124. package/lib/LicenseByline/LicenseLink.js +1 -2
  125. package/lib/Messages/MessageBox.js +1 -1
  126. package/lib/Notion/Notion.js +2 -2
  127. package/lib/Notion/NotionImage.d.ts +1 -11
  128. package/lib/Notion/NotionImage.js +12 -59
  129. package/lib/RelatedArticleList/RelatedArticleList.js +3 -3
  130. package/lib/ResourceBox/ResourceBox.js +13 -18
  131. package/lib/Search/ActiveFilters.js +1 -1
  132. package/lib/Search/ContentTypeResult.js +9 -6
  133. package/lib/Search/ContentTypeResultStyles.js +1 -1
  134. package/lib/Search/IsPathToHighlight.js +1 -1
  135. package/lib/Search/SearchField.js +6 -8
  136. package/lib/Search/SearchResult.js +14 -19
  137. package/lib/Search/SearchResultSleeve.js +14 -16
  138. package/lib/SnackBar/SnackbarProvider.js +8 -11
  139. package/lib/TagSelector/TagSelector.js +1 -1
  140. package/lib/TagSelector/ariaMessages.js +6 -6
  141. package/lib/TreeStructure/AddFolderButton.js +4 -6
  142. package/lib/TreeStructure/ComboboxButton.js +4 -7
  143. package/lib/TreeStructure/FolderItem.js +12 -15
  144. package/lib/TreeStructure/FolderItems.js +3 -3
  145. package/lib/TreeStructure/TreeStructure.js +9 -12
  146. package/lib/TreeStructure/helperFunctions.js +1 -1
  147. package/lib/ZendeskButton/ZendeskButton.d.ts +19 -0
  148. package/lib/ZendeskButton/ZendeskButton.js +61 -0
  149. package/lib/i18n/formatNestedMessages.js +1 -1
  150. package/lib/index.d.ts +2 -0
  151. package/lib/index.js +7 -0
  152. package/lib/locale/messages-en.d.ts +1 -0
  153. package/lib/locale/messages-en.js +9 -8
  154. package/lib/locale/messages-nb.d.ts +1 -0
  155. package/lib/locale/messages-nb.js +9 -8
  156. package/lib/locale/messages-nn.d.ts +1 -0
  157. package/lib/locale/messages-nn.js +9 -8
  158. package/lib/locale/messages-se.d.ts +1 -0
  159. package/lib/locale/messages-se.js +9 -8
  160. package/lib/locale/messages-sma.d.ts +1 -0
  161. package/lib/locale/messages-sma.js +9 -8
  162. package/lib/styles.css +686 -0
  163. package/lib/types.d.ts +1 -0
  164. package/lib/utils/relativeUrl.js +3 -3
  165. package/package.json +17 -12
  166. package/src/AudioPlayer/AudioPlayer.tsx +139 -176
  167. package/src/AudioPlayer/Controls.tsx +210 -250
  168. package/src/AudioPlayer/SpeechControl.tsx +9 -7
  169. package/src/BlogPost/BlogPost.tsx +82 -58
  170. package/src/CodeBlock/CodeBlock.stories.tsx +0 -43
  171. package/src/CodeBlock/CodeBlock.tsx +91 -202
  172. package/src/ContactBlock/ContactBlock.tsx +10 -2
  173. package/src/Embed/CodeEmbed.stories.tsx +95 -0
  174. package/src/Embed/CodeEmbed.tsx +62 -7
  175. package/src/Embed/ConceptEmbed.tsx +1 -9
  176. package/src/Embed/EmbedErrorPlaceholder.tsx +31 -28
  177. package/src/Embed/ImageEmbed.stories.tsx +53 -11
  178. package/src/Embed/ImageEmbed.tsx +162 -166
  179. package/src/Notion/NotionImage.tsx +4 -54
  180. package/src/ResourceBox/ResourceBox.tsx +3 -15
  181. package/src/Search/ContentTypeResult.tsx +9 -3
  182. package/src/Search/SearchResultSleeve.tsx +5 -2
  183. package/src/ZendeskButton/ZendeskButton.tsx +58 -0
  184. package/src/index.ts +4 -0
  185. package/src/locale/messages-en.ts +1 -0
  186. package/src/locale/messages-nb.ts +1 -0
  187. package/src/locale/messages-nn.ts +1 -0
  188. package/src/locale/messages-se.ts +1 -0
  189. package/src/locale/messages-sma.ts +1 -0
  190. package/src/types.ts +2 -0
  191. package/src/Image/__tests__/Image-test.tsx +0 -66
  192. package/src/Image/__tests__/__snapshots__/Image-test.tsx.snap +0 -194
@@ -8,188 +8,128 @@
8
8
 
9
9
  import { useEffect, useRef, useState } from "react";
10
10
  import { useTranslation } from "react-i18next";
11
- import styled from "@emotion/styled";
12
- import { Root as PopoverRoot, PopoverContent, PopoverTrigger, PopoverPortal } from "@radix-ui/react-popover";
13
- import { Root as SliderRoot, Track, Range, SliderThumb } from "@radix-ui/react-slider";
14
- import { ButtonV2, IconButtonV2 } from "@ndla/button";
15
- import { breakpoints, colors, fonts, misc, mq, spacing, stackOrder } from "@ndla/core";
16
- import { DropdownMenu, DropdownContent, DropdownItem, DropdownTrigger } from "@ndla/dropdown-menu";
11
+ import type { SliderValueChangeDetails } from "@ark-ui/react";
17
12
  import { Back15, Forward15 } from "@ndla/icons/action";
18
13
  import { Play, Pause, VolumeUp } from "@ndla/icons/common";
19
-
20
- const ControlsWrapper = styled.div`
21
- border: 1px solid ${colors.brand.lighter};
22
- display: flex;
23
- align-items: center;
24
- justify-content: center;
25
- background: ${colors.white};
26
- font-family: ${fonts.sans};
27
- gap: ${spacing.xsmall};
28
- padding: ${spacing.small} ${spacing.normal};
29
- ${mq.range({ until: breakpoints.tabletWide })} {
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 .";
36
- }
37
- `;
38
-
39
- const PlayButton = styled(IconButtonV2)`
40
- ${mq.range({ until: breakpoints.tabletWide })} {
41
- grid-area: play;
42
- }
43
- `;
44
-
45
- const Forward15SecButton = styled(IconButtonV2)`
46
- ${mq.range({ until: breakpoints.tabletWide })} {
47
- grid-area: forwards;
48
- }
49
- `;
50
- const Back15SecButton = styled(IconButtonV2)`
51
- ${mq.range({ until: breakpoints.tabletWide })} {
52
- grid-area: backwards;
53
- }
54
- `;
55
-
56
- const SpeedButton = styled(ButtonV2)`
57
- ${mq.range({ until: breakpoints.tabletWide })} {
58
- grid-area: speed;
59
- }
60
- `;
61
-
62
- const SpeedList = styled(DropdownContent)`
63
- border: 1px solid ${colors.brand.lighter};
64
- padding: 5px 10px;
65
- justify-content: center;
66
- `;
67
-
68
- const SpeedValueButton = styled(ButtonV2)`
69
- padding: 0 14px;
70
- gap: 0px;
71
- color: ${colors.text.light};
72
- display: flex;
73
- justify-content: center;
74
- &:hover,
75
- &:active,
76
- &:focus,
77
- &[data-highlighted] {
78
- outline: none;
79
- color: ${colors.text.primary};
80
- }
81
- `;
82
-
83
- const SpeedSelectedMark = styled.span`
84
- align-self: flex-start;
85
- border-radius: ${misc.borderRadiusLarge};
86
- background: #d1372e;
87
- width: 6px;
88
- height: 6px;
89
- margin: ${spacing.xsmall} 0 0 2px;
90
- `;
91
-
92
- const Time = styled.div`
93
- ${fonts.sizes("16px")};
94
- `;
95
-
96
- const ProgressWrapper = styled.div`
97
- flex: 1;
98
- display: flex;
99
- align-items: center;
100
- gap: ${spacing.small};
101
- ${mq.range({ until: breakpoints.tabletWide })} {
102
- grid-area: track;
103
- }
104
- `;
105
-
106
- const SliderWrapper = styled(SliderRoot)`
107
- cursor: pointer;
108
- flex: 1;
109
- position: relative;
110
- display: flex;
111
- align-items: center;
112
- user-select: none;
113
- touch-action: none;
114
- `;
115
-
116
- const StyledTrack = styled(Track)`
117
- height: 4px;
118
- width: 100%;
119
- background: ${colors.brand.lighter};
120
- border-radius: 7px;
121
- `;
122
-
123
- const StyledRange = styled(Range)`
124
- position: absolute;
125
- height: 4px;
126
- background: #5cbc80;
127
- border-radius: 7px;
128
- `;
129
-
130
- const StyledThumb = styled(SliderThumb)`
131
- display: block;
132
- width: 20px;
133
- height: 20px;
134
- background: #5cbc80;
135
- border-radius: ${misc.borderRadiusLarge};
136
- outline: none;
137
- `;
138
-
139
- const VolumeWrapper = styled(PopoverRoot)`
140
- position: relative;
141
- display: flex;
142
- justify-content: center;
143
- `;
144
-
145
- const VolumeList = styled(PopoverContent)`
146
- box-shadow: 0 14px 20px -5px rgba(32, 88, 143, 0.17);
147
- border-radius: 60px;
148
- background: ${colors.white};
149
- padding: ${spacing.small};
150
- border: 1px solid ${colors.brand.lighter};
151
- height: 128px;
152
- z-index: ${stackOrder.offsetDouble};
153
- `;
154
-
155
- const VolumeSliderWrapper = styled(SliderRoot)`
156
- cursor: pointer;
157
- height: 100%;
158
- position: relative;
159
- display: flex;
160
- flex-direction: column;
161
- align-items: center;
162
- user-select: none;
163
- touch-action: none;
164
- `;
165
-
166
- const VolumeButton = styled(IconButtonV2)`
167
- ${mq.range({ until: breakpoints.tabletWide })} {
168
- grid-area: volume;
169
- }
170
- `;
171
-
172
- const VolumeSliderBackground = styled(Track)`
173
- height: 100%;
174
- width: 5px;
175
- background: ${colors.brand.lighter};
176
- border-radius: 7px;
177
- `;
178
-
179
- const VolumeSliderSelected = styled(Range)`
180
- position: absolute;
181
- width: 5px;
182
- background: ${colors.brand.secondary};
183
- border-radius: 7px;
184
- `;
185
-
186
- const VolumeSliderHandle = styled(SliderThumb)`
187
- display: block;
188
- width: 20px;
189
- height: 20px;
190
- background: ${colors.brand.primary};
191
- border-radius: ${misc.borderRadiusLarge};
192
- `;
14
+ import { Done } from "@ndla/icons/editor";
15
+ import {
16
+ Button,
17
+ IconButton,
18
+ PopoverContent,
19
+ PopoverRoot,
20
+ PopoverTrigger,
21
+ SelectContent,
22
+ SelectControl,
23
+ SelectItem,
24
+ SelectItemIndicator,
25
+ SelectItemText,
26
+ SelectLabel,
27
+ SelectPositioner,
28
+ SelectRoot,
29
+ SelectTrigger,
30
+ SliderControl,
31
+ SliderHiddenInput,
32
+ SliderLabel,
33
+ SliderRange,
34
+ SliderRoot,
35
+ SliderThumb,
36
+ SliderTrack,
37
+ Text,
38
+ } from "@ndla/primitives";
39
+ import { styled } from "@ndla/styled-system/jsx";
40
+ import { visuallyHidden } from "@ndla/styled-system/patterns";
41
+
42
+ const ControlsWrapper = styled("div", {
43
+ base: {
44
+ borderBlockStart: "1px solid",
45
+ borderColor: "stroke.default",
46
+ borderBottomRadius: "xsmall",
47
+ display: "flex",
48
+ alignItems: "center",
49
+ justifyContent: "center",
50
+ background: "background.default",
51
+ gap: "xsmall",
52
+ paddingBlock: "xsmall",
53
+ paddingInline: "medium",
54
+ tabletWideDown: {
55
+ display: "grid",
56
+ paddingBlock: "xsmall",
57
+ paddingInline: "xsmall",
58
+ gridTemplateColumns: "1fr repeat(5, auto) 1fr",
59
+ gridTemplateAreas: `
60
+ "track track track track track track track"
61
+ ". speed backwards play forwards volume ."
62
+ `,
63
+ },
64
+ mobileWideDown: {
65
+ columnGap: "3xsmall",
66
+ },
67
+ },
68
+ });
69
+
70
+ const PlayButton = styled(IconButton, {
71
+ base: {
72
+ gridArea: "play",
73
+ },
74
+ });
75
+
76
+ const Forward15SecButton = styled(IconButton, {
77
+ base: {
78
+ gridArea: "forwards",
79
+ },
80
+ });
81
+
82
+ const Back15SecButton = styled(IconButton, {
83
+ base: {
84
+ gridArea: "backwards",
85
+ },
86
+ });
87
+
88
+ const ProgressWrapper = styled("div", {
89
+ base: {
90
+ flex: "1",
91
+ display: "flex",
92
+ alignItems: "center",
93
+ gap: "xsmall",
94
+ gridArea: "track",
95
+ paddingBlock: "xsmall",
96
+ mobileDown: {
97
+ paddingInline: "xsmall",
98
+ },
99
+ },
100
+ });
101
+
102
+ const VolumeButton = styled(IconButton, {
103
+ base: {
104
+ gridArea: "volume",
105
+ },
106
+ });
107
+
108
+ const SpeedButton = styled(Button, {
109
+ base: {
110
+ paddingBlock: "auto",
111
+ paddingInline: "auto",
112
+ maxWidth: "xxlarge",
113
+ maxHeight: "xxlarge",
114
+ minWidth: "xxlarge",
115
+ minHeight: "xxlarge",
116
+ "& span": {
117
+ flex: "1",
118
+ },
119
+ },
120
+ });
121
+
122
+ const StyledSelectRoot = styled(SelectRoot, {
123
+ base: {
124
+ gridArea: "speed",
125
+ },
126
+ });
127
+
128
+ const StyledSliderControl = styled(SliderControl, {
129
+ base: {
130
+ height: "surface.3xsmall",
131
+ },
132
+ });
193
133
 
194
134
  const formatTime = (seconds: number) => {
195
135
  const minutes = Math.floor(seconds / 60);
@@ -199,7 +139,7 @@ const formatTime = (seconds: number) => {
199
139
  return `${minutes}:${formattedSeconds}`;
200
140
  };
201
141
 
202
- const speedValues = [0.5, 0.75, 1, 1.25, 1.5, 1.75, 2];
142
+ const speedValues = ["0.5", "0.75", "1", "1.25", "1.5", "1.75", "2"];
203
143
 
204
144
  interface Props {
205
145
  src: string;
@@ -269,67 +209,38 @@ const Controls = ({ src, title }: Props) => {
269
209
  }
270
210
  };
271
211
 
272
- const handleSliderChange = (value: number[]) => {
212
+ const handleSliderChange = (details: SliderValueChangeDetails) => {
273
213
  if (audioRef.current) {
274
- audioRef.current.currentTime = value[0];
214
+ audioRef.current.currentTime = details.value[0];
275
215
  }
276
216
  };
277
217
 
278
- const handleVolumeSliderChange = (values: number[]) => {
218
+ const handleVolumeSliderChange = (details: SliderValueChangeDetails) => {
279
219
  if (audioRef.current) {
280
- audioRef.current.volume = values[0] / 100;
281
- setVolumeValue(values[0]);
220
+ audioRef.current.volume = details.value[0] / 100;
221
+ setVolumeValue(details.value[0]);
282
222
  }
283
223
  };
284
224
 
285
225
  return (
286
226
  <div>
227
+ {/* TODO: We should tie this up to the textual description somehow */}
287
228
  {/* eslint-disable-next-line jsx-a11y/media-has-caption */}
288
229
  <audio ref={audioRef} src={src} title={title} preload="metadata" />
289
230
  <ControlsWrapper>
290
- <PlayButton
291
- aria-label={t(playing ? t("audio.pause") : t("audio.play"))}
292
- colorTheme="lighter"
293
- size="normal"
294
- onClick={togglePlay}
295
- >
296
- {playing ? <Pause /> : <Play />}
297
- </PlayButton>
298
231
  <Back15SecButton
299
- variant="ghost"
300
- colorTheme="greyLighter"
232
+ variant="tertiary"
301
233
  title={t("audio.controls.rewind15sec")}
302
234
  aria-label={t("audio.controls.rewind15sec")}
303
235
  onClick={() => onSeekSeconds(-15)}
304
236
  >
305
237
  <Back15 />
306
238
  </Back15SecButton>
307
- <DropdownMenu>
308
- <DropdownTrigger>
309
- <SpeedButton
310
- shape="pill"
311
- variant="ghost"
312
- size="normal"
313
- colorTheme="greyLighter"
314
- title={t("audio.controls.selectSpeed")}
315
- aria-label={t("audio.controls.selectSpeed")}
316
- >
317
- {speedValue}x
318
- </SpeedButton>
319
- </DropdownTrigger>
320
- <SpeedList side="top">
321
- {speedValues.map((speed) => (
322
- <DropdownItem key={speed} onSelect={() => setSpeedValue(speed)}>
323
- <SpeedValueButton variant="ghost" colorTheme="greyLighter" size="small">
324
- {speed}x{speed === speedValue && <SpeedSelectedMark />}
325
- </SpeedValueButton>
326
- </DropdownItem>
327
- ))}
328
- </SpeedList>
329
- </DropdownMenu>
239
+ <PlayButton aria-label={t(playing ? t("audio.pause") : t("audio.play"))} variant="primary" onClick={togglePlay}>
240
+ {playing ? <Pause /> : <Play />}
241
+ </PlayButton>
330
242
  <Forward15SecButton
331
- colorTheme="greyLighter"
332
- variant="ghost"
243
+ variant="tertiary"
333
244
  title={t("audio.controls.forward15sec")}
334
245
  aria-label={t("audio.controls.forward15sec")}
335
246
  onClick={() => onSeekSeconds(15)}
@@ -337,45 +248,94 @@ const Controls = ({ src, title }: Props) => {
337
248
  <Forward15 />
338
249
  </Forward15SecButton>
339
250
  <ProgressWrapper>
340
- <Time>{formatTime(currentTime)}</Time>
341
- <SliderWrapper
251
+ <Text textStyle="label.medium" asChild consumeCss>
252
+ <div>{formatTime(currentTime)}</div>
253
+ </Text>
254
+ <SliderRoot
342
255
  value={[audioRef.current?.currentTime ?? 0]}
343
256
  defaultValue={[0]}
344
257
  step={1}
345
- max={audioRef.current?.duration ?? 0}
258
+ max={Math.round(audioRef.current?.duration ?? 0)}
346
259
  onValueChange={handleSliderChange}
260
+ getAriaValueText={(value) =>
261
+ t("audio.valueText", {
262
+ start: formatTime(Math.round(value.value)),
263
+ end: formatTime(Math.round(audioRef.current?.duration ?? 0)),
264
+ })
265
+ }
347
266
  >
348
- <StyledTrack>
349
- <StyledRange />
350
- </StyledTrack>
351
- <StyledThumb />
352
- </SliderWrapper>
353
- <Time>-{formatTime(remainingTime)}</Time>
267
+ <SliderControl>
268
+ <SliderTrack>
269
+ <SliderRange />
270
+ </SliderTrack>
271
+ <SliderThumb index={0}>
272
+ <SliderHiddenInput />
273
+ </SliderThumb>
274
+ </SliderControl>
275
+ </SliderRoot>
276
+ <Text textStyle="label.medium" asChild consumeCss>
277
+ <div>-{formatTime(remainingTime)}</div>
278
+ </Text>
354
279
  </ProgressWrapper>
355
- <VolumeWrapper>
280
+ <StyledSelectRoot
281
+ items={speedValues}
282
+ value={[speedValue.toString()]}
283
+ onValueChange={(details) => setSpeedValue(parseFloat(details.value[0]))}
284
+ positioning={{ placement: "top" }}
285
+ >
286
+ <SelectLabel css={visuallyHidden.raw()}>{t("audio.controls.selectSpeed")}</SelectLabel>
287
+ <SelectControl>
288
+ <SelectTrigger asChild>
289
+ <SpeedButton
290
+ variant="tertiary"
291
+ title={t("audio.controls.selectSpeed")}
292
+ aria-label={t("audio.controls.selectSpeed")}
293
+ >
294
+ <span>{`${speedValue}x`}</span>
295
+ </SpeedButton>
296
+ </SelectTrigger>
297
+ </SelectControl>
298
+ <SelectPositioner>
299
+ <SelectContent>
300
+ {speedValues.map((speed) => (
301
+ <SelectItem key={speed} item={speed}>
302
+ <SelectItemText>{speed}x</SelectItemText>
303
+ <SelectItemIndicator>
304
+ <Done />
305
+ </SelectItemIndicator>
306
+ </SelectItem>
307
+ ))}
308
+ </SelectContent>
309
+ </SelectPositioner>
310
+ </StyledSelectRoot>
311
+ <PopoverRoot positioning={{ placement: "top" }}>
356
312
  <PopoverTrigger asChild>
357
- <VolumeButton variant="ghost" colorTheme="greyLighter" aria-label={t("audio.controls.adjustVolume")}>
313
+ <VolumeButton variant="tertiary" aria-label={t("audio.controls.adjustVolume")}>
358
314
  <VolumeUp />
359
315
  </VolumeButton>
360
316
  </PopoverTrigger>
361
- <PopoverPortal>
362
- <VolumeList side="top">
363
- <VolumeSliderWrapper
364
- orientation="vertical"
365
- value={[volumeValue]}
366
- min={0}
367
- defaultValue={[100]}
368
- step={1}
369
- onValueChange={handleVolumeSliderChange}
370
- >
371
- <VolumeSliderBackground>
372
- <VolumeSliderSelected />
373
- </VolumeSliderBackground>
374
- <VolumeSliderHandle />
375
- </VolumeSliderWrapper>
376
- </VolumeList>
377
- </PopoverPortal>
378
- </VolumeWrapper>
317
+ <PopoverContent>
318
+ <SliderRoot
319
+ orientation="vertical"
320
+ value={[volumeValue]}
321
+ min={0}
322
+ max={100}
323
+ defaultValue={[100]}
324
+ step={1}
325
+ onValueChange={handleVolumeSliderChange}
326
+ >
327
+ <SliderLabel css={visuallyHidden.raw()}>{t("audio.controls.adjustVolume")}</SliderLabel>
328
+ <StyledSliderControl>
329
+ <SliderTrack>
330
+ <SliderRange />
331
+ </SliderTrack>
332
+ <SliderThumb index={0}>
333
+ <SliderHiddenInput />
334
+ </SliderThumb>
335
+ </StyledSliderControl>
336
+ </SliderRoot>
337
+ </PopoverContent>
338
+ </PopoverRoot>
379
339
  </ControlsWrapper>
380
340
  </div>
381
341
  );
@@ -8,9 +8,8 @@
8
8
 
9
9
  import { useRef } from "react";
10
10
  import { useTranslation } from "react-i18next";
11
- import { IconButtonV2 } from "@ndla/button";
12
11
  import { VolumeUp } from "@ndla/icons/common";
13
- import { Tooltip } from "@ndla/tooltip";
12
+ import { TooltipRoot, TooltipTrigger, TooltipContent, IconButton } from "@ndla/primitives";
14
13
 
15
14
  type Props = {
16
15
  src: string;
@@ -36,11 +35,14 @@ const SpeechControl = ({ src, title, type = "audio" }: Props) => {
36
35
  <div>
37
36
  {/* eslint-disable-next-line jsx-a11y/media-has-caption */}
38
37
  <audio ref={audioRef} src={src} title={title} preload="metadata" />
39
- <Tooltip tooltip={t(`${type}.play`)}>
40
- <IconButtonV2 type="button" onClick={togglePlay} aria-label={t(`${type}.play`)} variant="ghost">
41
- <VolumeUp />
42
- </IconButtonV2>
43
- </Tooltip>
38
+ <TooltipRoot>
39
+ <TooltipTrigger asChild>
40
+ <IconButton variant="tertiary" aria-label={t(`${type}.play`)} onClick={togglePlay}>
41
+ <VolumeUp />
42
+ </IconButton>
43
+ </TooltipTrigger>
44
+ <TooltipContent>{t(`${type}.play`)}</TooltipContent>
45
+ </TooltipRoot>
44
46
  </div>
45
47
  );
46
48
  };