@ndla/ui 42.1.2 → 43.0.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 (121) hide show
  1. package/es/Article/ArticleNotions.js +46 -53
  2. package/es/AudioPlayer/Controls.js +41 -39
  3. package/es/Breadcrumb/index.js +0 -1
  4. package/es/Filter/FilterButtons.js +49 -53
  5. package/es/Filter/FilterListPhone.js +78 -71
  6. package/es/LanguageSelector/LanguageSelector.js +31 -36
  7. package/es/LearningPaths/LearningPathMenuModalWrapper.js +39 -28
  8. package/es/Masthead/MastheadSearchModal.js +31 -35
  9. package/es/MyNdla/Resource/Folder.js +10 -16
  10. package/es/MyNdla/index.js +1 -3
  11. package/es/NDLAFilm/AboutNdlaFilm.js +16 -20
  12. package/es/NDLAFilm/FilmMovieSearch.js +43 -11
  13. package/es/Resource/BlockResource.js +8 -11
  14. package/es/Resource/ListResource.js +8 -11
  15. package/es/Resource/resourceComponents.js +46 -35
  16. package/es/ResourcesWrapper/ResourcesTopicTitle.js +36 -44
  17. package/es/Search/ToggleSearchButton.js +7 -6
  18. package/es/SearchTypeResult/PopupFilter.js +55 -69
  19. package/es/SearchTypeResult/SearchNotionsResult.js +9 -7
  20. package/es/SearchTypeResult/components/ItemContexts.js +41 -45
  21. package/es/SearchTypeResult/components/SubjectFilters.js +16 -17
  22. package/es/Topic/Topic.js +41 -45
  23. package/es/TreeStructure/FolderItem.js +7 -11
  24. package/es/index.js +2 -2
  25. package/es/locale/messages-en.js +1 -0
  26. package/es/locale/messages-nb.js +1 -0
  27. package/es/locale/messages-nn.js +1 -0
  28. package/es/locale/messages-se.js +1 -0
  29. package/es/locale/messages-sma.js +1 -0
  30. package/lib/Article/ArticleNotions.js +45 -52
  31. package/lib/AudioPlayer/Controls.js +40 -38
  32. package/lib/Breadcrumb/index.d.ts +0 -1
  33. package/lib/Breadcrumb/index.js +0 -7
  34. package/lib/Filter/FilterButtons.js +48 -52
  35. package/lib/Filter/FilterListPhone.js +76 -69
  36. package/lib/LanguageSelector/LanguageSelector.js +31 -36
  37. package/lib/LearningPaths/LearningPathMenuModalWrapper.js +47 -35
  38. package/lib/Masthead/MastheadSearchModal.js +29 -32
  39. package/lib/MyNdla/Resource/Folder.d.ts +3 -4
  40. package/lib/MyNdla/Resource/Folder.js +10 -16
  41. package/lib/MyNdla/index.d.ts +1 -3
  42. package/lib/MyNdla/index.js +0 -14
  43. package/lib/NDLAFilm/AboutNdlaFilm.js +15 -18
  44. package/lib/NDLAFilm/FilmMovieSearch.d.ts +1 -2
  45. package/lib/NDLAFilm/FilmMovieSearch.js +46 -11
  46. package/lib/Resource/BlockResource.d.ts +3 -3
  47. package/lib/Resource/BlockResource.js +8 -11
  48. package/lib/Resource/ListResource.d.ts +3 -3
  49. package/lib/Resource/ListResource.js +8 -11
  50. package/lib/Resource/resourceComponents.js +45 -34
  51. package/lib/ResourcesWrapper/ResourcesTopicTitle.js +35 -42
  52. package/lib/Search/ToggleSearchButton.d.ts +2 -1
  53. package/lib/Search/ToggleSearchButton.js +9 -6
  54. package/lib/SearchTypeResult/PopupFilter.d.ts +1 -3
  55. package/lib/SearchTypeResult/PopupFilter.js +54 -68
  56. package/lib/SearchTypeResult/SearchNotionsResult.js +9 -7
  57. package/lib/SearchTypeResult/components/ItemContexts.js +40 -44
  58. package/lib/SearchTypeResult/components/SubjectFilters.js +16 -17
  59. package/lib/Topic/Topic.js +40 -44
  60. package/lib/TreeStructure/FolderItem.js +7 -11
  61. package/lib/index.d.ts +2 -2
  62. package/lib/index.js +0 -12
  63. package/lib/locale/messages-en.d.ts +1 -0
  64. package/lib/locale/messages-en.js +1 -0
  65. package/lib/locale/messages-nb.d.ts +1 -0
  66. package/lib/locale/messages-nb.js +1 -0
  67. package/lib/locale/messages-nn.d.ts +1 -0
  68. package/lib/locale/messages-nn.js +1 -0
  69. package/lib/locale/messages-se.d.ts +1 -0
  70. package/lib/locale/messages-se.js +1 -0
  71. package/lib/locale/messages-sma.d.ts +1 -0
  72. package/lib/locale/messages-sma.js +1 -0
  73. package/package.json +11 -12
  74. package/src/Article/ArticleNotions.tsx +29 -35
  75. package/src/AudioPlayer/Controls.tsx +22 -26
  76. package/src/Breadcrumb/index.ts +0 -2
  77. package/src/Filter/FilterButtons.tsx +28 -34
  78. package/src/Filter/FilterListPhone.tsx +63 -62
  79. package/src/LanguageSelector/LanguageSelector.tsx +26 -32
  80. package/src/LearningPaths/LearningPathMenuModalWrapper.tsx +19 -18
  81. package/src/Masthead/MastheadSearchModal.tsx +21 -29
  82. package/src/MyNdla/Resource/Folder.stories.tsx +27 -5
  83. package/src/MyNdla/Resource/Folder.tsx +4 -19
  84. package/src/MyNdla/index.ts +1 -3
  85. package/src/NDLAFilm/AboutNdlaFilm.tsx +11 -10
  86. package/src/NDLAFilm/FilmMovieSearch.tsx +32 -9
  87. package/src/Resource/BlockResource.stories.tsx +1 -1
  88. package/src/Resource/BlockResource.tsx +4 -6
  89. package/src/Resource/ListResource.tsx +4 -6
  90. package/src/Resource/Resource.stories.tsx +32 -2
  91. package/src/Resource/resourceComponents.tsx +34 -24
  92. package/src/ResourcesWrapper/ResourcesTopicTitle.tsx +23 -27
  93. package/src/Search/ToggleSearchButton.tsx +15 -12
  94. package/src/SearchTypeResult/PopupFilter.tsx +55 -70
  95. package/src/SearchTypeResult/SearchNotionsResult.tsx +5 -2
  96. package/src/SearchTypeResult/components/ItemContexts.tsx +23 -28
  97. package/src/SearchTypeResult/components/SubjectFilters.tsx +9 -12
  98. package/src/Topic/Topic.tsx +15 -17
  99. package/src/TreeStructure/FolderItem.tsx +2 -4
  100. package/src/index.ts +2 -2
  101. package/src/locale/messages-en.ts +1 -0
  102. package/src/locale/messages-nb.ts +1 -0
  103. package/src/locale/messages-nn.ts +1 -0
  104. package/src/locale/messages-se.ts +1 -0
  105. package/src/locale/messages-sma.ts +1 -0
  106. package/es/Breadcrumb/ActionBreadcrumb.js +0 -74
  107. package/es/MyNdla/Resource/FolderMenu.js +0 -74
  108. package/es/MyNdla/SettingsMenu.js +0 -98
  109. package/es/NDLAFilm/CategorySelect.js +0 -135
  110. package/lib/Breadcrumb/ActionBreadcrumb.d.ts +0 -15
  111. package/lib/Breadcrumb/ActionBreadcrumb.js +0 -82
  112. package/lib/MyNdla/Resource/FolderMenu.d.ts +0 -16
  113. package/lib/MyNdla/Resource/FolderMenu.js +0 -81
  114. package/lib/MyNdla/SettingsMenu.d.ts +0 -15
  115. package/lib/MyNdla/SettingsMenu.js +0 -102
  116. package/lib/NDLAFilm/CategorySelect.d.ts +0 -16
  117. package/lib/NDLAFilm/CategorySelect.js +0 -144
  118. package/src/Breadcrumb/ActionBreadcrumb.tsx +0 -87
  119. package/src/MyNdla/Resource/FolderMenu.tsx +0 -102
  120. package/src/MyNdla/SettingsMenu.tsx +0 -96
  121. package/src/NDLAFilm/CategorySelect.tsx +0 -197
