@ndla/ui 42.1.1 → 43.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 (71) hide show
  1. package/es/AudioPlayer/AudioPlayer.js +27 -33
  2. package/es/AudioPlayer/Controls.js +41 -39
  3. package/es/Breadcrumb/index.js +0 -1
  4. package/es/CampaignBlock/CampaignBlock.js +32 -18
  5. package/es/LanguageSelector/LanguageSelector.js +31 -36
  6. package/es/LicenseByline/EmbedByline.js +5 -5
  7. package/es/MyNdla/Resource/Folder.js +27 -72
  8. package/es/MyNdla/index.js +1 -3
  9. package/es/Resource/BlockResource.js +15 -27
  10. package/es/Resource/ListResource.js +14 -19
  11. package/es/Resource/resourceComponents.js +82 -41
  12. package/es/TreeStructure/ComboboxButton.js +17 -20
  13. package/es/TreeStructure/FolderItem.js +42 -69
  14. package/es/TreeStructure/FolderItems.js +25 -19
  15. package/es/TreeStructure/TreeStructure.js +19 -26
  16. package/es/index.js +2 -2
  17. package/lib/AudioPlayer/AudioPlayer.js +27 -33
  18. package/lib/AudioPlayer/Controls.js +40 -38
  19. package/lib/Breadcrumb/index.d.ts +0 -1
  20. package/lib/Breadcrumb/index.js +0 -7
  21. package/lib/CampaignBlock/CampaignBlock.js +32 -18
  22. package/lib/LanguageSelector/LanguageSelector.js +31 -36
  23. package/lib/LicenseByline/EmbedByline.js +5 -5
  24. package/lib/MyNdla/Resource/Folder.d.ts +3 -4
  25. package/lib/MyNdla/Resource/Folder.js +27 -72
  26. package/lib/MyNdla/index.d.ts +1 -3
  27. package/lib/MyNdla/index.js +0 -14
  28. package/lib/Resource/BlockResource.d.ts +3 -3
  29. package/lib/Resource/BlockResource.js +14 -26
  30. package/lib/Resource/ListResource.d.ts +3 -3
  31. package/lib/Resource/ListResource.js +13 -18
  32. package/lib/Resource/resourceComponents.d.ts +5 -10
  33. package/lib/Resource/resourceComponents.js +85 -42
  34. package/lib/TreeStructure/ComboboxButton.js +17 -20
  35. package/lib/TreeStructure/FolderItem.js +40 -67
  36. package/lib/TreeStructure/FolderItems.js +31 -26
  37. package/lib/TreeStructure/TreeStructure.js +19 -26
  38. package/lib/index.d.ts +2 -2
  39. package/lib/index.js +0 -12
  40. package/package.json +16 -17
  41. package/src/AudioPlayer/AudioPlayer.tsx +24 -34
  42. package/src/AudioPlayer/Controls.tsx +22 -26
  43. package/src/Breadcrumb/index.ts +0 -2
  44. package/src/CampaignBlock/CampaignBlock.tsx +10 -10
  45. package/src/LanguageSelector/LanguageSelector.tsx +26 -32
  46. package/src/LicenseByline/EmbedByline.tsx +1 -1
  47. package/src/MyNdla/Resource/Folder.stories.tsx +27 -5
  48. package/src/MyNdla/Resource/Folder.tsx +32 -54
  49. package/src/MyNdla/index.ts +1 -3
  50. package/src/Resource/BlockResource.stories.tsx +1 -1
  51. package/src/Resource/BlockResource.tsx +25 -24
  52. package/src/Resource/ListResource.tsx +21 -18
  53. package/src/Resource/Resource.stories.tsx +32 -2
  54. package/src/Resource/resourceComponents.tsx +55 -26
  55. package/src/TreeStructure/ComboboxButton.tsx +5 -7
  56. package/src/TreeStructure/FolderItem.tsx +50 -35
  57. package/src/TreeStructure/FolderItems.tsx +6 -8
  58. package/src/TreeStructure/TreeStructure.tsx +16 -25
  59. package/src/index.ts +2 -2
  60. package/es/Breadcrumb/ActionBreadcrumb.js +0 -74
  61. package/es/MyNdla/Resource/FolderMenu.js +0 -74
  62. package/es/MyNdla/SettingsMenu.js +0 -98
  63. package/lib/Breadcrumb/ActionBreadcrumb.d.ts +0 -15
  64. package/lib/Breadcrumb/ActionBreadcrumb.js +0 -82
  65. package/lib/MyNdla/Resource/FolderMenu.d.ts +0 -16
  66. package/lib/MyNdla/Resource/FolderMenu.js +0 -81
  67. package/lib/MyNdla/SettingsMenu.d.ts +0 -15
  68. package/lib/MyNdla/SettingsMenu.js +0 -102
  69. package/src/Breadcrumb/ActionBreadcrumb.tsx +0 -87
  70. package/src/MyNdla/Resource/FolderMenu.tsx +0 -102
  71. package/src/MyNdla/SettingsMenu.tsx +0 -96
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ndla/ui",
3
- "version": "42.1.1",
3
+ "version": "43.0.0",
4
4
  "description": "UI component library for NDLA.",
