@ndla/ui 27.1.1 → 27.1.3
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/MyNdla/Resource/FolderInput.js +65 -77
- package/es/Resource/resourceComponents.js +13 -13
- package/es/TreeStructure/AddFolderButton.js +87 -0
- package/es/TreeStructure/ComboboxButton.js +14 -65
- package/es/TreeStructure/FolderItem.js +12 -15
- package/es/TreeStructure/FolderItems.js +12 -14
- package/es/TreeStructure/TreeStructure.js +74 -55
- package/es/locale/messages-en.js +1 -1
- package/es/locale/messages-nb.js +1 -1
- package/es/locale/messages-nn.js +1 -1
- package/es/locale/messages-se.js +1 -1
- package/es/locale/messages-sma.js +1 -1
- package/lib/MyNdla/Resource/FolderInput.d.ts +7 -6
- package/lib/MyNdla/Resource/FolderInput.js +65 -73
- package/lib/Resource/resourceComponents.js +13 -13
- package/lib/TreeStructure/AddFolderButton.d.ts +16 -0
- package/lib/TreeStructure/AddFolderButton.js +100 -0
- package/lib/TreeStructure/ComboboxButton.d.ts +2 -6
- package/lib/TreeStructure/ComboboxButton.js +20 -65
- package/lib/TreeStructure/FolderItem.d.ts +1 -1
- package/lib/TreeStructure/FolderItem.js +12 -15
- package/lib/TreeStructure/FolderItems.d.ts +4 -3
- package/lib/TreeStructure/FolderItems.js +12 -15
- package/lib/TreeStructure/TreeStructure.d.ts +4 -4
- package/lib/TreeStructure/TreeStructure.js +74 -55
- package/lib/TreeStructure/index.d.ts +1 -1
- package/lib/TreeStructure/types.d.ts +8 -7
- package/lib/index.d.ts +1 -1
- package/lib/locale/messages-en.js +1 -1
- package/lib/locale/messages-nb.js +1 -1
- package/lib/locale/messages-nn.js +1 -1
- package/lib/locale/messages-se.js +1 -1
- package/lib/locale/messages-sma.js +1 -1
- package/package.json +7 -7
- package/src/MyNdla/Resource/FolderInput.tsx +69 -73
- package/src/Resource/resourceComponents.tsx +4 -6
- package/src/TreeStructure/AddFolderButton.tsx +79 -0
- package/src/TreeStructure/ComboboxButton.tsx +11 -56
- package/src/TreeStructure/FolderItem.tsx +5 -6
- package/src/TreeStructure/FolderItems.tsx +8 -15
- package/src/TreeStructure/TreeStructure.tsx +60 -45
- package/src/TreeStructure/index.ts +1 -1
- package/src/TreeStructure/types.ts +13 -7
- package/src/index.ts +1 -1
- package/src/locale/messages-en.ts +1 -1
- package/src/locale/messages-nb.ts +1 -1
- package/src/locale/messages-nn.ts +1 -1
- package/src/locale/messages-se.ts +1 -1
- package/src/locale/messages-sma.ts +1 -1
- package/es/TreeStructure/FolderNameInput.js +0 -143
- package/lib/TreeStructure/FolderNameInput.d.ts +0 -19
- package/lib/TreeStructure/FolderNameInput.js +0 -159
- package/src/TreeStructure/FolderNameInput.tsx +0 -167
|
@@ -993,7 +993,7 @@ var messages = _objectSpread(_objectSpread({
|
|
|
993
993
|
myPage: 'Mi side',
|
|
994
994
|
deleteAccount: 'Slett Min NDLA',
|
|
995
995
|
logout: 'Logg ut av Min NDLA',
|
|
996
|
-
loginText: '
|
|
996
|
+
loginText: 'For å kunne bruke tjenesten Min NDLA må du vere elev eller jobbe på ein skule i eit fylke som er med i NDLA-samarbeidet. Vi ber om at du ikkje skriv noko støtande, personsensitiv informasjon eller andre persondata i tekstfelt. Les vår ',
|
|
997
997
|
loginTextLink: 'personvernerklæring her',
|
|
998
998
|
loginTerms: 'Logg på med Feide for å få tilgang. Ved å logge på godkjennar du våre vilkår for bruk',
|
|
999
999
|
loginResourcePitch: 'Ønsker du å favorittmerke denne sida?',
|
|
@@ -993,7 +993,7 @@ var messages = _objectSpread(_objectSpread({
|
|
|
993
993
|
myPage: 'Mu siidu',
|
|
994
994
|
deleteAccount: 'Sihko mu NDLA',
|
|
995
995
|
logout: 'Logge eret mu NDLAs',
|
|
996
|
-
loginText: '
|
|
996
|
+
loginText: 'For å kunne bruke tjenesten Min NDLA må du vere elev eller jobbe på ein skule i eit fylke som er med i NDLA-samarbeidet. Vi ber om at du ikkje skriv noko støtande, personsensitiv informasjon eller andre persondata i tekstfelt. Les vår ',
|
|
997
997
|
loginTextLink: 'personvernerklæring her',
|
|
998
998
|
loginTerms: 'Logge Feide bokte vai oaččut beassanlobi. Go logget sisa de dohkkehat min geavahaneavttuid.',
|
|
999
999
|
loginResourcePitch: 'Dáhtut go merket siiddu oiddohin?',
|
|
@@ -993,7 +993,7 @@ var messages = _objectSpread(_objectSpread({
|
|
|
993
993
|
myPage: 'Min side',
|
|
994
994
|
deleteAccount: 'Slett Min NDLA',
|
|
995
995
|
logout: 'Logg ut av Min NDLA',
|
|
996
|
-
loginText: '
|
|
996
|
+
loginText: 'For å kunne bruke tjenesten Min NDLA må du vere elev eller jobbe på ein skule i eit fylke som er med i NDLA-samarbeidet. Vi ber om at du ikkje skriv noko støtande, personsensitiv informasjon eller andre persondata i tekstfelt. Les vår ',
|
|
997
997
|
loginTextLink: 'personvernerklæring her',
|
|
998
998
|
loginTerms: 'Logg på med Feide for å få tilgang. Ved å logge på godkjenner du våre vilkår for bruk',
|
|
999
999
|
loginResourcePitch: 'Ønsker du å favorittmerke denne siden?',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ndla/ui",
|
|
3
|
-
"version": "27.1.
|
|
3
|
+
"version": "27.1.3",
|
|
4
4
|
"description": "UI component library for NDLA.",
|
|
5
5
|
"license": "GPL-3.0",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -32,16 +32,16 @@
|
|
|
32
32
|
],
|
|
33
33
|
"dependencies": {
|
|
34
34
|
"@ndla/article-scripts": "^3.0.2",
|
|
35
|
-
"@ndla/button": "^3.
|
|
35
|
+
"@ndla/button": "^3.6.0",
|
|
36
36
|
"@ndla/carousel": "^1.2.23",
|
|
37
37
|
"@ndla/core": "^2.3.5",
|
|
38
|
-
"@ndla/forms": "^3.3.
|
|
38
|
+
"@ndla/forms": "^3.3.4",
|
|
39
39
|
"@ndla/hooks": "^1.1.6",
|
|
40
40
|
"@ndla/icons": "^1.13.0",
|
|
41
41
|
"@ndla/licenses": "^5.0.17",
|
|
42
|
-
"@ndla/modal": "^1.
|
|
43
|
-
"@ndla/notion": "^3.1.
|
|
44
|
-
"@ndla/safelink": "^2.2.
|
|
42
|
+
"@ndla/modal": "^1.5.0",
|
|
43
|
+
"@ndla/notion": "^3.1.45",
|
|
44
|
+
"@ndla/safelink": "^2.2.18",
|
|
45
45
|
"@ndla/switch": "^0.1.13",
|
|
46
46
|
"@ndla/tabs": "^1.1.22",
|
|
47
47
|
"@ndla/tooltip": "^2.2.1",
|
|
@@ -85,5 +85,5 @@
|
|
|
85
85
|
"publishConfig": {
|
|
86
86
|
"access": "public"
|
|
87
87
|
},
|
|
88
|
-
"gitHead": "
|
|
88
|
+
"gitHead": "88e2b2d4c85688382f9edb3e1d9a31d45fae00ab"
|
|
89
89
|
}
|
|
@@ -7,110 +7,106 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import styled from '@emotion/styled';
|
|
10
|
-
import { IconButton } from '@ndla/button';
|
|
11
|
-
import { FolderOutlined } from '@ndla/icons/contentType';
|
|
10
|
+
import { IconButton, IconButtonV2 } from '@ndla/button';
|
|
12
11
|
import { Cross } from '@ndla/icons/action';
|
|
13
|
-
import React, {
|
|
12
|
+
import React, { ComponentProps, forwardRef, useEffect } from 'react';
|
|
13
|
+
import { isMobile } from 'react-device-detect';
|
|
14
14
|
import { useTranslation } from 'react-i18next';
|
|
15
15
|
import { colors, spacing } from '@ndla/core';
|
|
16
|
-
import {
|
|
17
|
-
import { css } from '@emotion/core';
|
|
16
|
+
import { InputV2 } from '@ndla/forms';
|
|
18
17
|
import { Done } from '@ndla/icons/editor';
|
|
18
|
+
import { Spinner } from '@ndla/icons';
|
|
19
|
+
import { useForwardedRef } from '@ndla/util';
|
|
20
|
+
|
|
21
|
+
interface Props extends ComponentProps<typeof InputV2> {
|
|
22
|
+
loading?: boolean;
|
|
23
|
+
onClose?: () => void;
|
|
24
|
+
onSave: () => void;
|
|
25
|
+
}
|
|
19
26
|
|
|
20
27
|
// Source: https://kovart.github.io/dashed-border-generator/
|
|
21
|
-
const borderStyle =
|
|
22
|
-
|
|
23
|
-
|
|
28
|
+
const borderStyle = (error?: boolean) =>
|
|
29
|
+
`url("data:image/svg+xml,%3csvg width='100%25' height='100%25' xmlns='http://www.w3.org/2000/svg'%3e%3crect width='100%25' height='100%25' fill='none' stroke='${encodeURIComponent(
|
|
30
|
+
error ? colors.support.red : colors.brand.tertiary,
|
|
31
|
+
)}' stroke-width='2' stroke-dasharray='8%2c8' stroke-dashoffset='4' stroke-linecap='square'/%3e%3c/svg%3e")`;
|
|
24
32
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
svg {
|
|
29
|
-
color: ${colors.brand.primary};
|
|
30
|
-
height: 20px;
|
|
31
|
-
width: 20px;
|
|
32
|
-
}
|
|
33
|
-
`;
|
|
33
|
+
interface StyledInputProps {
|
|
34
|
+
error?: string;
|
|
35
|
+
}
|
|
34
36
|
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
background:
|
|
38
|
-
background-image: ${borderStyle};
|
|
37
|
+
const StyledInput = styled(InputV2)<StyledInputProps>`
|
|
38
|
+
background-color: white;
|
|
39
|
+
background-image: ${({ error }) => borderStyle(!!error)};
|
|
39
40
|
border: none;
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
&& {
|
|
44
|
-
flex-grow: 1;
|
|
45
|
-
flex-basis: 0;
|
|
46
|
-
min-width: 0;
|
|
41
|
+
border-radius: 0;
|
|
42
|
+
flex-wrap: nowrap;
|
|
43
|
+
input {
|
|
47
44
|
line-height: 1.75em;
|
|
48
45
|
color: ${colors.brand.primary};
|
|
46
|
+
caret-color: ${colors.brand.tertiary};
|
|
49
47
|
::selection {
|
|
50
48
|
background: ${colors.brand.lighter};
|
|
51
49
|
}
|
|
50
|
+
::placeholder {
|
|
51
|
+
color: ${colors.brand.tertiary};
|
|
52
|
+
}
|
|
52
53
|
}
|
|
53
54
|
`;
|
|
54
55
|
|
|
55
56
|
const Row = styled.div`
|
|
56
57
|
display: flex;
|
|
57
|
-
|
|
58
|
-
|
|
58
|
+
align-items: center;
|
|
59
|
+
gap: ${spacing.xxsmall};
|
|
60
|
+
padding-right: ${spacing.xsmall};
|
|
59
61
|
`;
|
|
60
62
|
|
|
61
|
-
|
|
62
|
-
onAddFolder: (name: string) => void;
|
|
63
|
-
onClose: () => void;
|
|
64
|
-
autoSelect?: boolean;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
const FolderInput = ({ onAddFolder, onClose, autoSelect }: Props) => {
|
|
63
|
+
const FolderInput = forwardRef<HTMLInputElement, Props>(({ loading, error, onClose, onSave, ...rest }, ref) => {
|
|
68
64
|
const { t } = useTranslation();
|
|
69
|
-
const
|
|
70
|
-
const [input, setInput] = useState<string>(newFolderText);
|
|
71
|
-
const inputRef = useRef<HTMLInputElement>(null);
|
|
72
|
-
|
|
73
|
-
const handleInputChange = (e: ChangeEvent<HTMLInputElement>) => {
|
|
74
|
-
setInput(e.target.value);
|
|
75
|
-
};
|
|
65
|
+
const inputRef = useForwardedRef(ref);
|
|
76
66
|
|
|
77
|
-
|
|
78
|
-
if (
|
|
79
|
-
|
|
80
|
-
onAddFolder(input);
|
|
81
|
-
} else if (e.key === 'Escape') {
|
|
82
|
-
e.preventDefault();
|
|
83
|
-
onClose();
|
|
67
|
+
useEffect(() => {
|
|
68
|
+
if (isMobile) {
|
|
69
|
+
inputRef.current?.scrollIntoView({ behavior: 'smooth' });
|
|
84
70
|
}
|
|
85
|
-
|
|
71
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
72
|
+
}, []);
|
|
86
73
|
|
|
87
74
|
return (
|
|
88
75
|
<StyledInput
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
onKeyDown={onKeydown}
|
|
96
|
-
aria-label={newFolderText}
|
|
97
|
-
iconLeft={
|
|
98
|
-
<StyledFolderIcon>
|
|
99
|
-
<FolderOutlined />
|
|
100
|
-
</StyledFolderIcon>
|
|
101
|
-
}
|
|
102
|
-
iconRight={
|
|
76
|
+
white
|
|
77
|
+
error={error}
|
|
78
|
+
aria-disabled={loading ? true : undefined}
|
|
79
|
+
aria-describedby={'folder-input-spinner'}
|
|
80
|
+
ref={ref}
|
|
81
|
+
after={
|
|
103
82
|
<Row>
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
83
|
+
{!loading && (
|
|
84
|
+
<>
|
|
85
|
+
{!error && (
|
|
86
|
+
<IconButtonV2
|
|
87
|
+
variant={'ghost'}
|
|
88
|
+
colorTheme="light"
|
|
89
|
+
tabIndex={0}
|
|
90
|
+
aria-label={t('save')}
|
|
91
|
+
title={t('save')}
|
|
92
|
+
size="small"
|
|
93
|
+
onClick={onSave}>
|
|
94
|
+
<Done />
|
|
95
|
+
</IconButtonV2>
|
|
96
|
+
)}
|
|
97
|
+
<IconButton aria-label={t('close')} title={t('close')} size="small" ghostPill onClick={onClose}>
|
|
98
|
+
<Cross />
|
|
99
|
+
</IconButton>
|
|
100
|
+
</>
|
|
101
|
+
)}
|
|
102
|
+
<div aria-live="assertive">
|
|
103
|
+
{loading && <Spinner size="normal" margin={spacing.small} id="folder-spinner" aria-label={t('loading')} />}
|
|
104
|
+
</div>
|
|
110
105
|
</Row>
|
|
111
106
|
}
|
|
107
|
+
{...rest}
|
|
112
108
|
/>
|
|
113
109
|
);
|
|
114
|
-
};
|
|
110
|
+
});
|
|
115
111
|
|
|
116
112
|
export default FolderInput;
|
|
@@ -185,12 +185,10 @@ export const TopicList = ({ topics }: TopicListProps) => {
|
|
|
185
185
|
return (
|
|
186
186
|
<StyledTopicList aria-label={t('navigation.topics')}>
|
|
187
187
|
{topics.map((topic, i) => (
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
</StyledTopicListElement>
|
|
193
|
-
</>
|
|
188
|
+
<StyledTopicListElement key={topic}>
|
|
189
|
+
{topic}
|
|
190
|
+
{i !== topics.length - 1 && <StyledTopicDivider aria-hidden="true">•</StyledTopicDivider>}
|
|
191
|
+
</StyledTopicListElement>
|
|
194
192
|
))}
|
|
195
193
|
</StyledTopicList>
|
|
196
194
|
);
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2022-present, NDLA.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the GPLv3 license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import React, { useRef } from 'react';
|
|
10
|
+
import { useTranslation } from 'react-i18next';
|
|
11
|
+
import Tooltip from '@ndla/tooltip';
|
|
12
|
+
import styled from '@emotion/styled';
|
|
13
|
+
import { ButtonV2 as Button } from '@ndla/button';
|
|
14
|
+
import { Plus } from '@ndla/icons/action';
|
|
15
|
+
import { FolderType } from './types';
|
|
16
|
+
|
|
17
|
+
interface AddFolderButtonProps {
|
|
18
|
+
canAddFolder: boolean;
|
|
19
|
+
focusedFolder?: FolderType;
|
|
20
|
+
setNewFolderParentId: (id?: string) => void;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const StyledAddFolderButton = styled(Button)`
|
|
24
|
+
&,
|
|
25
|
+
&:disabled {
|
|
26
|
+
border-color: transparent;
|
|
27
|
+
}
|
|
28
|
+
`;
|
|
29
|
+
|
|
30
|
+
const StyledPlus = styled(Plus)`
|
|
31
|
+
height: 24px;
|
|
32
|
+
width: 24px;
|
|
33
|
+
`;
|
|
34
|
+
|
|
35
|
+
const AddFolderButton = ({ canAddFolder, setNewFolderParentId, focusedFolder }: AddFolderButtonProps) => {
|
|
36
|
+
const { t } = useTranslation();
|
|
37
|
+
const ref = useRef<HTMLButtonElement>(null);
|
|
38
|
+
return (
|
|
39
|
+
<Tooltip
|
|
40
|
+
tooltip={
|
|
41
|
+
canAddFolder
|
|
42
|
+
? t('myNdla.newFolderUnder', {
|
|
43
|
+
folderName: focusedFolder?.name,
|
|
44
|
+
})
|
|
45
|
+
: t('treeStructure.maxFoldersAlreadyAdded')
|
|
46
|
+
}>
|
|
47
|
+
<StyledAddFolderButton
|
|
48
|
+
ref={ref}
|
|
49
|
+
variant="outline"
|
|
50
|
+
shape="pill"
|
|
51
|
+
disabled={!canAddFolder}
|
|
52
|
+
aria-label={
|
|
53
|
+
canAddFolder
|
|
54
|
+
? t('myNdla.newFolderUnder', {
|
|
55
|
+
folderName: focusedFolder?.name,
|
|
56
|
+
})
|
|
57
|
+
: t('treeStructure.maxFoldersAlreadyAdded')
|
|
58
|
+
}
|
|
59
|
+
onMouseDown={(e) => {
|
|
60
|
+
e.preventDefault();
|
|
61
|
+
e.stopPropagation();
|
|
62
|
+
ref.current?.focus();
|
|
63
|
+
}}
|
|
64
|
+
onMouseUp={(e) => {
|
|
65
|
+
e.preventDefault();
|
|
66
|
+
e.stopPropagation();
|
|
67
|
+
ref.current?.focus();
|
|
68
|
+
}}
|
|
69
|
+
onClick={(e) => {
|
|
70
|
+
e.currentTarget.focus();
|
|
71
|
+
setNewFolderParentId(focusedFolder?.id);
|
|
72
|
+
}}>
|
|
73
|
+
<StyledPlus /> {t('myNdla.newFolder')}
|
|
74
|
+
</StyledAddFolderButton>
|
|
75
|
+
</Tooltip>
|
|
76
|
+
);
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
export default AddFolderButton;
|
|
@@ -7,13 +7,9 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import React, { KeyboardEvent } from 'react';
|
|
10
|
-
import { useTranslation } from 'react-i18next';
|
|
11
10
|
import styled from '@emotion/styled';
|
|
12
11
|
import { useForwardedRef } from '@ndla/util';
|
|
13
|
-
import
|
|
14
|
-
import { colors, spacing } from '@ndla/core';
|
|
15
|
-
import { IFolder } from '@ndla/types-learningpath-api';
|
|
16
|
-
import { Plus } from '@ndla/icons/action';
|
|
12
|
+
import { breakpoints, colors, mq, spacing } from '@ndla/core';
|
|
17
13
|
import { ChevronUp, ChevronDown } from '@ndla/icons/common';
|
|
18
14
|
import { forwardRef } from 'react';
|
|
19
15
|
import { ButtonV2 as Button, IconButtonV2 as IconButton } from '@ndla/button';
|
|
@@ -27,8 +23,8 @@ interface StyledRowProps {
|
|
|
27
23
|
|
|
28
24
|
const StyledRow = styled.div<StyledRowProps>`
|
|
29
25
|
display: flex;
|
|
30
|
-
justify-content: space-between;
|
|
31
26
|
padding: ${spacing.xxsmall};
|
|
27
|
+
align-items: center;
|
|
32
28
|
border-bottom: ${({ isOpen }) => isOpen && `1px solid ${colors.brand.tertiary}`};
|
|
33
29
|
`;
|
|
34
30
|
const StyledSelectedFolder = styled(Button)`
|
|
@@ -44,35 +40,25 @@ const StyledSelectedFolder = styled(Button)`
|
|
|
44
40
|
:focus-visible {
|
|
45
41
|
outline: none;
|
|
46
42
|
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
&:disabled {
|
|
52
|
-
border-color: transparent;
|
|
43
|
+
${mq.range({ until: breakpoints.tablet })} {
|
|
44
|
+
min-height: 4rem;
|
|
45
|
+
max-height: 4rem;
|
|
46
|
+
text-align: start;
|
|
53
47
|
}
|
|
54
48
|
`;
|
|
55
49
|
|
|
56
|
-
const StyledPlus = styled(Plus)`
|
|
57
|
-
height: 24px;
|
|
58
|
-
width: 24px;
|
|
59
|
-
`;
|
|
60
|
-
|
|
61
50
|
interface Props {
|
|
62
51
|
showTree: boolean;
|
|
63
52
|
type: TreeStructureType;
|
|
64
53
|
label?: string;
|
|
65
54
|
focusedFolder?: FolderType;
|
|
66
55
|
selectedFolder?: FolderType;
|
|
67
|
-
setSelectedFolder: (folder
|
|
56
|
+
setSelectedFolder: (folder: FolderType) => void;
|
|
68
57
|
onToggleTree: (open: boolean) => void;
|
|
69
58
|
flattenedFolders: FolderType[];
|
|
70
59
|
onOpenFolder: (id: string) => void;
|
|
71
60
|
onCloseFolder: (id: string) => void;
|
|
72
|
-
setFocusedFolder: (folder
|
|
73
|
-
onNewFolder?: (name: string, parentId: string) => Promise<IFolder>;
|
|
74
|
-
maxLevel: number;
|
|
75
|
-
setNewFolderParentId: (id?: string) => void;
|
|
61
|
+
setFocusedFolder: (folder: FolderType) => void;
|
|
76
62
|
}
|
|
77
63
|
|
|
78
64
|
const ComboboxButton = forwardRef<HTMLButtonElement, Props>(
|
|
@@ -89,18 +75,14 @@ const ComboboxButton = forwardRef<HTMLButtonElement, Props>(
|
|
|
89
75
|
setFocusedFolder,
|
|
90
76
|
onOpenFolder,
|
|
91
77
|
onCloseFolder,
|
|
92
|
-
onNewFolder,
|
|
93
|
-
maxLevel,
|
|
94
|
-
setNewFolderParentId,
|
|
95
78
|
},
|
|
96
79
|
ref,
|
|
97
80
|
) => {
|
|
98
|
-
const { t } = useTranslation();
|
|
99
81
|
const innerRef = useForwardedRef(ref);
|
|
100
82
|
|
|
101
83
|
const onKeyDown = (e: KeyboardEvent<HTMLButtonElement>) => {
|
|
102
84
|
if (e.key === 'Enter') {
|
|
103
|
-
if (showTree) {
|
|
85
|
+
if (showTree && focusedFolder) {
|
|
104
86
|
setSelectedFolder(focusedFolder);
|
|
105
87
|
}
|
|
106
88
|
return;
|
|
@@ -118,7 +100,6 @@ const ComboboxButton = forwardRef<HTMLButtonElement, Props>(
|
|
|
118
100
|
}
|
|
119
101
|
};
|
|
120
102
|
|
|
121
|
-
const canAddFolder = selectedFolder && selectedFolder?.breadcrumbs.length < (maxLevel || 1);
|
|
122
103
|
return (
|
|
123
104
|
<StyledRow isOpen={showTree}>
|
|
124
105
|
<StyledSelectedFolder
|
|
@@ -137,35 +118,11 @@ const ComboboxButton = forwardRef<HTMLButtonElement, Props>(
|
|
|
137
118
|
shape="sharp"
|
|
138
119
|
onKeyDown={onKeyDown}
|
|
139
120
|
onClick={() => {
|
|
121
|
+
innerRef.current?.focus();
|
|
140
122
|
onToggleTree(!showTree);
|
|
141
123
|
}}>
|
|
142
124
|
{selectedFolder?.name}
|
|
143
125
|
</StyledSelectedFolder>
|
|
144
|
-
{onNewFolder && showTree && (
|
|
145
|
-
<Tooltip
|
|
146
|
-
tooltip={
|
|
147
|
-
canAddFolder
|
|
148
|
-
? t('myNdla.newFolderUnder', {
|
|
149
|
-
folderName: selectedFolder?.name,
|
|
150
|
-
})
|
|
151
|
-
: t('treeStructure.maxFoldersAlreadyAdded')
|
|
152
|
-
}>
|
|
153
|
-
<StyledAddFolderButton
|
|
154
|
-
variant="outline"
|
|
155
|
-
shape="pill"
|
|
156
|
-
disabled={!canAddFolder}
|
|
157
|
-
aria-label={
|
|
158
|
-
canAddFolder
|
|
159
|
-
? t('myNdla.newFolderUnder', {
|
|
160
|
-
folderName: selectedFolder?.name,
|
|
161
|
-
})
|
|
162
|
-
: t('treeStructure.maxFoldersAlreadyAdded')
|
|
163
|
-
}
|
|
164
|
-
onClick={() => setNewFolderParentId(focusedFolder?.id)}>
|
|
165
|
-
<StyledPlus /> {t('myNdla.newFolder')}
|
|
166
|
-
</StyledAddFolderButton>
|
|
167
|
-
</Tooltip>
|
|
168
|
-
)}
|
|
169
126
|
<IconButton
|
|
170
127
|
aria-hidden
|
|
171
128
|
aria-label=""
|
|
@@ -174,9 +131,7 @@ const ComboboxButton = forwardRef<HTMLButtonElement, Props>(
|
|
|
174
131
|
colorTheme="greyLighter"
|
|
175
132
|
size="small"
|
|
176
133
|
onClick={() => {
|
|
177
|
-
|
|
178
|
-
innerRef.current?.focus();
|
|
179
|
-
}
|
|
134
|
+
innerRef.current?.focus();
|
|
180
135
|
onToggleTree(!showTree);
|
|
181
136
|
}}>
|
|
182
137
|
{showTree ? <ChevronUp /> : <ChevronDown />}
|
|
@@ -37,6 +37,9 @@ const OpenButton = styled.span<{ isOpen: boolean }>`
|
|
|
37
37
|
`;
|
|
38
38
|
|
|
39
39
|
const StyledName = styled.span`
|
|
40
|
+
white-space: nowrap;
|
|
41
|
+
overflow: hidden;
|
|
42
|
+
text-overflow: ellipsis;
|
|
40
43
|
grid-column-start: 2;
|
|
41
44
|
text-align: left;
|
|
42
45
|
`;
|
|
@@ -63,7 +66,6 @@ const FolderName = styled(Button, { shouldForwardProp })<FolderNameProps>`
|
|
|
63
66
|
color: ${({ isCreatingFolder, focused }) =>
|
|
64
67
|
isCreatingFolder && focused ? colors.brand.primary : colors.text.primary};
|
|
65
68
|
transition: ${animations.durations.superFast};
|
|
66
|
-
line-height: 1;
|
|
67
69
|
word-break: break-word;
|
|
68
70
|
|
|
69
71
|
&:hover {
|
|
@@ -93,7 +95,6 @@ const FolderNameLink = styled(SafeLink, { shouldForwardProp })<FolderNameProps>`
|
|
|
93
95
|
font-weight: ${({ selected }) => selected && fonts.weight.semibold};
|
|
94
96
|
font-size: ${fonts.sizes('16px')};
|
|
95
97
|
transition: ${animations.durations.superFast};
|
|
96
|
-
line-height: 1;
|
|
97
98
|
word-break: break-word;
|
|
98
99
|
&:hover,
|
|
99
100
|
&:focus {
|
|
@@ -116,7 +117,6 @@ const FolderItem = ({
|
|
|
116
117
|
selectedFolder,
|
|
117
118
|
onCloseFolder,
|
|
118
119
|
onOpenFolder,
|
|
119
|
-
onSelectFolder,
|
|
120
120
|
setFocusedFolder,
|
|
121
121
|
setSelectedFolder,
|
|
122
122
|
targetResource,
|
|
@@ -142,7 +142,6 @@ const FolderItem = ({
|
|
|
142
142
|
if (selected) {
|
|
143
143
|
closeTree();
|
|
144
144
|
}
|
|
145
|
-
onSelectFolder?.(id);
|
|
146
145
|
}
|
|
147
146
|
};
|
|
148
147
|
|
|
@@ -230,7 +229,7 @@ const FolderItem = ({
|
|
|
230
229
|
selected={selected}
|
|
231
230
|
disabled={loading}
|
|
232
231
|
onFocus={(e) => {
|
|
233
|
-
setFocusedFolder(focusedFolder || folder
|
|
232
|
+
setFocusedFolder(focusedFolder || folder);
|
|
234
233
|
}}
|
|
235
234
|
onClick={handleClickFolder}
|
|
236
235
|
isCreatingFolder={isCreatingFolder}>
|
|
@@ -241,7 +240,7 @@ const FolderItem = ({
|
|
|
241
240
|
isOpen={isOpen}
|
|
242
241
|
onClick={(e) => {
|
|
243
242
|
e.stopPropagation();
|
|
244
|
-
setFocusedFolder(folder
|
|
243
|
+
setFocusedFolder(folder);
|
|
245
244
|
if (isOpen) {
|
|
246
245
|
onCloseFolder(id);
|
|
247
246
|
} else {
|
|
@@ -10,8 +10,7 @@ import React, { ReactNode } from 'react';
|
|
|
10
10
|
import styled from '@emotion/styled';
|
|
11
11
|
import { animations } from '@ndla/core';
|
|
12
12
|
import FolderItem from './FolderItem';
|
|
13
|
-
import
|
|
14
|
-
import { CommonFolderItemsProps, FolderType, TreeStructureType } from './types';
|
|
13
|
+
import { CommonFolderItemsProps, FolderType, NewFolderInputFunc, OnCreatedFunc, TreeStructureType } from './types';
|
|
15
14
|
import NavigationLink from './NavigationLink';
|
|
16
15
|
import { treestructureId } from './helperFunctions';
|
|
17
16
|
|
|
@@ -42,10 +41,11 @@ export interface FolderItemsProps extends CommonFolderItemsProps {
|
|
|
42
41
|
folders: FolderType[];
|
|
43
42
|
newFolderParentId: string | undefined;
|
|
44
43
|
onCancelNewFolder: () => void;
|
|
45
|
-
onSaveNewFolder: (name: string, parentId: string) => void;
|
|
46
44
|
openFolders: string[];
|
|
47
45
|
parentFolder?: FolderType;
|
|
48
46
|
children?: ReactNode;
|
|
47
|
+
onCreate: OnCreatedFunc;
|
|
48
|
+
newFolderInput?: NewFolderInputFunc;
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
const FolderItems = ({
|
|
@@ -54,11 +54,12 @@ const FolderItems = ({
|
|
|
54
54
|
loading,
|
|
55
55
|
newFolderParentId,
|
|
56
56
|
onCancelNewFolder,
|
|
57
|
-
onSaveNewFolder,
|
|
58
57
|
openFolders,
|
|
59
58
|
type,
|
|
60
59
|
parentFolder,
|
|
61
60
|
children,
|
|
61
|
+
onCreate,
|
|
62
|
+
newFolderInput,
|
|
62
63
|
...rest
|
|
63
64
|
}: FolderItemsProps) => (
|
|
64
65
|
<StyledUL
|
|
@@ -101,20 +102,12 @@ const FolderItems = ({
|
|
|
101
102
|
type={type}
|
|
102
103
|
newFolderParentId={newFolderParentId}
|
|
103
104
|
onCancelNewFolder={onCancelNewFolder}
|
|
104
|
-
onSaveNewFolder={onSaveNewFolder}
|
|
105
105
|
openFolders={openFolders}
|
|
106
|
+
newFolderInput={newFolderInput}
|
|
107
|
+
onCreate={onCreate}
|
|
106
108
|
{...rest}>
|
|
107
109
|
{newFolderParentId === id && (
|
|
108
|
-
<li role="none">
|
|
109
|
-
<FolderNameInput
|
|
110
|
-
loading={loading}
|
|
111
|
-
level={level}
|
|
112
|
-
onCancelNewFolder={onCancelNewFolder}
|
|
113
|
-
onSaveNewFolder={onSaveNewFolder}
|
|
114
|
-
parentId={newFolderParentId}
|
|
115
|
-
type={type}
|
|
116
|
-
/>
|
|
117
|
-
</li>
|
|
110
|
+
<li role="none">{newFolderInput?.({ parentId: id, onClose: onCancelNewFolder, onCreate })}</li>
|
|
118
111
|
)}
|
|
119
112
|
</FolderItems>
|
|
120
113
|
)}
|