@@ -1,5 +1,5 @@
1
- import React, { ReactNode, useState } from 'react';
2
- import { Drawer } from '@ndla/modal';
1
+ import React, { ReactNode, useCallback, useState } from 'react';
2
+ import { Drawer, Modal, ModalTrigger } from '@ndla/modal';
3
3
  import { IconButtonV2 as IconButton } from '@ndla/button';
4
4
  import { Cross } from '@ndla/icons/action';
5
5
  import styled from '@emotion/styled';
@@ -63,42 +63,34 @@ const StyledHeader = styled.div`
63
63
  const MastheadSearchModal = ({ onClose: onSearchClose, children, hideOnNarrowScreen, ndlaFilm }: Props) => {
64
64
  const { t } = useTranslation();
65
65
  const [isOpen, setIsOpen] = useState(false);
66
+
67
+ const closeModal = useCallback(() => {
68
+ onSearchClose();
69
+ setIsOpen(false);
70
+ }, [onSearchClose]);
71
+
66
72
  return (
67
- <>
68
- <ToggleSearchButton hideOnNarrowScreen={hideOnNarrowScreen} onClick={() => setIsOpen(true)} ndlaFilm={ndlaFilm}>
69
- {t('masthead.menu.search')}
70
- </ToggleSearchButton>
73
+ <Modal open={isOpen} onOpenChange={setIsOpen}>
74
+ <ModalTrigger>
75
+ <ToggleSearchButton hideOnNarrowScreen={hideOnNarrowScreen} onClick={() => setIsOpen(true)} ndlaFilm={ndlaFilm}>
76
+ {t('masthead.menu.search')}
77
+ </ToggleSearchButton>
78
+ </ModalTrigger>
71
79
  <StyledDrawer
72
- controlled
73
80
  aria-label={t('searchPage.searchFieldPlaceholder')}
74
81
  position="top"
75
82
  expands
76
83
  size="small"
77
- animation="slideIn"
78
84
  animationDuration={200}
79
- isOpen={isOpen}
80
- onClose={() => {
81
- setIsOpen(false);
82
- onSearchClose();
83
- }}
84
85
  >
85
- {(closeModal) => (
86
- <>
87
- <StyledHeader>
88
- {children(closeModal)}
89
- <IconButton
90
- aria-label={t('welcomePage.closeSearch')}
91
- variant="ghost"
92
- colorTheme="light"
93
- onClick={closeModal}
94
- >
95
- <Cross className="c-icon--medium" />
96
- </IconButton>
97
- </StyledHeader>
98
- </>
99
- )}
86
+ <StyledHeader>
87
+ {children(closeModal)}
88
+ <IconButton aria-label={t('welcomePage.closeSearch')} variant="ghost" colorTheme="light" onClick={closeModal}>
89
+ <Cross className="c-icon--medium" />
90
+ </IconButton>
91
+ </StyledHeader>
100
92
  </StyledDrawer>
101
- </>
93
+ </Modal>
102
94
  );
103
95
  };
104
96
 
@@ -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,14 +7,12 @@
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
14
  import { useTranslation } from 'react-i18next';
15
- import { MenuItemProps } from '@ndla/button';
16
15
  import { ResourceTitleLink } from '../../Resource/resourceComponents';
17
- import FolderMenu from './FolderMenu';
18
16
 
19
17
  export type LayoutType = 'list' | 'listLarger' | 'block';
20
18
 
@@ -151,22 +149,11 @@ interface Props {
151
149
  description?: string;
152
150
  link: string;
153
151
  type?: LayoutType;
154
- onViewTypeChange?: (type: LayoutType) => void;
155
- menuItems?: MenuItemProps[];
152
+ menu?: ReactNode;
156
153
  isShared?: boolean;
157
154
  }
158
155
 
159
- const Folder = ({
160
- id,
161
- link,
162
- title,
163
- subFolders,
164
- subResources,
165
- type = 'list',
166
- menuItems,
167
- isShared,
168
- onViewTypeChange,
169
- }: Props) => {
156
+ const Folder = ({ id, link, title, subFolders, subResources, type = 'list', menu, isShared }: Props) => {
170
157
  const { t } = useTranslation();
171
158
  const Icon = isShared ? FolderShared : FolderOutlined;
172
159
 
@@ -196,9 +183,7 @@ const Folder = ({
196
183
  <Count layoutType={type} type={'folder'} count={subFolders} />
197
184
  <Count layoutType={type} type={'resource'} count={subResources} />
198
185
  </CountContainer>
199
- {menuItems && menuItems.length > 0 && (
200
- <FolderMenu menuItems={menuItems} viewType={type} onViewTypeChange={onViewTypeChange} />
201
- )}
186
+ {menu}
202
187
  </MenuWrapper>
203
188
  </FolderWrapper>
204
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 };
@@ -1,7 +1,7 @@
1
1
  import React, { ReactNode } from 'react';
2
2
  import { useTranslation } from 'react-i18next';
3
3
  import styled from '@emotion/styled';
4
- import { ModalHeader, ModalBody, ModalCloseButton, Modal } from '@ndla/modal';
4
+ import { ModalHeader, ModalBody, ModalCloseButton, Modal, ModalTrigger, ModalContent } from '@ndla/modal';
5
5
  import { colors, spacing, mq, breakpoints } from '@ndla/core';
6
6
  import { ButtonV2 as Button } from '@ndla/button';
7
7
  import VisualElement from './VisualElement';
@@ -64,15 +64,16 @@ const AboutNdlaFilm = ({ aboutNDLAVideo, moreAboutNdlaFilm }: Props) => {
64
64
  <div>
65
65
  <h2 id={titleId}>{aboutNDLAVideo.title}</h2>
66
66
  <p>{aboutNDLAVideo.description}</p>
67
- <Modal size="full" activateButton={<Button variant="link">{t('ndlaFilm.about.more')}</Button>}>
68
- {(onClose) => (
69
- <>
70
- <ModalHeader>
71
- <ModalCloseButton onClick={onClose} />
72
- </ModalHeader>
73
- <ModalBody>{moreAboutNdlaFilm}</ModalBody>
74
- </>
75
- )}
67
+ <Modal>
68
+ <ModalTrigger>
69
+ <Button variant="link">{t('ndlaFilm.about.more')}</Button>
70
+ </ModalTrigger>
71
+ <ModalContent size="full">
72
+ <ModalHeader>
73
+ <ModalCloseButton />
74
+ </ModalHeader>
75
+ <ModalBody>{moreAboutNdlaFilm}</ModalBody>
76
+ </ModalContent>
76
77
  </Modal>
77
78
  </div>
78
79
  </StyledAside>
@@ -6,12 +6,12 @@
6
6
  *
7
7
  */
8
8
 
9
- import React from 'react';
9
+ import React, { useCallback, useMemo } from 'react';
10
10
  import SafeLink from '@ndla/safelink';
11
11
  import { useTranslation } from 'react-i18next';
12
12
  import styled from '@emotion/styled';
13
13
  import { spacing, mq, breakpoints, colors } from '@ndla/core';
14
- import CategorySelect from './CategorySelect';
14
+ import { Option, Select, SingleValue } from '@ndla/select';
15
15
  import { MovieResourceType } from './types';
16
16
  import { OneColumn } from '..';
17
17
  import { StyledHeadingH2 } from './filmStyles';
@@ -59,7 +59,6 @@ interface Props {
59
59
  onChangeResourceType: (resourceType?: string) => void;
60
60
  resourceTypeSelected?: MovieResourceType;
61
61
  resourceTypes: MovieResourceType[];
62
- ariaControlId: string;
63
62
  skipToContentId?: string;
64
63
  }
65
64
 
@@ -68,10 +67,32 @@ const FilmMovieSearch = ({
68
67
  onChangeResourceType,
69
68
  resourceTypes,
70
69
  resourceTypeSelected,
71
- ariaControlId,
72
70
  skipToContentId,
73
71
  }: Props) => {
74
72
  const { t } = useTranslation();
73
+ const selectedOption = useMemo(() => {
74
+ if (resourceTypeSelected) {
75
+ return { value: resourceTypeSelected.id, label: resourceTypeSelected.name };
76
+ }
77
+ return { value: 'fromNdla', label: t('ndlaFilm.search.categoryFromNdla') };
78
+ }, [resourceTypeSelected, t]);
79
+
80
+ const options: Option[] = useMemo(() => {
81
+ const fromNdla = { value: 'fromNdla', label: t('ndlaFilm.search.categoryFromNdla') };
82
+ return [fromNdla].concat(resourceTypes.map((rt) => ({ value: rt.id, label: rt.name })));
83
+ }, [resourceTypes, t]);
84
+
85
+ const onChange = useCallback(
86
+ (value: SingleValue) => {
87
+ if (value?.value === 'fromNdla') {
88
+ onChangeResourceType();
89
+ } else {
90
+ onChangeResourceType(value?.value);
91
+ }
92
+ },
93
+ [onChangeResourceType],
94
+ );
95
+
75
96
  return (
76
97
  <FilmMovieSearchContainer>
77
98
  <OneColumn>
@@ -91,11 +112,13 @@ const FilmMovieSearch = ({
91
112
  </StyledUl>
92
113
  </nav>
93
114
  </TopicNavigation>
94
- <CategorySelect
95
- onChangeResourceType={onChangeResourceType}
96
- resourceTypes={resourceTypes}
97
- resourceTypeSelected={resourceTypeSelected}
98
- ariaControlId={ariaControlId}
115
+ <Select<false>
116
+ options={options}
117
+ value={selectedOption}
118
+ onChange={onChange}
119
+ colorTheme="white"
120
+ placeholder={t('ndlaFilm.search.chooseCategory')}
121
+ prefix={`${t('ndlaFilm.search.chooseCategory')} `}
99
122
  />
100
123
  </OneColumn>
101
124
  </FilmMovieSearchContainer>
@@ -28,7 +28,7 @@ export default {
28
28
  headingLevel: {
29
29
  control: false,
30
30
  },
31
- menuItems: {
31
+ menu: {
32
32
  control: false,
33
33
  },
34
34
  },
@@ -7,9 +7,8 @@
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 { colors, fonts, spacing } from '@ndla/core';
12
- import { MenuItemProps } from '@ndla/button';
13
12
  import ContentTypeBadge from '../ContentTypeBadge';
14
13
  import Image from '../Image';
15
14
  import {
@@ -23,7 +22,6 @@ import {
23
22
  } from './resourceComponents';
24
23
  import ContentLoader from '../ContentLoader';
25
24
  import { contentTypeMapping, resourceEmbedTypeMapping } from '../model/ContentType';
26
- import { SettingsMenu } from '../MyNdla';
27
25
 
28
26
  const BlockElementWrapper = styled.div`