5
5
  "license": "GPL-3.0",
6
6
  "main": "lib/index.js",
@@ -31,23 +31,23 @@
31
31
  "types"
32
32
  ],
33
33
  "dependencies": {
34
- "@ndla/accordion": "^2.2.13",
35
- "@ndla/article-scripts": "^3.0.18",
36
- "@ndla/button": "^10.1.12",
37
- "@ndla/carousel": "^3.1.10",
34
+ "@ndla/accordion": "^2.2.15",
35
+ "@ndla/article-scripts": "^3.0.19",
36
+ "@ndla/button": "^11.0.0",
37
+ "@ndla/carousel": "^3.1.11",
38
38
  "@ndla/core": "^4.1.4",
39
- "@ndla/forms": "^4.3.13",
40
- "@ndla/hooks": "^2.0.7",
41
- "@ndla/icons": "^4.0.0",
39
+ "@ndla/dropdown-menu": "^1.0.0",
40
+ "@ndla/forms": "^4.3.15",
41
+ "@ndla/hooks": "^2.0.8",
42
+ "@ndla/icons": "^4.0.1",
42
43
  "@ndla/licenses": "^7.1.1",
43
- "@ndla/modal": "^3.0.10",
44
- "@ndla/notion": "^5.0.11",
45
- "@ndla/safelink": "^4.1.12",
44
+ "@ndla/modal": "^3.0.11",
45
+ "@ndla/notion": "^5.0.13",
46
+ "@ndla/safelink": "^4.1.14",
46
47
  "@ndla/switch": "^1.1.8",
47
48
  "@ndla/tabs": "^3.0.4",
48
- "@ndla/tooltip": "^4.1.12",
49
- "@ndla/util": "^3.1.13",
50
- "@radix-ui/react-dropdown-menu": "^2.0.5",
49
+ "@ndla/tooltip": "^4.1.13",
50
+ "@ndla/util": "^3.1.14",
51
51
  "@radix-ui/react-popover": "^1.0.6",
52
52
  "@radix-ui/react-slider": "^1.1.2",
53
53
  "focus-trap-react": "^8.9.2",
@@ -67,8 +67,7 @@
67
67
  "i18next": "^21.9.2",
68
68
  "lodash": "^4.17.20",
69
69
  "react": ">= 16.8.0",
70
- "react-i18next": "^11.18.6",
71
- "react-router-dom": "^6.3.0"
70
+ "react-i18next": "^11.18.6"
72
71
  },
73
72
  "devDependencies": {
74
73
  "@babel/plugin-proposal-optional-chaining": "^7.11.0",
@@ -83,5 +82,5 @@
83
82
  "publishConfig": {
84
83
  "access": "public"
85
84
  },
86
- "gitHead": "4c4276e39a7529a8043ef1dcc3c1e9858f2ddca8"
85
+ "gitHead": "2aa95438581ea00bd5f1eac85a1514511bfe0de2"
87
86
  }
@@ -53,22 +53,17 @@ const ImageWrapper = styled.div`
53
53
  }
54
54
  `;
55
55
 
56
- type TextWrapperProps = {
57
- hasImage?: boolean;
58
- };
59
-
60
- const TextWrapper = styled.div<TextWrapperProps>`
56
+ const TextWrapper = styled.div`
61
57
  padding: ${spacing.small};
62
58
  width: 100%;
