@ndla/ui 30.8.2 → 30.9.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.
- package/es/Article/Article.js +3 -3
- package/es/Article/ArticleSideBar.js +5 -5
- package/es/AudioPlayer/Controls.js +26 -26
- package/es/AudioPlayer/SpeechControl.js +1 -1
- package/es/CopyParagraphButton/CopyParagraphButton.js +18 -24
- package/es/Frontpage/FrontpageSearch.js +3 -9
- package/es/MediaList/MediaList.js +1 -0
- package/es/Messages/MessageBox.js +10 -10
- package/es/NDLAFilm/AllMoviesAlphabetically.js +11 -11
- package/es/NDLAFilm/FilmSlideshow.js +7 -7
- package/es/NDLAFilm/MovieGrid.js +4 -4
- package/es/Programme/Programme.js +5 -5
- package/es/ResourceGroup/ResourceItem.js +12 -13
- package/es/ResourceGroup/ResourceList.js +3 -4
- package/es/Search/SearchField.js +2 -3
- package/es/Subject/SubjectNewContent.js +10 -10
- package/es/TreeStructure/AddFolderButton.js +9 -9
- package/es/TreeStructure/ComboboxButton.js +30 -5
- package/es/TreeStructure/TreeStructure.js +9 -7
- package/es/all.css +1 -1
- package/es/i18n/index.js +1 -2
- package/es/index.js +1 -1
- package/lib/Article/Article.js +3 -3
- package/lib/Article/ArticleSideBar.js +5 -5
- package/lib/AudioPlayer/Controls.js +26 -26
- package/lib/AudioPlayer/SpeechControl.js +1 -1
- package/lib/CopyParagraphButton/CopyParagraphButton.js +18 -24
- package/lib/Frontpage/FrontpageSearch.js +3 -9
- package/lib/MediaList/MediaList.js +1 -0
- package/lib/Messages/MessageBox.js +10 -10
- package/lib/NDLAFilm/AllMoviesAlphabetically.js +11 -11
- package/lib/NDLAFilm/FilmSlideshow.js +7 -7
- package/lib/NDLAFilm/MovieGrid.js +4 -4
- package/lib/Programme/Programme.js +5 -5
- package/lib/ResourceGroup/ResourceItem.js +11 -11
- package/lib/ResourceGroup/ResourceList.js +2 -2
- package/lib/Search/SearchField.js +2 -3
- package/lib/Subject/SubjectNewContent.js +10 -10
- package/lib/TreeStructure/AddFolderButton.d.ts +2 -1
- package/lib/TreeStructure/AddFolderButton.js +9 -9
- package/lib/TreeStructure/ComboboxButton.d.ts +1 -0
- package/lib/TreeStructure/ComboboxButton.js +29 -3
- package/lib/TreeStructure/TreeStructure.js +9 -7
- package/lib/all.css +1 -1
- package/lib/i18n/index.d.ts +0 -1
- package/lib/i18n/index.js +1 -8
- package/lib/index.d.ts +1 -1
- package/lib/index.js +0 -7
- package/package.json +17 -19
- package/src/Article/Article.tsx +1 -1
- package/src/Article/ArticleSideBar.tsx +1 -1
- package/src/AudioPlayer/Controls.tsx +1 -0
- package/src/AudioPlayer/SpeechControl.tsx +1 -0
- package/src/CopyParagraphButton/CopyParagraphButton.tsx +14 -10
- package/src/Frontpage/FrontpageSearch.tsx +1 -7
- package/src/MediaList/MediaList.tsx +1 -0
- package/src/Messages/MessageBox.tsx +1 -1
- package/src/NDLAFilm/AllMoviesAlphabetically.tsx +1 -1
- package/src/NDLAFilm/FilmSlideshow.tsx +1 -1
- package/src/NDLAFilm/MovieGrid.tsx +2 -1
- package/src/Programme/Programme.tsx +1 -2
- package/src/ResourceGroup/ResourceItem.tsx +1 -2
- package/src/ResourceGroup/ResourceList.tsx +1 -2
- package/src/Search/SearchField.tsx +1 -2
- package/src/Subject/SubjectNewContent.tsx +2 -2
- package/src/TopicMenu/component.topic-menu.scss +16 -13
- package/src/TreeStructure/AddFolderButton.tsx +16 -17
- package/src/TreeStructure/ComboboxButton.tsx +45 -20
- package/src/TreeStructure/TreeStructure.tsx +2 -0
- package/src/i18n/index.ts +0 -1
- package/src/index.ts +1 -1
- package/es/i18n/formatMessage.js +0 -45
- package/lib/i18n/formatMessage.d.ts +0 -14
- package/lib/i18n/formatMessage.js +0 -53
- package/src/i18n/__tests__/formatMessage-test.ts +0 -34
- package/src/i18n/formatMessage.ts +0 -61
package/lib/i18n/index.d.ts
CHANGED
package/lib/i18n/index.js
CHANGED
|
@@ -3,12 +3,6 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
Object.defineProperty(exports, "formatMessage", {
|
|
7
|
-
enumerable: true,
|
|
8
|
-
get: function get() {
|
|
9
|
-
return _formatMessage.formatMessage;
|
|
10
|
-
}
|
|
11
|
-
});
|
|
12
6
|
Object.defineProperty(exports, "formatNestedMessages", {
|
|
13
7
|
enumerable: true,
|
|
14
8
|
get: function get() {
|
|
@@ -22,5 +16,4 @@ Object.defineProperty(exports, "i18nInstance", {
|
|
|
22
16
|
}
|
|
23
17
|
});
|
|
24
18
|
var _i18n = require("./i18n");
|
|
25
|
-
var _formatNestedMessages = require("./formatNestedMessages");
|
|
26
|
-
var _formatMessage = require("./formatMessage");
|
|
19
|
+
var _formatNestedMessages = require("./formatNestedMessages");
|
package/lib/index.d.ts
CHANGED
|
@@ -70,7 +70,7 @@ export { default as AuthorInfo } from './AuthorInfo';
|
|
|
70
70
|
export { default as Breadcrumb, HeaderBreadcrumb, HomeBreadcrumb, ActionBreadcrumb } from './Breadcrumb';
|
|
71
71
|
export type { SimpleBreadcrumbItem, IndexedBreadcrumbItem } from './Breadcrumb';
|
|
72
72
|
export type { BreadcrumbItemProps } from './Breadcrumblist';
|
|
73
|
-
export { i18nInstance, formatNestedMessages
|
|
73
|
+
export { i18nInstance, formatNestedMessages } from './i18n';
|
|
74
74
|
export { default as ResourceGroup } from './ResourceGroup';
|
|
75
75
|
export { default as LayoutItem, OneColumn, PageContainer, Content } from './Layout';
|
|
76
76
|
export { FilmSlideshow, MovieGrid, AboutNdlaFilm, FilmMovieSearch, FilmMovieList, AllMoviesAlphabetically, } from './NDLAFilm';
|
package/lib/index.js
CHANGED
|
@@ -133,7 +133,6 @@ var _exportNames = {
|
|
|
133
133
|
ActionBreadcrumb: true,
|
|
134
134
|
i18nInstance: true,
|
|
135
135
|
formatNestedMessages: true,
|
|
136
|
-
formatMessage: true,
|
|
137
136
|
ResourceGroup: true,
|
|
138
137
|
LayoutItem: true,
|
|
139
138
|
OneColumn: true,
|
|
@@ -1306,12 +1305,6 @@ Object.defineProperty(exports, "createUniversalPortal", {
|
|
|
1306
1305
|
return _createUniversalPortal.createUniversalPortal;
|
|
1307
1306
|
}
|
|
1308
1307
|
});
|
|
1309
|
-
Object.defineProperty(exports, "formatMessage", {
|
|
1310
|
-
enumerable: true,
|
|
1311
|
-
get: function get() {
|
|
1312
|
-
return _i18n.formatMessage;
|
|
1313
|
-
}
|
|
1314
|
-
});
|
|
1315
1308
|
Object.defineProperty(exports, "formatNestedMessages", {
|
|
1316
1309
|
enumerable: true,
|
|
1317
1310
|
get: function get() {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ndla/ui",
|
|
3
|
-
"version": "30.
|
|
3
|
+
"version": "30.9.0",
|
|
4
4
|
"description": "UI component library for NDLA.",
|
|
5
5
|
"license": "GPL-3.0",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -31,29 +31,27 @@
|
|
|
31
31
|
"types"
|
|
32
32
|
],
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@ndla/article-scripts": "^3.0.
|
|
35
|
-
"@ndla/button": "^6.0.
|
|
36
|
-
"@ndla/carousel": "^2.0.
|
|
37
|
-
"@ndla/core": "^3.0.
|
|
38
|
-
"@ndla/forms": "^4.0.
|
|
39
|
-
"@ndla/hooks": "^1.1.
|
|
40
|
-
"@ndla/icons": "^2.0.
|
|
41
|
-
"@ndla/licenses": "^6.0.
|
|
42
|
-
"@ndla/modal": "^2.1.
|
|
43
|
-
"@ndla/notion": "^4.0.
|
|
44
|
-
"@ndla/safelink": "^3.0.
|
|
45
|
-
"@ndla/switch": "^1.0.
|
|
46
|
-
"@ndla/tabs": "^2.0.
|
|
47
|
-
"@ndla/tooltip": "^3.0.
|
|
34
|
+
"@ndla/article-scripts": "^3.0.11",
|
|
35
|
+
"@ndla/button": "^6.0.4",
|
|
36
|
+
"@ndla/carousel": "^2.0.8",
|
|
37
|
+
"@ndla/core": "^3.0.3",
|
|
38
|
+
"@ndla/forms": "^4.0.16",
|
|
39
|
+
"@ndla/hooks": "^1.1.15",
|
|
40
|
+
"@ndla/icons": "^2.0.8",
|
|
41
|
+
"@ndla/licenses": "^6.0.10",
|
|
42
|
+
"@ndla/modal": "^2.1.3",
|
|
43
|
+
"@ndla/notion": "^4.0.18",
|
|
44
|
+
"@ndla/safelink": "^3.0.16",
|
|
45
|
+
"@ndla/switch": "^1.0.3",
|
|
46
|
+
"@ndla/tabs": "^2.0.11",
|
|
47
|
+
"@ndla/tooltip": "^3.0.6",
|
|
48
48
|
"@ndla/types-learningpath-api": "^0.0.17",
|
|
49
|
-
"@ndla/util": "^3.1.
|
|
49
|
+
"@ndla/util": "^3.1.9",
|
|
50
50
|
"@reach/menu-button": "^0.16.2",
|
|
51
51
|
"@reach/slider": "^0.16.0",
|
|
52
52
|
"focus-trap-react": "^8.9.2",
|
|
53
53
|
"html-react-parser": "^0.14.1",
|
|
54
54
|
"i18next-browser-languagedetector": "^6.1.1",
|
|
55
|
-
"intl-format-cache": "^4.3.1",
|
|
56
|
-
"intl-messageformat": "5.4.3",
|
|
57
55
|
"invariant": "^2.2.3",
|
|
58
56
|
"lodash": "^4.17.20",
|
|
59
57
|
"react-bem-helper": "1.4.1",
|
|
@@ -86,5 +84,5 @@
|
|
|
86
84
|
"publishConfig": {
|
|
87
85
|
"access": "public"
|
|
88
86
|
},
|
|
89
|
-
"gitHead": "
|
|
87
|
+
"gitHead": "68b1327bb5950eee8a41227b3b48589c7d428bd7"
|
|
90
88
|
}
|
package/src/Article/Article.tsx
CHANGED
|
@@ -74,7 +74,7 @@ const ArticleSideBar = ({
|
|
|
74
74
|
//TOP
|
|
75
75
|
if (resourcesRef.current.getBoundingClientRect().top <= 0) {
|
|
76
76
|
setHide(true);
|
|
77
|
-
} else if (resourcesRef.current.getBoundingClientRect().top
|
|
77
|
+
} else if (resourcesRef.current.getBoundingClientRect().top >= 0) {
|
|
78
78
|
setHide(false);
|
|
79
79
|
}
|
|
80
80
|
};
|
|
@@ -411,6 +411,7 @@ const Controls = ({ src, title }: Props) => {
|
|
|
411
411
|
|
|
412
412
|
return (
|
|
413
413
|
<div>
|
|
414
|
+
{/* eslint-disable-next-line jsx-a11y/media-has-caption */}
|
|
414
415
|
<audio ref={audioRef} src={src} title={title} preload="metadata" />
|
|
415
416
|
<ControlsWrapper>
|
|
416
417
|
<PlayButton type="button" onClick={togglePlay} title="play" aria-label="play">
|
|
@@ -52,6 +52,7 @@ const SpeechControl = ({ src, title }: Props) => {
|
|
|
52
52
|
};
|
|
53
53
|
return (
|
|
54
54
|
<div>
|
|
55
|
+
{/* eslint-disable-next-line jsx-a11y/media-has-caption */}
|
|
55
56
|
<audio ref={audioRef} src={src} title={title} preload="metadata" />
|
|
56
57
|
<SpeechPlayButton type="button" onClick={togglePlay}>
|
|
57
58
|
<VolumeUp role="img" aria-label="play" title="play" />
|
|
@@ -13,6 +13,11 @@ import { Link } from '@ndla/icons/common';
|
|
|
13
13
|
import { useTranslation } from 'react-i18next';
|
|
14
14
|
import Tooltip from '@ndla/tooltip';
|
|
15
15
|
import { copyTextToClipboard } from '@ndla/util';
|
|
16
|
+
import { colors } from '@ndla/core';
|
|
17
|
+
|
|
18
|
+
const ContainerDiv = styled.div`
|
|
19
|
+
position: relative;
|
|
20
|
+
`;
|
|
16
21
|
|
|
17
22
|
const IconButton = styled.button`
|
|
18
23
|
position: absolute;
|
|
@@ -23,18 +28,17 @@ const IconButton = styled.button`
|
|
|
23
28
|
z-index: 1;
|
|
24
29
|
transition: 0.2s;
|
|
25
30
|
opacity: 0;
|
|
31
|
+
color: ${colors.brand.grey};
|
|
26
32
|
|
|
27
33
|
& svg {
|
|
28
34
|
width: 30px;
|
|
29
35
|
height: 30px;
|
|
30
36
|
}
|
|
31
|
-
`;
|
|
32
37
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
&:hover button {
|
|
38
|
+
${ContainerDiv}:hover &,
|
|
39
|
+
&:focus, &:focus-visible, &:active {
|
|
36
40
|
cursor: pointer;
|
|
37
|
-
opacity:
|
|
41
|
+
opacity: 1;
|
|
38
42
|
}
|
|
39
43
|
`;
|
|
40
44
|
|
|
@@ -54,12 +58,12 @@ interface CopyButtonProps {
|
|
|
54
58
|
const CopyButton = ({ onClick, title, tooltip, content }: CopyButtonProps) => {
|
|
55
59
|
return (
|
|
56
60
|
<div>
|
|
57
|
-
<
|
|
58
|
-
<
|
|
61
|
+
<Tooltip tooltip={tooltip}>
|
|
62
|
+
<IconButton onClick={onClick} data-title={title} aria-label={`${tooltip}: ${title}`}>
|
|
59
63
|
<Link title={''} />
|
|
60
|
-
</
|
|
61
|
-
</
|
|
62
|
-
<h2 id={title} tabIndex={
|
|
64
|
+
</IconButton>
|
|
65
|
+
</Tooltip>
|
|
66
|
+
<h2 id={title} tabIndex={-1} dangerouslySetInnerHTML={{ __html: content || '' }} />
|
|
63
67
|
</div>
|
|
64
68
|
);
|
|
65
69
|
};
|
|
@@ -141,17 +141,11 @@ const FrontpageSearch = ({
|
|
|
141
141
|
return () => {
|
|
142
142
|
noScroll(false, 'preventPageScroll');
|
|
143
143
|
window.removeEventListener('scroll', resetScroll);
|
|
144
|
+
inputHasFocusRef.current = false;
|
|
144
145
|
};
|
|
145
146
|
}, [inputHasFocus]);
|
|
146
147
|
|
|
147
148
|
const onBlur = () => {
|
|
148
|
-
setTimeout(() => {
|
|
149
|
-
if (searchFieldRef.current) {
|
|
150
|
-
if (!searchFieldRef.current.contains(document.activeElement)) {
|
|
151
|
-
onInputBlur();
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
}, 0);
|
|
155
149
|
// This is needed when user tabs out of field
|
|
156
150
|
if (!searchFieldValue) {
|
|
157
151
|
onInputBlur();
|
|
@@ -147,6 +147,7 @@ export const MediaListItemMeta = ({ items = [] }: MediaListItemMetaProps) => {
|
|
|
147
147
|
|
|
148
148
|
return (
|
|
149
149
|
//@ts-ignore
|
|
150
|
+
// eslint-disable-next-line react/no-unknown-property
|
|
150
151
|
<ul {...cClasses('actions')} property="cc:attributionName" content={attributionMeta}>
|
|
151
152
|
{items.map((item) => (
|
|
152
153
|
<li key={uuid()} className="c-medialist__meta-item">
|
|
@@ -138,7 +138,7 @@ export const MessageBox = ({ type, children = '', links, showCloseButton, onClos
|
|
|
138
138
|
{links && (
|
|
139
139
|
<LinkWrapper>
|
|
140
140
|
{links.map((x) => (
|
|
141
|
-
<Link href={x.href}>
|
|
141
|
+
<Link href={x.href} key={x.href}>
|
|
142
142
|
<span>{x.text}</span>
|
|
143
143
|
<Forward />
|
|
144
144
|
</Link>
|
|
@@ -170,7 +170,7 @@ const hasForEachPolyfill = () => {
|
|
|
170
170
|
if ('NodeList' in window && !NodeList.prototype.forEach) {
|
|
171
171
|
NodeList.prototype.forEach = function (callback, thisArg) {
|
|
172
172
|
thisArg = thisArg || window;
|
|
173
|
-
for (
|
|
173
|
+
for (let i = 0; i < this.length; i++) {
|
|
174
174
|
callback.call(thisArg, this[i], i, this);
|
|
175
175
|
}
|
|
176
176
|
};
|
|
@@ -217,7 +217,7 @@ const FilmSlideshow = ({ autoSlide = false, slideshow = [], slideInterval = 5000
|
|
|
217
217
|
const [animationComplete, setAnimationComplete] = useState(true);
|
|
218
218
|
const slideRef = useRef<HTMLDivElement>(null);
|
|
219
219
|
const slideText = useRef<HTMLDivElement>(null);
|
|
220
|
-
|
|
220
|
+
const timer = useRef<ReturnType<typeof setTimeout> | null>(null);
|
|
221
221
|
|
|
222
222
|
const gotoSlide = useCallback((indexTarget: number, useAnimation = false) => {
|
|
223
223
|
setSwipeDistance(0);
|
|
@@ -66,8 +66,9 @@ const MovieGrid = ({
|
|
|
66
66
|
<MovieListing marginLeft={autoSizedProps.margin}>
|
|
67
67
|
{fetchingMoviesByType && <LoadingPlaceholder height={loadingPlaceholderHeight} />}
|
|
68
68
|
{!fetchingMoviesByType &&
|
|
69
|
-
moviesByType.map((movie) => (
|
|
69
|
+
moviesByType.map((movie, index) => (
|
|
70
70
|
<FilmContentCard
|
|
71
|
+
key={index}
|
|
71
72
|
hideTags
|
|
72
73
|
movie={movie}
|
|
73
74
|
columnWidth={autoSizedProps.columnWidth}
|
|
@@ -3,8 +3,7 @@ import styled from '@emotion/styled';
|
|
|
3
3
|
import { breakpoints, mq, spacing } from '@ndla/core';
|
|
4
4
|
import { useTranslation } from 'react-i18next';
|
|
5
5
|
import LayoutItem, { OneColumn } from '../Layout';
|
|
6
|
-
import ProgrammeSubjects from './ProgrammeSubjects';
|
|
7
|
-
import { GradesProps } from './ProgrammeSubjects';
|
|
6
|
+
import ProgrammeSubjects, { GradesProps } from './ProgrammeSubjects';
|
|
8
7
|
import MessageBox from '../Messages/MessageBox';
|
|
9
8
|
import { NavigationHeading } from '..';
|
|
10
9
|
const StyledWrapper = styled.div`
|
|
@@ -9,8 +9,7 @@
|
|
|
9
9
|
import React, { ReactNode } from 'react';
|
|
10
10
|
import { useTranslation } from 'react-i18next';
|
|
11
11
|
import styled from '@emotion/styled';
|
|
12
|
-
import { css } from '@emotion/react';
|
|
13
|
-
import { keyframes } from '@emotion/react';
|
|
12
|
+
import { css, keyframes } from '@emotion/react';
|
|
14
13
|
import SafeLink from '@ndla/safelink';
|
|
15
14
|
import { Additional, Core, HumanMaleBoard } from '@ndla/icons/common';
|
|
16
15
|
import { breakpoints, colors, fonts, mq, spacing } from '@ndla/core';
|
|
@@ -8,8 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
import React, { ReactNode } from 'react';
|
|
10
10
|
import styled from '@emotion/styled';
|
|
11
|
-
import { css } from '@emotion/react';
|
|
12
|
-
import { keyframes } from '@emotion/react';
|
|
11
|
+
import { css, keyframes } from '@emotion/react';
|
|
13
12
|
import { useTranslation } from 'react-i18next';
|
|
14
13
|
import NoContentBox from '../NoContentBox';
|
|
15
14
|
import ResourceItem from './ResourceItem';
|
|
@@ -91,8 +91,8 @@ const SubjectNewContent = ({ heading, content }: Props) => (
|
|
|
91
91
|
<StyledSubjectSectionTitle>{heading}</StyledSubjectSectionTitle>
|
|
92
92
|
<nav>
|
|
93
93
|
<StyledUl>
|
|
94
|
-
{content.map((item) => (
|
|
95
|
-
<StyledListItem>
|
|
94
|
+
{content.map((item, index) => (
|
|
95
|
+
<StyledListItem key={index}>
|
|
96
96
|
<LeftWrapper>
|
|
97
97
|
<ContentTypeBadge type={item.contentType} size="x-small" background border />
|
|
98
98
|
<ContentLinkWrapper>
|
|
@@ -264,8 +264,7 @@ $navigation-row-width: 980px / 3;
|
|
|
264
264
|
|
|
265
265
|
@include mq(desktop) {
|
|
266
266
|
padding: $spacing--large;
|
|
267
|
-
margin: -($spacing + $spacing--small) $spacing + $spacing--small 0 $spacing +
|
|
268
|
-
$spacing--small;
|
|
267
|
+
margin: -($spacing + $spacing--small) $spacing + $spacing--small 0 $spacing + $spacing--small;
|
|
269
268
|
}
|
|
270
269
|
|
|
271
270
|
& > * {
|
|
@@ -362,7 +361,8 @@ $navigation-row-width: 980px / 3;
|
|
|
362
361
|
@include inuit-font-size(26px);
|
|
363
362
|
}
|
|
364
363
|
|
|
365
|
-
a,
|
|
364
|
+
a,
|
|
365
|
+
button {
|
|
366
366
|
padding: 0;
|
|
367
367
|
padding-right: $spacing--small;
|
|
368
368
|
border: 0;
|
|
@@ -374,7 +374,8 @@ $navigation-row-width: 980px / 3;
|
|
|
374
374
|
svg {
|
|
375
375
|
transition: transform 100ms ease;
|
|
376
376
|
}
|
|
377
|
-
&:hover,
|
|
377
|
+
&:hover,
|
|
378
|
+
&:focus {
|
|
378
379
|
svg {
|
|
379
380
|
transform: translateX($spacing--small / 4);
|
|
380
381
|
}
|
|
@@ -386,7 +387,8 @@ $navigation-row-width: 980px / 3;
|
|
|
386
387
|
|
|
387
388
|
@include mq($until: tabletWide) {
|
|
388
389
|
width: 100%;
|
|
389
|
-
a,
|
|
390
|
+
a,
|
|
391
|
+
button {
|
|
390
392
|
background: $brand-color--lighter;
|
|
391
393
|
box-shadow: none;
|
|
392
394
|
width: 100%;
|
|
@@ -402,13 +404,14 @@ $navigation-row-width: 980px / 3;
|
|
|
402
404
|
}
|
|
403
405
|
}
|
|
404
406
|
@include mq($until: mobileWide) {
|
|
405
|
-
a,
|
|
407
|
+
a,
|
|
408
|
+
button {
|
|
406
409
|
padding: 0 $left-margin-narrow-screen;
|
|
407
410
|
}
|
|
408
411
|
}
|
|
409
412
|
}
|
|
410
413
|
&__menu-filter {
|
|
411
|
-
display:flex;
|
|
414
|
+
display: flex;
|
|
412
415
|
flex-wrap: wrap;
|
|
413
416
|
margin-top: -$spacing--small;
|
|
414
417
|
button {
|
|
@@ -453,7 +456,7 @@ $navigation-row-width: 980px / 3;
|
|
|
453
456
|
.c-topic-menu__back-button {
|
|
454
457
|
display: flex;
|
|
455
458
|
align-items: center;
|
|
456
|
-
cursor:pointer;
|
|
459
|
+
cursor: pointer;
|
|
457
460
|
border: 0;
|
|
458
461
|
padding: 0;
|
|
459
462
|
color: $brand-color;
|
|
@@ -484,7 +487,7 @@ $navigation-row-width: 980px / 3;
|
|
|
484
487
|
.c-topic-menu__back-button-slides {
|
|
485
488
|
display: flex;
|
|
486
489
|
align-items: center;
|
|
487
|
-
cursor:pointer;
|
|
490
|
+
cursor: pointer;
|
|
488
491
|
border: 0;
|
|
489
492
|
padding: 0;
|
|
490
493
|
color: $brand-color;
|
|
@@ -734,7 +737,6 @@ $navigation-row-width: 980px / 3;
|
|
|
734
737
|
&:active,
|
|
735
738
|
&:focus {
|
|
736
739
|
background-color: $brand-color--light;
|
|
737
|
-
|
|
738
740
|
}
|
|
739
741
|
}
|
|
740
742
|
|
|
@@ -745,13 +747,13 @@ $navigation-row-width: 980px / 3;
|
|
|
745
747
|
height: auto;
|
|
746
748
|
min-height: $link-height;
|
|
747
749
|
|
|
748
|
-
.c-topic-menu__link-wrapper{
|
|
750
|
+
.c-topic-menu__link-wrapper {
|
|
749
751
|
border-bottom: 1px solid $brand-color--dark;
|
|
750
752
|
padding-bottom: $spacing--small;
|
|
751
753
|
display: flex;
|
|
752
754
|
flex-wrap: wrap;
|
|
753
755
|
@include mq($until: tabletWide) {
|
|
754
|
-
border:0;
|
|
756
|
+
border: 0;
|
|
755
757
|
padding-bottom: 0;
|
|
756
758
|
}
|
|
757
759
|
}
|
|
@@ -871,6 +873,7 @@ $navigation-row-width: 980px / 3;
|
|
|
871
873
|
|
|
872
874
|
&-right {
|
|
873
875
|
justify-content: flex-end;
|
|
876
|
+
margin-right: 16px;
|
|
874
877
|
}
|
|
875
878
|
}
|
|
876
879
|
.c-topic-menu__search {
|
|
@@ -940,7 +943,7 @@ $navigation-row-width: 980px / 3;
|
|
|
940
943
|
padding-right: $spacing + $spacing--small;
|
|
941
944
|
}
|
|
942
945
|
& > nav:first-child {
|
|
943
|
-
margin-top:0;
|
|
946
|
+
margin-top: 0;
|
|
944
947
|
}
|
|
945
948
|
}
|
|
946
949
|
|
|
@@ -19,6 +19,7 @@ interface AddFolderButtonProps {
|
|
|
19
19
|
focusedFolder?: FolderType;
|
|
20
20
|
setNewFolderParentId: (id?: string) => void;
|
|
21
21
|
setShowTree: (value: boolean) => void;
|
|
22
|
+
loading?: boolean;
|
|
22
23
|
}
|
|
23
24
|
|
|
24
25
|
const StyledAddFolderButton = styled(Button)`
|
|
@@ -33,30 +34,28 @@ const StyledPlus = styled(Plus)`
|
|
|
33
34
|
width: 24px;
|
|
34
35
|
`;
|
|
35
36
|
|
|
36
|
-
const AddFolderButton = ({
|
|
37
|
+
const AddFolderButton = ({
|
|
38
|
+
canAddFolder,
|
|
39
|
+
loading,
|
|
40
|
+
setNewFolderParentId,
|
|
41
|
+
focusedFolder,
|
|
42
|
+
setShowTree,
|
|
43
|
+
}: AddFolderButtonProps) => {
|
|
37
44
|
const { t } = useTranslation();
|
|
38
45
|
const ref = useRef<HTMLButtonElement>(null);
|
|
46
|
+
const tooltip = loading
|
|
47
|
+
? t('loading')
|
|
48
|
+
: canAddFolder
|
|
49
|
+
? t('myNdla.newFolderUnder', { folderName: focusedFolder?.name })
|
|
50
|
+
: t('treeStructure.maxFoldersAlreadyAdded');
|
|
39
51
|
return (
|
|
40
|
-
<Tooltip
|
|
41
|
-
tooltip={
|
|
42
|
-
canAddFolder
|
|
43
|
-
? t('myNdla.newFolderUnder', {
|
|
44
|
-
folderName: focusedFolder?.name,
|
|
45
|
-
})
|
|
46
|
-
: t('treeStructure.maxFoldersAlreadyAdded')
|
|
47
|
-
}>
|
|
52
|
+
<Tooltip tooltip={tooltip}>
|
|
48
53
|
<StyledAddFolderButton
|
|
49
54
|
ref={ref}
|
|
50
55
|
variant="outline"
|
|
51
56
|
shape="pill"
|
|
52
|
-
disabled={!canAddFolder}
|
|
53
|
-
aria-label={
|
|
54
|
-
canAddFolder
|
|
55
|
-
? t('myNdla.newFolderUnder', {
|
|
56
|
-
folderName: focusedFolder?.name,
|
|
57
|
-
})
|
|
58
|
-
: t('treeStructure.maxFoldersAlreadyAdded')
|
|
59
|
-
}
|
|
57
|
+
disabled={loading || !canAddFolder}
|
|
58
|
+
aria-label={tooltip}
|
|
60
59
|
onMouseDown={(e) => {
|
|
61
60
|
e.preventDefault();
|
|
62
61
|
e.stopPropagation();
|
|
@@ -6,16 +6,16 @@
|
|
|
6
6
|
*
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import React, { KeyboardEvent } from 'react';
|
|
9
|
+
import React, { KeyboardEvent, forwardRef } from 'react';
|
|
10
10
|
import styled from '@emotion/styled';
|
|
11
11
|
import { useForwardedRef } from '@ndla/util';
|
|
12
12
|
import { breakpoints, colors, mq, spacing } from '@ndla/core';
|
|
13
13
|
import { ChevronUp, ChevronDown } from '@ndla/icons/common';
|
|
14
|
-
import { forwardRef } from 'react';
|
|
15
14
|
import { ButtonV2 as Button, IconButtonV2 as IconButton } from '@ndla/button';
|
|
16
15
|
import { treestructureId } from './helperFunctions';
|
|
17
16
|
import { FolderType, TreeStructureType } from './types';
|
|
18
17
|
import { arrowNavigation } from './arrowNavigation';
|
|
18
|
+
import ContentLoader from '../ContentLoader';
|
|
19
19
|
|
|
20
20
|
interface StyledRowProps {
|
|
21
21
|
isOpen: boolean;
|
|
@@ -52,6 +52,7 @@ interface Props {
|
|
|
52
52
|
showTree: boolean;
|
|
53
53
|
type: TreeStructureType;
|
|
54
54
|
label?: string;
|
|
55
|
+
loading?: boolean;
|
|
55
56
|
focusedFolder?: FolderType;
|
|
56
57
|
selectedFolder?: FolderType;
|
|
57
58
|
setSelectedFolder: (folder: FolderType) => void;
|
|
@@ -77,6 +78,7 @@ const ComboboxButton = forwardRef<HTMLButtonElement, Props>(
|
|
|
77
78
|
setFocusedFolder,
|
|
78
79
|
onOpenFolder,
|
|
79
80
|
onCloseFolder,
|
|
81
|
+
loading,
|
|
80
82
|
ariaDescribedby,
|
|
81
83
|
},
|
|
82
84
|
ref,
|
|
@@ -116,25 +118,48 @@ const ComboboxButton = forwardRef<HTMLButtonElement, Props>(
|
|
|
116
118
|
innerRef.current?.focus();
|
|
117
119
|
}
|
|
118
120
|
}}>
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
121
|
+
{loading && (
|
|
122
|
+
<ContentLoader width={1000} height={40}>
|
|
123
|
+
<rect x="15" y="0" width="1000" rx="3" ry="3" r="15" height="40" />
|
|
124
|
+
</ContentLoader>
|
|
125
|
+
)}
|
|
126
|
+
{!loading && (
|
|
127
|
+
<StyledSelectedFolder
|
|
128
|
+
ref={innerRef}
|
|
129
|
+
tabIndex={0}
|
|
130
|
+
id={treestructureId(type, 'combobox')}
|
|
131
|
+
role="combobox"
|
|
132
|
+
aria-controls={treestructureId(type, 'popup')}
|
|
133
|
+
aria-haspopup="tree"
|
|
134
|
+
aria-expanded={showTree}
|
|
135
|
+
aria-labelledby={label ? treestructureId(type, 'label') : undefined}
|
|
136
|
+
aria-activedescendant={focusedFolder ? treestructureId(type, focusedFolder.id) : undefined}
|
|
137
|
+
aria-describedby={ariaDescribedby}
|
|
138
|
+
variant="ghost"
|
|
139
|
+
colorTheme="light"
|
|
140
|
+
fontWeight="normal"
|
|
141
|
+
shape="sharp"
|
|
142
|
+
onKeyDown={onKeyDown}
|
|
143
|
+
onClick={() => {
|
|
144
|
+
innerRef.current?.focus();
|
|
145
|
+
onToggleTree(!showTree);
|
|
146
|
+
}}>
|
|
147
|
+
{selectedFolder?.name}
|
|
148
|
+
</StyledSelectedFolder>
|
|
149
|
+
)}
|
|
150
|
+
<IconButton
|
|
151
|
+
disabled={loading}
|
|
152
|
+
aria-busy={loading}
|
|
153
|
+
aria-hidden
|
|
154
|
+
aria-label=""
|
|
155
|
+
tabIndex={-1}
|
|
130
156
|
variant="ghost"
|
|
131
|
-
colorTheme="
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
<IconButton aria-hidden aria-label="" tabIndex={-1} variant="ghost" colorTheme="greyLighter" size="small">
|
|
157
|
+
colorTheme="greyLighter"
|
|
158
|
+
size="small"
|
|
159
|
+
onClick={() => {
|
|
160
|
+
innerRef.current?.focus();
|
|
161
|
+
onToggleTree(!showTree);
|
|
162
|
+
}}>
|
|
138
163
|
{showTree ? <ChevronUp /> : <ChevronDown />}
|
|
139
164
|
</IconButton>
|
|
140
165
|
</StyledRow>
|
|
@@ -189,6 +189,7 @@ const TreeStructure = ({
|
|
|
189
189
|
{label && <StyledLabel id={treestructureId(type, 'label')}>{label}</StyledLabel>}
|
|
190
190
|
{type === 'picker' && (
|
|
191
191
|
<AddFolderButton
|
|
192
|
+
loading={loading}
|
|
192
193
|
canAddFolder={!!canAddFolder}
|
|
193
194
|
focusedFolder={focusedFolder}
|
|
194
195
|
setNewFolderParentId={setNewFolderParentId}
|
|
@@ -203,6 +204,7 @@ const TreeStructure = ({
|
|
|
203
204
|
showTree={showTree}
|
|
204
205
|
type={type}
|
|
205
206
|
label={label}
|
|
207
|
+
loading={loading}
|
|
206
208
|
focusedFolder={focusedFolder}
|
|
207
209
|
selectedFolder={selectedFolder}
|
|
208
210
|
setSelectedFolder={setSelectedFolder}
|
package/src/i18n/index.ts
CHANGED
package/src/index.ts
CHANGED
|
@@ -174,7 +174,7 @@ export { default as Breadcrumb, HeaderBreadcrumb, HomeBreadcrumb, ActionBreadcru
|
|
|
174
174
|
export type { SimpleBreadcrumbItem, IndexedBreadcrumbItem } from './Breadcrumb';
|
|
175
175
|
|
|
176
176
|
export type { BreadcrumbItemProps } from './Breadcrumblist';
|
|
177
|
-
export { i18nInstance, formatNestedMessages
|
|
177
|
+
export { i18nInstance, formatNestedMessages } from './i18n';
|
|
178
178
|
export { default as ResourceGroup } from './ResourceGroup';
|
|
179
179
|
|
|
180
180
|
export { default as LayoutItem, OneColumn, PageContainer, Content } from './Layout';
|