29
27
  display: flex;
@@ -149,7 +147,7 @@ interface Props {
149
147
  tags?: string[];
150
148
  description?: string;
151
149
  headingLevel?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
152
- menuItems?: MenuItemProps[];
150
+ menu?: ReactNode;
153
151
  isLoading?: boolean;
154
152
  targetBlank?: boolean;
155
153
  resourceTypes?: { id: string; name: string }[];
@@ -163,7 +161,7 @@ const BlockResource = ({
163
161
  tags,
164
162
  resourceImage,
165
163
  description,
166
- menuItems,
164
+ menu,
167
165
  isLoading,
168
166
  headingLevel: Heading = 'h2',
169
167
  targetBlank,
@@ -196,7 +194,7 @@ const BlockResource = ({
196
194
  </ContentWrapper>
197
195
  <TagsAndActionMenu>
198
196
  {tags && tags.length > 0 && <CompressedTagList tagLinkPrefix={tagLinkPrefix} tags={tags} />}
199
- {menuItems && menuItems.length > 0 && <SettingsMenu menuItems={menuItems} />}
197
+ {menu}
200
198
  </TagsAndActionMenu>
201
199
  </BlockInfoWrapper>
202
200
  </BlockElementWrapper>
@@ -7,9 +7,8 @@
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 { fonts, spacing, colors, breakpoints, mq } from '@ndla/core';
12
- import { MenuItemProps } from '@ndla/button';
13
12
  import Image from '../Image';
14
13
  import {
15
14
  CompressedTagList,
@@ -23,7 +22,6 @@ import {
23
22
  import ContentLoader from '../ContentLoader';
24
23
  import ContentTypeBadge from '../ContentTypeBadge';
25
24
  import { contentTypeMapping, resourceEmbedTypeMapping } from '../model/ContentType';
26
- import { SettingsMenu } from '../MyNdla';
27
25
 
28
26
  const ListResourceWrapper = styled.div`
29
27
  flex: 1;
@@ -204,7 +202,7 @@ export interface ListResourceProps {
204
202
  resourceTypes: { id: string; name: string }[];
205
203
  tags?: string[];
206
204
  description?: string;
207
- menuItems?: MenuItemProps[];
205
+ menu?: ReactNode;
208
206
  isLoading?: boolean;
209
207
  targetBlank?: boolean;
210
208
  }
@@ -218,7 +216,7 @@ const ListResource = ({
218
216
  resourceImage,
219
217
  resourceTypes,
220
218
  description,
221
- menuItems,
219
+ menu,
222
220
  isLoading = false,
223
221
  targetBlank,
224
222
  }: ListResourceProps) => {
@@ -251,7 +249,7 @@ const ListResource = ({
251
249
  {showDescription && <Description description={description} loading={isLoading} />}
252
250
  <TagsandActionMenu>
253
251
  {tags && tags.length > 0 && <CompressedTagList tagLinkPrefix={tagLinkPrefix} tags={tags} />}
254
- {menuItems && menuItems.length > 0 && <SettingsMenu menuItems={menuItems} />}
252
+ {menu}
255
253
  </TagsandActionMenu>
256
254
  </ListResourceWrapper>
257
255
  );
@@ -8,8 +8,37 @@
8
8
 
9
9
  import React from 'react';
10
10
  import { Meta, StoryFn } from '@storybook/react';
11
- import { defaultParameters } from '../../../../stories/defaults';
11
+ import { DropdownMenu, DropdownContent, DropdownItem, DropdownTrigger } from '@ndla/dropdown-menu';
12
+ import { ButtonV2, IconButtonV2 } from '@ndla/button';
13
+ import { HorizontalMenu } from '@ndla/icons/contentType';
14
+ import { Pencil } from '@ndla/icons/action';
15
+ import { DeleteForever } from '@ndla/icons/editor';
12
16
  import ListResource from './ListResource';
17
+ import { defaultParameters } from '../../../../stories/defaults';
18
+
19
+ const StoryResourceMenu = () => (
20
+ <DropdownMenu>
21
+ <DropdownTrigger>
22
+ <IconButtonV2 aria-label="Show more" title="Show more" variant="ghost" colorTheme="light">
23
+ <HorizontalMenu />
24
+ </IconButtonV2>
25
+ </DropdownTrigger>
26
+ <DropdownContent>
27
+ <DropdownItem>
28
+ <ButtonV2 variant="ghost" colorTheme="light" shape="sharp" size="small" fontWeight="normal">
29
+ <Pencil />
30
+ Rediger
31
+ </ButtonV2>
32
+ </DropdownItem>
33
+ <DropdownItem>
34
+ <ButtonV2 variant="ghost" colorTheme="danger" shape="sharp" size="small" fontWeight="normal">
35
+ <DeleteForever />
36
+ Slett
37
+ </ButtonV2>
38
+ </DropdownItem>
39
+ </DropdownContent>
40
+ </DropdownMenu>
41
+ );
13
42
 
14
43
  export default {
15
44
  title: 'Components/Resources/ListResource',
@@ -28,7 +57,7 @@ export default {
28
57
  headingLevel: {
29
58
  control: false,
30
59
  },
31
- menuItems: {
60
+ menu: {
32
61
  control: false,
33
62
  },
34
63
  },
@@ -41,6 +70,7 @@ export default {
41
70
  alt: '',
42
71
  },
43
72
  resourceTypes: [{ id: 'urn:resourcetype:learningPath', name: 'Læringssti' }],
73
+ menu: <StoryResourceMenu />,
44
74
  tags: ['tag', 'tag', 'tag', 'tag'],
45
75
  },
46
76
  } as Meta<typeof ListResource>;
@@ -10,11 +10,11 @@ import styled from '@emotion/styled';
10
10
  import { colors, fonts, spacing } from '@ndla/core';
11
11
  import React, { CSSProperties, HTMLAttributes, ReactNode, useMemo } from 'react';
12
12
  import { useTranslation } from 'react-i18next';
13
- import { MenuButton } from '@ndla/button';
14
- import SafeLink from '@ndla/safelink';
15
- import { useNavigate } from 'react-router-dom';
13
+ import { IconButtonV2 } from '@ndla/button';
14
+ import SafeLink, { SafeLinkButton } from '@ndla/safelink';
16
15
  import { HashTag } from '@ndla/icons/common';
17
16
  import { css } from '@emotion/react';
17
+ import { DropdownMenu, DropdownContent, DropdownTrigger, DropdownItem } from '@ndla/dropdown-menu';
18
18
  import resourceTypeColor from '../utils/resourceTypeColor';
19
19
  import { resourceEmbedTypeMapping } from '../model/ContentType';
20
20
 
@@ -38,6 +38,10 @@ export const ResourceTitleLink = styled(SafeLink)`
38
38
  }
39
39
  `;
40
40
 
41
+ const StyledTrigger = styled(IconButtonV2)`
42
+ margin: 0px ${spacing.xsmall};
43
+ `;
44
+
41
45
  export const resourceHeadingStyle = css`
42
46
  margin: 0;
43
47
  overflow: hidden;
@@ -173,34 +177,40 @@ interface CompressedTagListProps {
173
177
  }
174
178
 
175
179
  export const CompressedTagList = ({ tags, tagLinkPrefix }: CompressedTagListProps) => {
176
- const navigate = useNavigate();
177
180
  const { t } = useTranslation();
178
181
  const visibleTags = useMemo(() => tags.slice(0, 3), [tags]);
179
- const remainingTags = useMemo(
180
- () =>
181
- tags.slice(3, tags.length).map((tag) => {
182
- return {
183
- icon: <HashTag />,
184
- text: tag,
185
- onClick: () => {
186
- navigate(`${tagLinkPrefix ? tagLinkPrefix : ''}/${encodeURIComponent(tag)}`);
187
- },
188
- };
189
- }),
190
- [navigate, tagLinkPrefix, tags],
191
- );
182
+ const remainingTags = useMemo(() => tags.slice(3, tags.length), [tags]);
192
183
 
193
184
  return (
194
185
  <>
195
186
  <TagList tagLinkPrefix={tagLinkPrefix} tags={visibleTags} />
196
187
  {remainingTags.length > 0 && (
197
- <MenuButton
198
- size="small"
199
- menuIcon={<TagCounterWrapper>{`+${remainingTags.length}`}</TagCounterWrapper>}
200
- menuItems={remainingTags}
201
- align="end"
202
- aria-label={t('myNdla.moreTags', { count: remainingTags.length })}
203
- />
188
+ <DropdownMenu>
189
+ <DropdownTrigger>
190
+ <StyledTrigger
191
+ size="xsmall"
192
+ variant="ghost"
193
+ colorTheme="light"
194
+ aria-label={t('myNdla.moreTags', { count: remainingTags.length })}
195
+ >
196
+ {<TagCounterWrapper>{`+${remainingTags.length}`}</TagCounterWrapper>}
197
+ </StyledTrigger>
198
+ </DropdownTrigger>
199
+ <DropdownContent showArrow>
200
+ {remainingTags.map((tag, i) => (
201
+ <DropdownItem key={`tag-${i}`}>
202
+ <SafeLinkButton
203
+ to={`${tagLinkPrefix ?? ''}/${encodeURIComponent(tag)}`}
204
+ variant="ghost"
205
+ colorTheme="light"
206
+ >
207
+ <HashTag />
208
+ {tag}
209
+ </SafeLinkButton>
210
+ </DropdownItem>
211
+ ))}
212
+ </DropdownContent>
213
+ </DropdownMenu>
204
214
  )}
205
215
  </>
206
216
  );
@@ -1,9 +1,9 @@
1
- import React, { ReactNode } from 'react';
1
+ import React from 'react';
2
2
  import { useTranslation } from 'react-i18next';
3
3
  import { css } from '@emotion/react';
4
4
  import styled from '@emotion/styled';
5
5
  import { breakpoints, colors, fonts, mq, spacing } from '@ndla/core';
6
- import { ModalBody, ModalHeader, ModalCloseButton, Modal, ModalTitle } from '@ndla/modal';
6
+ import { ModalBody, ModalHeader, ModalCloseButton, Modal, ModalTitle, ModalTrigger, ModalContent } from '@ndla/modal';
7
7
  import Tooltip from '@ndla/tooltip';
8
8
  import { Switch } from '@ndla/switch';
9
9
  import { LearningPathQuiz } from '@ndla/icons/contentType';
@@ -185,31 +185,27 @@ const ResourcesTopicTitle = ({
185
185
  onChange={toggleAdditionalResources}
186
186
  css={invertedStyle ? invertedSwitchCSS : switchCSS}
187
187
  />
188
- <Modal
189
- wrapperFunctionForButton={(activateButton: ReactNode) => (
190
- <TooltipWrapper>
191
- <Tooltip tooltip={t('resource.dialogTooltip')}>{activateButton}</Tooltip>
192
- </TooltipWrapper>
193
- )}
194
- activateButton={
195
- <TooltipButton aria-label={t('resource.dialogTooltip')}>
196
- <HelpIcon invertedStyle={invertedStyle} />
197
- </TooltipButton>
198
- }
199
- >
200
- {(onClose: () => void) => (
201
- <>
202
- <ModalHeader>
203
- <ModalTitle>{t('resource.dialogHeading')}</ModalTitle>
204
- <ModalCloseButton title={t('modal.closeModal')} onClick={onClose} />
205
- </ModalHeader>
206
- <ModalBody>
207
- <hr />
208
- <p>{t('resource.dialogText1')}</p>
209
- <p>{t('resource.dialogText2')}</p>
210
- </ModalBody>
211
- </>
212
- )}
188
+ <Modal>
189
+ <TooltipWrapper>
190
+ <Tooltip tooltip={t('resource.dialogTooltip')}>
191
+ <ModalTrigger>
192
+ <TooltipButton aria-label={t('resource.dialogTooltip')}>
193
+ <HelpIcon invertedStyle={invertedStyle} />
194
+ </TooltipButton>
195
+ </ModalTrigger>
196
+ </Tooltip>
197
+ </TooltipWrapper>
198
+ <ModalContent>
199
+ <ModalHeader>
200
+ <ModalTitle>{t('resource.dialogHeading')}</ModalTitle>
201
+ <ModalCloseButton />
202
+ </ModalHeader>
203
+ <ModalBody>
204
+ <hr />
205
+ <p>{t('resource.dialogText1')}</p>
206
+ <p>{t('resource.dialogText2')}</p>
207
+ </ModalBody>
208
+ </ModalContent>
213
209
  </Modal>
214
210
  </StyledRow>
215
211
  )}
@@ -6,7 +6,7 @@
6
6
  *
7
7
  */
8
8
 
9
- import React from 'react';
9
+ import React, { forwardRef } from 'react';
10
10
  import { spacing, spacingUnit, breakpoints, mq, misc, fonts, colors } from '@ndla/core';
11
11
  import { Search } from '@ndla/icons/common';
12
12
  import { ButtonProps, ButtonV2 } from '@ndla/button';
@@ -62,17 +62,20 @@ const StyledSpan = styled.span`
62
62
  font-weight: ${fonts.weight.normal};
63
63
  `;
64
64
 
65
- const ToggleSearchButton = ({ children, ndlaFilm, hideOnNarrowScreen, hideOnWideScreen, ...rest }: Props) => (
66
- <StyledButton
67
- ndlaFilm={ndlaFilm}
68
- hideOnNarrowScreen={hideOnNarrowScreen}
69
- hideOnWideScreen={hideOnWideScreen}
70
- type="button"
71
- {...rest}
72
- >
73
- <StyledSpan>{children}</StyledSpan>
74
- <Search />
75
- </StyledButton>
65
+ const ToggleSearchButton = forwardRef<HTMLButtonElement, Props>(
66
+ ({ children, ndlaFilm, hideOnNarrowScreen, hideOnWideScreen, ...rest }, ref) => (
67
+ <StyledButton
68
+ ndlaFilm={ndlaFilm}
69
+ hideOnNarrowScreen={hideOnNarrowScreen}
70
+ hideOnWideScreen={hideOnWideScreen}
71
+ type="button"
72
+ ref={ref}
73
+ {...rest}
74
+ >
75
+ <StyledSpan>{children}</StyledSpan>
76
+ <Search />
77
+ </StyledButton>
78
+ ),
76
79
  );
77
80
 
78
81
  export default ToggleSearchButton;