63
-
64
- ${(props) =>
65
- props.hasImage &&
66
- `${mq.range({ from: breakpoints.tablet })} {
67
- padding: ${spacing.small} ${spacing.normal};
59
+ &[data-has-image='true'] {
60
+ ${mq.range({ from: breakpoints.tablet })} {
61
+ padding: ${spacing.small} ${spacing.normal};
62
+ }
63
+ ${mq.range({ from: breakpoints.tabletWide })} {
64
+ padding: ${spacing.small} ${spacing.medium};
65
+ }
68
66
  }
69
- ${mq.range({ from: breakpoints.tabletWide })} {
70
- padding: ${spacing.small} ${spacing.medium};
71
- }`}
72
67
  `;
73
68
 
74
69
  const TitleWrapper = styled.div`
@@ -78,13 +73,12 @@ const TitleWrapper = styled.div`
78
73
  }
79
74
  `;
80
75
 
81
- type TitleProps = {
82
- hasDescription?: boolean;
83
- };
84
-
85
- const Title = styled.h2<TitleProps>`
76
+ const Title = styled.h2`
86
77
  ${fonts.sizes('22px', '30px')};
87
- margin: 0 0 ${(props) => props.hasDescription && `${spacing.small}`};
78
+ margin: 0px;
79
+ &[data-has-desc='true'] {
80
+ margin: 0 0 ${spacing.small};
81
+ }
88
82
  `;
89
83
 
90
84
  const Subtitle = styled.h3`
@@ -99,14 +93,10 @@ const StyledDescription = styled.div`
99
93
  margin: 0;
100
94
  `;
101
95
 
102
- type LinkToTextVersionWrapperProps = {
103
- noMargin?: boolean;
104
- };
105
- const LinkToTextVersionWrapper = styled.div<LinkToTextVersionWrapperProps>`
106
- ${(props) =>
107
- !props.noMargin &&
108
- `margin-top: ${spacing.normal};
109
- `}
96
+ const LinkToTextVersionWrapper = styled.div`
97
+ &[data-margin='true'] {
98
+ margin-top: ${spacing.small};
99
+ }
110
100
  ${mq.range({ until: breakpoints.tabletWide })} {
111
101
  margin: ${spacing.small} 0;
112
102
  }
@@ -201,10 +191,10 @@ const AudioPlayer = ({ src, title, subtitle, speech, description, img, textVersi
201
191
  };
202
192
 
203
193
  type TextVersionComponentProps = {
204
- noMargin?: boolean;
194
+ margin?: boolean;
205
195
  };
206
- const TextVersionComponent = ({ noMargin }: TextVersionComponentProps) => (
207
- <LinkToTextVersionWrapper noMargin={noMargin}>
196
+ const TextVersionComponent = ({ margin }: TextVersionComponentProps) => (
197
+ <LinkToTextVersionWrapper data-margin={margin}>
208
198
  <ButtonV2 size="normal" shape="pill" onClick={toggleTextVersion} data-audio-text-button-id={staticRenderId}>
209
199
  {t('audio.textVersion.heading')}
210
200
  </ButtonV2>
@@ -219,7 +209,7 @@ const AudioPlayer = ({ src, title, subtitle, speech, description, img, textVersi
219
209
  <img src={img.url} alt={img.alt} />
220
210
  </ImageWrapper>
221
211
  )}
222
- <TextWrapper hasImage={!!img}>
212
+ <TextWrapper data-has-image={!!img}>
223
213
  <TitleWrapper>
224
214
  <div>
225
215
  {subtitle && (
@@ -227,9 +217,9 @@ const AudioPlayer = ({ src, title, subtitle, speech, description, img, textVersi
227
217
  {subtitle.url ? <SafeLink to={subtitle.url}>{subtitle.title}</SafeLink> : subtitle.title}
228
218
  </Subtitle>
229
219
  )}
230
- <Title hasDescription={!!description}>{title}</Title>
220
+ <Title data-has-desc={!!description}>{title}</Title>
231
221
  </div>
232
- {textVersion && !img && <TextVersionComponent noMargin />}
222
+ {textVersion && !img && <TextVersionComponent />}
233
223
  </TitleWrapper>
234
224
  {description && (
235
225
  <StyledDescription>
@@ -241,7 +231,7 @@ const AudioPlayer = ({ src, title, subtitle, speech, description, img, textVersi
241
231
  </ButtonV2>
242
232
  </StyledDescription>
243
233
  )}
244
- {textVersion && img && <TextVersionComponent />}
234
+ {textVersion && img && <TextVersionComponent margin />}
245
235
  </TextWrapper>
246
236
  </InfoWrapper>
247
237
  <div data-audio-player={1} data-src={src} data-title={title}>
@@ -8,14 +8,14 @@
8
8
 
9
9
  import React, { useEffect, useRef, useState } from 'react';
10
10
  import styled from '@emotion/styled';
11
- import { Root, Trigger, Item, Content, DropdownMenuPortal } from '@radix-ui/react-dropdown-menu';
12
11
  import { Root as SliderRoot, Track, Range, SliderThumb } from '@radix-ui/react-slider';
13
12
  import { Root as PopoverRoot, PopoverContent, PopoverTrigger, PopoverPortal } from '@radix-ui/react-popover';
14
13
  import { Play, Pause, VolumeUp } from '@ndla/icons/common';
15
- import { breakpoints, colors, fonts, misc, mq, spacing } from '@ndla/core';
14
+ import { breakpoints, colors, fonts, mq, spacing } from '@ndla/core';
16
15
  import { useTranslation } from 'react-i18next';
17
16
  import { Back15, Forward15 } from '@ndla/icons/action';
18
17
  import { ButtonV2, IconButtonV2 } from '@ndla/button';
18
+ import { DropdownMenu, DropdownContent, DropdownItem, DropdownTrigger } from '@ndla/dropdown-menu';
19
19
 
20
20
  const ControlsWrapper = styled.div`
21
21
  border: 1px solid ${colors.brand.lighter};
@@ -59,22 +59,15 @@ const SpeedButton = styled(ButtonV2)`
59
59
  }
60
60
  `;
61
61
 
62
- const SpeedList = styled(Content)`
63
- background: ${colors.white};
62
+ const SpeedList = styled(DropdownContent)`
64
63
  border: 1px solid ${colors.brand.lighter};
65
- border-radius: ${misc.borderRadius};
66
64
  padding: 5px 10px;
67
- display: flex;
68
- flex-direction: column;
69
65
  justify-content: center;
70
66
  `;
71
67
 
72
- const SpeedValueButton = styled(Item)`
73
- height: 28px;
68
+ const SpeedValueButton = styled(ButtonV2)`
74
69
  padding: 0 14px;
75
- cursor: pointer;
76
- font-weight: ${fonts.weight.semibold};
77
- ${fonts.sizes('14px')};
70
+ gap: 0px;
78
71
  color: ${colors.text.light};
79
72
  display: flex;
80
73
  justify-content: center;
@@ -82,14 +75,13 @@ const SpeedValueButton = styled(Item)`
82
75
  &:active,
83
76
  &:focus,
84
77
  &[data-highlighted] {
85
- background: ${colors.brand.greyLighter};
86
- border-radius: 5px;
87
78
  outline: none;
88
79
  color: ${colors.text.primary};
89
80
  }
90
81
  `;
91
82
 
92
83
  const SpeedSelectedMark = styled.span`
84
+ align-self: flex-start;
93
85
  border-radius: 50%;
94
86
  background: #d1372e;
95
87
  width: 6px;
@@ -311,9 +303,8 @@ const Controls = ({ src, title }: Props) => {
311
303
  >
312
304
  <Back15 />
313
305
  </Back15SecButton>
314
-
315
- <Root>
316
- <Trigger asChild>
306
+ <DropdownMenu>
307
+ <DropdownTrigger>
317
308
  <SpeedButton
318
309
  shape="pill"
319
310
  variant="ghost"
@@ -324,17 +315,22 @@ const Controls = ({ src, title }: Props) => {
324
315
  >
325
316
  {speedValue}x
326
317
  </SpeedButton>
327
- </Trigger>
328
- <DropdownMenuPortal>
329
- <SpeedList side="top">
330
- {speedValues.map((speed) => (
331
- <SpeedValueButton key={speed} onSelect={() => setSpeedValue(speed)}>
318
+ </DropdownTrigger>
319
+ <SpeedList side="top">
320
+ {speedValues.map((speed) => (
321
+ <DropdownItem key={speed}>
322
+ <SpeedValueButton
323
+ variant="ghost"
324
+ colorTheme="greyLighter"
325
+ size="small"
326
+ onSelect={() => setSpeedValue(speed)}
327
+ >
332
328
  {speed}x{speed === speedValue && <SpeedSelectedMark />}
333
329
  </SpeedValueButton>
334
- ))}
335
- </SpeedList>
336
- </DropdownMenuPortal>
337
- </Root>
330
+ </DropdownItem>
331
+ ))}
332
+ </SpeedList>
333
+ </DropdownMenu>
338
334
  <Forward15SecButton
339
335
  colorTheme="greyLighter"
340
336
  variant="ghost"
@@ -14,6 +14,4 @@ export { default as HeaderBreadcrumb } from './HeaderBreadcrumb';
14
14
 
15
15
  export { default as HomeBreadcrumb } from './HomeBreadcrumb';
16
16
 
17
- export { default as ActionBreadcrumb } from './ActionBreadcrumb';
18
-
19
17
  export default Breadcrumb;
@@ -18,6 +18,7 @@ interface Image {
18
18
  src: string;
19
19
  alt: string;
20
20
  }
21
+
21
22
  interface Props {
22
23
  title: {
23
24
  title: string;
@@ -62,12 +63,7 @@ const StyledDescription = styled.p`
62
63
 
63
64
  const StyledImg = styled.img`
64
65
  max-height: 200px;
65
- ${mq.range({ until: breakpoints.tabletWide })} {
66
- align-self: center;
67
- }
68
- ${mq.range({ from: breakpoints.tabletWide })} {
69
- align-self: center;
70
- }
66
+ align-self: center;
71
67
  `;
72
68
 
73
69
  const StyledLink = styled(SafeLink)`
@@ -84,6 +80,10 @@ const StyledLink = styled(SafeLink)`
84
80
  }
85
81
  `;
86
82
 
83
+ const TextWrapper = styled.div`
84
+ flex-grow: 1;
85
+ `;
86
+
87
87
  const CampaignBlock = ({
88
88
  title,
89
89
  imageBefore,
@@ -95,16 +95,16 @@ const CampaignBlock = ({
95
95
  }: Props) => {
96
96
  return (
97
97
  <Container className={className}>
98
- {imageBefore && <StyledImg src={imageBefore.src} data-left={true} />}
99
- <div>
98
+ {imageBefore && <StyledImg src={imageBefore.src} />}
99
+ <TextWrapper>
100
100
  <Heading css={headingStyle}>{title.title}</Heading>
101
101
  <StyledDescription>{description.text}</StyledDescription>
102
102
  <StyledLink to={url.url}>
103
103
  {url.text}
104
104
  <Forward />
105
105
  </StyledLink>
106
- </div>
107
- {imageAfter && <StyledImg src={imageAfter.src} data-right={true} />}
106
+ </TextWrapper>
107
+ {imageAfter && <StyledImg src={imageAfter.src} />}
108
108
  </Container>
109
109
  );
110
110
  };
@@ -7,7 +7,7 @@
7
7
  */
8
8
 
9
9
  import React from 'react';
10
- import { Root, Trigger, Item, Content, Portal, Arrow } from '@radix-ui/react-dropdown-menu';
10
+ import { DropdownMenu, DropdownTrigger, DropdownContent, DropdownItem } from '@ndla/dropdown-menu';
11
11
  import { ButtonV2 } from '@ndla/button';
12
12
  import { useTranslation } from 'react-i18next';
13
13
  import { ChevronDown } from '@ndla/icons/common';
@@ -20,15 +20,12 @@ interface Props<T extends string> {
20
20
  inverted?: boolean;
21
21
  }
22
22
 
23
- const PopoverContent = styled(Content)`
24
- z-index: 9999;
25
- display: flex;
26
- flex-direction: column;
27
- overflow: hidden;
28
- background-color: ${colors.white};
23
+ const StyledDropdownContent = styled(DropdownContent)`
29
24
  border-radius: ${spacing.small};
30
25
  border: 1px solid ${colors.brand.tertiary};
31
- fill: ${colors.brand.tertiary};
26
+ [data-arrow] {
27
+ fill: ${colors.brand.tertiary};
28
+ }
32
29
  `;
33
30
 
34
31
  const LanguageChoice = styled(ButtonV2)`
@@ -67,33 +64,30 @@ const Text = styled.span`
67
64
  const LanguageSelector = <T extends string>({ locales, onSelect, inverted }: Props<T>) => {
68
65
  const { t, i18n } = useTranslation();
69
66
  return (
70
- <Root>
71
- <Trigger asChild>
67
+ <DropdownMenu>
68
+ <DropdownTrigger>
72
69
  <ButtonV2 variant="outline" shape="pill" inverted={inverted} aria-label={t('footer.selectLanguage')}>
73
70
  {t(`languages.prefixChangeLanguage`)} <ChevronDown />
74
71
  </ButtonV2>
75
- </Trigger>
76
- <Portal>
77
- <PopoverContent sideOffset={4}>
78
- <Arrow aria-hidden />
79
- {locales.map((locale) => (
80
- <Item asChild key={locale}>
81
- <LanguageChoice
82
- role="link"
83
- aria-current={i18n.language === locale}
84
- variant="ghost"
85
- shape="sharp"
86
- aria-label={t(`changeLanguage.${locale}`)}
87
- onClick={() => onSelect(locale)}
88
- >
89
- <ActivityIndicator>{i18n.language === locale && <ActiveIndicator />}</ActivityIndicator>
90
- <Text>{t(`languages.${locale}`)}</Text>
91
- </LanguageChoice>
92
- </Item>
93
- ))}
94
- </PopoverContent>
95
- </Portal>
96
- </Root>
72
+ </DropdownTrigger>
73
+ <StyledDropdownContent sideOffset={4} showArrow>
74
+ {locales.map((locale) => (
75
+ <DropdownItem key={locale}>
76
+ <LanguageChoice
77
+ role="link"
78
+ aria-current={i18n.language === locale}
79
+ variant="ghost"
80
+ shape="sharp"
81
+ aria-label={t(`changeLanguage.${locale}`)}
82
+ onClick={() => onSelect(locale)}
83
+ >
84
+ <ActivityIndicator>{i18n.language === locale && <ActiveIndicator />}</ActivityIndicator>
85
+ <Text>{t(`languages.${locale}`)}</Text>
86
+ </LanguageChoice>
87
+ </DropdownItem>
88
+ ))}
89
+ </StyledDropdownContent>
90
+ </DropdownMenu>
97
91
  );
98
92
  };
99
93
 
@@ -124,7 +124,7 @@ const StyledSpan = styled.span`
124
124
 
125
125
  const LicenseInformationWrapper = styled.div`
126
126
  flex: 1;
127
- padding-right: ${spacing.xsmall}}
127
+ padding-right: ${spacing.xsmall};
128
128
  `;
129
129
 
130
130
  const EmbedByline = ({
@@ -2,6 +2,9 @@ import React from 'react';
2
2
  import { Meta, StoryFn } from '@storybook/react';
3
3
  import { Pencil } from '@ndla/icons/action';
4
4
  import { DeleteForever } from '@ndla/icons/editor';
5
+ import { DropdownMenu, DropdownTrigger, DropdownContent, DropdownItem } from '@ndla/dropdown-menu';
6
+ import { ButtonV2, IconButtonV2 } from '@ndla/button';
7
+ import { HorizontalMenu } from '@ndla/icons/contentType';
5
8
  import { defaultParameters } from '../../../../../stories/defaults';
6
9
 
7
10
  import Folder from './Folder';
@@ -14,7 +17,7 @@ export default {
14
17
  ...defaultParameters,
15
18
  },
16
19
  argTypes: {
17
- menuItems: {
20
+ menu: {
18
21
  control: false,
19
22
  },
20
23
  },
@@ -26,10 +29,29 @@ export default {
26
29
  description: '',
27
30
  link: '',
28
31
  type: 'list',
29
- menuItems: [
30
- { icon: <Pencil />, text: 'Rediger', onClick: () => {} },
31
- { icon: <DeleteForever />, text: 'Slett', onClick: () => {}, type: 'danger' },
32
- ],
32
+ menu: (
33
+ <DropdownMenu>
34
+ <DropdownTrigger>
35
+ <IconButtonV2 aria-label="Show more" title="Show more" variant="ghost" colorTheme="light">
36
+ <HorizontalMenu />
37
+ </IconButtonV2>
38
+ </DropdownTrigger>
39
+ <DropdownContent>
40
+ <DropdownItem>
41
+ <ButtonV2 variant="ghost" colorTheme="light" shape="sharp" size="small" fontWeight="normal">
42
+ <Pencil />
43
+ Rediger
44
+ </ButtonV2>
45
+ </DropdownItem>
46
+ <DropdownItem>
47
+ <ButtonV2 variant="ghost" colorTheme="danger" shape="sharp" size="small" fontWeight="normal">
48
+ <DeleteForever />
49
+ Slett
50
+ </ButtonV2>
51
+ </DropdownItem>
52
+ </DropdownContent>
53
+ </DropdownMenu>
54
+ ),
33
55
  isShared: true,
34
56
  },
35
57
  } as Meta<typeof Folder>;
@@ -7,42 +7,32 @@
7
7
  */
8
8
 
9
9
  import styled from '@emotion/styled';
10
- import React from 'react';
10
+ import React, { ReactNode } from 'react';
11
11
  import { FolderOutlined, FolderShared } from '@ndla/icons/contentType';
12
12
  import { FileDocumentOutline, Share } from '@ndla/icons/common';
13
13
  import { fonts, spacing, colors, mq, breakpoints } from '@ndla/core';
14
- import { css } from '@emotion/react';
15
14
  import { useTranslation } from 'react-i18next';
16
- import { MenuItemProps } from '@ndla/button';
17
15
  import { ResourceTitleLink } from '../../Resource/resourceComponents';
18
- import FolderMenu from './FolderMenu';
19
16
 
20
17
  export type LayoutType = 'list' | 'listLarger' | 'block';
21
- interface LayoutProps {
22
- type: LayoutType;
23
- }
24
18
 
25
- const FolderWrapper = styled.div<LayoutProps>`
19
+ const FolderWrapper = styled.div`
26
20
  display: flex;
27
21
  position: relative;
28
22
  align-items: center;
29
23
  justify-content: space-between;
30
24
 
31
25
  ${mq.range({ until: breakpoints.mobileWide })} {
32
- ${({ type }) =>
33
- type !== 'list' &&
34
- css`
35
- flex-direction: column;
36
- align-items: unset;
37
- `}
38
- }
39
-
40
- ${({ type }) =>
41
- type === 'block' &&
42
- css`
26
+ &:not([data-type='list']) {
43
27
  flex-direction: column;
44
28
  align-items: unset;
45
- `}
29
+ }
30
+ }
31
+
32
+ &[data-type='block'] {
33
+ flex-direction: column;
34
+ align-items: unset;
35
+ }
46
36
 
47
37
  border: 1px solid ${colors.brand.neutral7};
48
38
  cursor: pointer;
@@ -52,17 +42,23 @@ const FolderWrapper = styled.div<LayoutProps>`
52
42
  &:hover {
53
43
  box-shadow: 1px 1px 6px 2px rgba(9, 55, 101, 0.08);
54
44
  transition-duration: 0.2s;
45
+ [data-title] {
46
+ color: ${colors.brand.primary};
47
+ text-decoration: underline;
48
+ }
55
49
  }
56
50
  `;
57
51
 
58
- const TitleWrapper = styled.div<LayoutProps>`
52
+ const TitleWrapper = styled.div`
59
53
  display: flex;
60
54
  margin: ${spacing.nsmall};
61
- margin-bottom: ${({ type }) => type === 'block' && 0};
62
55
  flex-direction: row;
63
56
  align-items: center;
64
57
  gap: ${spacing.xsmall};
65
58
  justify-content: space-between;
59
+ &[data-type='block'] {
60
+ margin-bottom: 0;
61
+ }
66
62
  `;
67
63
 
68
64
  const IconWrapper = styled.div`
@@ -88,11 +84,6 @@ const FolderTitle = styled.h2`
88
84
  -webkit-line-clamp: 1;
89
85
  line-clamp: 1;
90
86
  -webkit-box-orient: vertical;
91
-
92
- ${FolderWrapper}:hover & {
93
- color: ${colors.brand.primary};
94
- text-decoration: underline;
95
- }
96
87
  `;
97
88
 
98
89
  const MenuWrapper = styled.div`
@@ -113,7 +104,7 @@ const CountContainer = styled.div`
113
104
  margin: 0 ${spacing.small} 0 ${spacing.nsmall};
114
105
  `;
115
106
 
116
- const IconTextWrapper = styled.div<LayoutProps>`
107
+ const IconTextWrapper = styled.div`
117
108
  display: flex;
118
109
  align-items: center;
119
110
  gap: ${spacing.xxsmall};
@@ -125,11 +116,9 @@ const IconTextWrapper = styled.div<LayoutProps>`
125
116
  }
126
117
  ${fonts.sizes(16)};
127
118
  ${mq.range({ until: breakpoints.mobileWide })} {
128
- ${({ type }) =>
129
- type === 'list' &&
130
- css`
131
- display: none;
132
- `}
119
+ &[data-type='list'] {
120
+ display: none;
121
+ }
133
122
  }
134
123
  `;
135
124
 
@@ -145,7 +134,7 @@ const Count = ({ type, count, layoutType }: IconCountProps) => {
145
134
  if (!count) return null;
146
135
 
147
136
  return (
148
- <IconTextWrapper type={layoutType}>
137
+ <IconTextWrapper data-type={layoutType}>
149
138
  <Icon />
150
139
  <span>{t(`myNdla.${type}s`, { count })}</span>
151
140
  </IconTextWrapper>
@@ -160,42 +149,33 @@ interface Props {
160
149
  description?: string;
161
150
  link: string;
162
151
  type?: LayoutType;
163
- onViewTypeChange?: (type: LayoutType) => void;
164
- menuItems?: MenuItemProps[];
152
+ menu?: ReactNode;
165
153
  isShared?: boolean;
166
154
  }
167
155
 
168
- const Folder = ({
169
- id,
170
- link,
171
- title,
172
- subFolders,
173
- subResources,
174
- type = 'list',
175
- menuItems,
176
- isShared,
177
- onViewTypeChange,
178
- }: Props) => {
156
+ const Folder = ({ id, link, title, subFolders, subResources, type = 'list', menu, isShared }: Props) => {
179
157
  const { t } = useTranslation();
180
158
  const Icon = isShared ? FolderShared : FolderOutlined;
181
159
 
182
160
  return (
183
- <FolderWrapper type={type} id={id}>
184
- <TitleWrapper type={type}>
161
+ <FolderWrapper data-type={type} id={id}>
162
+ <TitleWrapper data-type={type}>
185
163
  <IconWrapper
186
164
  aria-label={`${isShared ? `${t('myNdla.folder.sharing.shared')} ` : ''}${t('myNdla.folder.folder')}`}
187
165
  >
188
166
  <Icon />
189
167
  </IconWrapper>
190
168
  <ResourceTitleLink to={link}>
191
- <FolderTitle title={title}>{title}</FolderTitle>
169
+ <FolderTitle data-title="" title={title}>
170
+ {title}
171
+ </FolderTitle>
192
172
  </ResourceTitleLink>
193
173
  </TitleWrapper>
194
174
  <MenuWrapper>
195
175
  <CountContainer>
196
176
  {isShared && (
197
177
  // Information regarding the shared status of a folder is read previously, ignore this
198
- <IconTextWrapper type={type} aria-hidden>
178
+ <IconTextWrapper data-type={type} aria-hidden>
199
179
  <Share />
200
180
  <span>{t('myNdla.folder.sharing.shared')}</span>
201
181
  </IconTextWrapper>
@@ -203,9 +183,7 @@ const Folder = ({
203
183
  <Count layoutType={type} type={'folder'} count={subFolders} />
204
184
  <Count layoutType={type} type={'resource'} count={subResources} />
205
185
  </CountContainer>
206
- {menuItems && menuItems.length > 0 && (
207
- <FolderMenu menuItems={menuItems} viewType={type} onViewTypeChange={onViewTypeChange} />
208
- )}
186
+ {menu}
209
187
  </MenuWrapper>
210
188
  </FolderWrapper>
211
189
  );
@@ -1,5 +1,3 @@
1
1
  import Folder from './Resource/Folder';
2
2
  import FolderInput from './Resource/FolderInput';
3
- import FolderMenu from './Resource/FolderMenu';
4
- import SettingsMenu from './SettingsMenu';
5
- export { Folder, FolderInput, SettingsMenu, FolderMenu };
3
+ export { Folder, FolderInput };