@ndla/ui 26.0.0 → 27.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.
- package/es/Breadcrumb/Breadcrumb.js +3 -4
- package/es/MyNdla/Resource/Folder.js +32 -14
- package/es/Resource/BlockResource.js +43 -61
- package/es/Resource/ListResource.js +44 -23
- package/es/Resource/resourceComponents.js +64 -38
- package/es/TreeStructure/ComboboxButton.js +162 -0
- package/es/TreeStructure/FolderItem.js +98 -78
- package/es/TreeStructure/FolderItems.js +25 -14
- package/es/TreeStructure/FolderNameInput.js +40 -33
- package/es/TreeStructure/NavigationLink.js +18 -10
- package/es/TreeStructure/TreeStructure.js +92 -165
- package/es/TreeStructure/arrowNavigation.js +3 -3
- package/es/TreeStructure/helperFunctions.js +3 -0
- package/es/locale/messages-en.js +8 -2
- package/es/locale/messages-nb.js +8 -2
- package/es/locale/messages-nn.js +8 -2
- package/es/locale/messages-se.js +8 -2
- package/es/locale/messages-sma.js +8 -2
- package/lib/Breadcrumb/Breadcrumb.js +3 -5
- package/lib/MyNdla/Resource/Folder.d.ts +2 -1
- package/lib/MyNdla/Resource/Folder.js +37 -14
- package/lib/Resource/BlockResource.d.ts +2 -1
- package/lib/Resource/BlockResource.js +48 -61
- package/lib/Resource/ListResource.d.ts +2 -1
- package/lib/Resource/ListResource.js +49 -23
- package/lib/Resource/resourceComponents.d.ts +6 -1
- package/lib/Resource/resourceComponents.js +64 -37
- package/lib/TreeStructure/ComboboxButton.d.ts +28 -0
- package/lib/TreeStructure/ComboboxButton.js +176 -0
- package/lib/TreeStructure/FolderItem.d.ts +1 -1
- package/lib/TreeStructure/FolderItem.js +99 -77
- package/lib/TreeStructure/FolderItems.d.ts +4 -2
- package/lib/TreeStructure/FolderItems.js +26 -14
- package/lib/TreeStructure/FolderNameInput.d.ts +3 -1
- package/lib/TreeStructure/FolderNameInput.js +41 -32
- package/lib/TreeStructure/NavigationLink.d.ts +1 -1
- package/lib/TreeStructure/NavigationLink.js +18 -10
- package/lib/TreeStructure/TreeStructure.d.ts +2 -2
- package/lib/TreeStructure/TreeStructure.js +92 -165
- package/lib/TreeStructure/arrowNavigation.d.ts +2 -1
- package/lib/TreeStructure/arrowNavigation.js +3 -3
- package/lib/TreeStructure/helperFunctions.d.ts +2 -1
- package/lib/TreeStructure/helperFunctions.js +8 -2
- package/lib/TreeStructure/types.d.ts +6 -7
- package/lib/locale/messages-en.d.ts +6 -0
- package/lib/locale/messages-en.js +8 -2
- package/lib/locale/messages-nb.d.ts +6 -0
- package/lib/locale/messages-nb.js +8 -2
- package/lib/locale/messages-nn.d.ts +6 -0
- package/lib/locale/messages-nn.js +8 -2
- package/lib/locale/messages-se.d.ts +6 -0
- package/lib/locale/messages-se.js +8 -2
- package/lib/locale/messages-sma.d.ts +6 -0
- package/lib/locale/messages-sma.js +8 -2
- package/package.json +11 -11
- package/src/Breadcrumb/Breadcrumb.tsx +1 -2
- package/src/MyNdla/Resource/Folder.tsx +21 -5
- package/src/Resource/BlockResource.tsx +43 -33
- package/src/Resource/ListResource.tsx +37 -29
- package/src/Resource/resourceComponents.tsx +60 -26
- package/src/TreeStructure/ComboboxButton.tsx +189 -0
- package/src/TreeStructure/FolderItem.tsx +89 -70
- package/src/TreeStructure/FolderItems.tsx +36 -16
- package/src/TreeStructure/FolderNameInput.tsx +43 -18
- package/src/TreeStructure/NavigationLink.tsx +17 -10
- package/src/TreeStructure/TreeStructure.tsx +63 -139
- package/src/TreeStructure/arrowNavigation.ts +7 -6
- package/src/TreeStructure/helperFunctions.ts +5 -1
- package/src/TreeStructure/types.ts +6 -7
- package/src/locale/messages-en.ts +7 -0
- package/src/locale/messages-nb.ts +6 -0
- package/src/locale/messages-nn.ts +6 -0
- package/src/locale/messages-se.ts +7 -0
- package/src/locale/messages-sma.ts +7 -0
|
@@ -7,19 +7,15 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import React, { useEffect, useState, useMemo, useRef } from 'react';
|
|
10
|
-
import { ButtonV2 as Button, IconButtonDualStates } from '@ndla/button';
|
|
11
|
-
import { Plus } from '@ndla/icons/action';
|
|
12
|
-
import { ChevronDown, ChevronUp } from '@ndla/icons/common';
|
|
13
|
-
import Tooltip from '@ndla/tooltip';
|
|
14
|
-
import { useTranslation } from 'react-i18next';
|
|
15
10
|
import styled from '@emotion/styled';
|
|
16
11
|
import { colors, fonts, misc, spacing } from '@ndla/core';
|
|
17
12
|
import { css } from '@emotion/core';
|
|
18
13
|
import { uniq } from 'lodash';
|
|
19
14
|
import { IFolder } from '@ndla/types-learningpath-api';
|
|
20
15
|
import FolderItems from './FolderItems';
|
|
21
|
-
import { flattenFolders } from './helperFunctions';
|
|
16
|
+
import { flattenFolders, treestructureId } from './helperFunctions';
|
|
22
17
|
import { CommonTreeStructureProps, FolderType, TreeStructureType } from './types';
|
|
18
|
+
import ComboboxButton from './ComboboxButton';
|
|
23
19
|
|
|
24
20
|
export const MAX_LEVEL_FOR_FOLDERS = 4;
|
|
25
21
|
|
|
@@ -27,17 +23,6 @@ const StyledLabel = styled.label`
|
|
|
27
23
|
font-weight: ${fonts.weight.semibold};
|
|
28
24
|
`;
|
|
29
25
|
|
|
30
|
-
interface StyledRowProps {
|
|
31
|
-
isOpen: boolean;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
const StyledRow = styled.div<StyledRowProps>`
|
|
35
|
-
display: flex;
|
|
36
|
-
justify-content: space-between;
|
|
37
|
-
padding: ${spacing.xxsmall};
|
|
38
|
-
border-bottom: ${({ isOpen }) => isOpen && `1px solid ${colors.brand.tertiary}`};
|
|
39
|
-
`;
|
|
40
|
-
|
|
41
26
|
const StyledTreeStructure = styled.div`
|
|
42
27
|
flex: 1;
|
|
43
28
|
display: flex;
|
|
@@ -48,7 +33,7 @@ const TreeStructureWrapper = styled.div<{ type: TreeStructureType }>`
|
|
|
48
33
|
display: flex;
|
|
49
34
|
flex-direction: column;
|
|
50
35
|
${({ type }) =>
|
|
51
|
-
|
|
36
|
+
type === 'picker' &&
|
|
52
37
|
css`
|
|
53
38
|
overflow: hidden;
|
|
54
39
|
border: 1px solid ${colors.brand.neutral7};
|
|
@@ -60,12 +45,14 @@ const TreeStructureWrapper = styled.div<{ type: TreeStructureType }>`
|
|
|
60
45
|
border-color: ${colors.brand.tertiary};
|
|
61
46
|
}
|
|
62
47
|
`;
|
|
48
|
+
|
|
63
49
|
interface ScrollableDivProps {
|
|
64
50
|
type: TreeStructureType;
|
|
65
51
|
}
|
|
52
|
+
|
|
66
53
|
const ScrollableDiv = styled.div<ScrollableDivProps>`
|
|
67
54
|
${({ type }) =>
|
|
68
|
-
|
|
55
|
+
type === 'picker' &&
|
|
69
56
|
css`
|
|
70
57
|
overflow: overlay;
|
|
71
58
|
::-webkit-scrollbar {
|
|
@@ -81,34 +68,11 @@ const ScrollableDiv = styled.div<ScrollableDivProps>`
|
|
|
81
68
|
`}
|
|
82
69
|
`;
|
|
83
70
|
|
|
84
|
-
const StyledSelectedFolder = styled(Button)`
|
|
85
|
-
flex: 1;
|
|
86
|
-
justify-content: flex-start;
|
|
87
|
-
:hover,
|
|
88
|
-
:focus {
|
|
89
|
-
background: none;
|
|
90
|
-
box-shadow: none;
|
|
91
|
-
border-color: transparent;
|
|
92
|
-
}
|
|
93
|
-
`;
|
|
94
|
-
|
|
95
|
-
const StyledAddFolderButton = styled(Button)`
|
|
96
|
-
&,
|
|
97
|
-
&:disabled {
|
|
98
|
-
border-color: transparent;
|
|
99
|
-
}
|
|
100
|
-
`;
|
|
101
|
-
|
|
102
|
-
const StyledPlus = styled(Plus)`
|
|
103
|
-
height: 24px;
|
|
104
|
-
width: 24px;
|
|
105
|
-
`;
|
|
106
|
-
|
|
107
71
|
export interface TreeStructureProps extends CommonTreeStructureProps {
|
|
108
72
|
defaultOpenFolders?: string[];
|
|
109
73
|
folders: FolderType[];
|
|
110
74
|
label?: string;
|
|
111
|
-
|
|
75
|
+
maxLevel?: number;
|
|
112
76
|
onNewFolder?: (name: string, parentId: string) => Promise<IFolder>;
|
|
113
77
|
}
|
|
114
78
|
|
|
@@ -117,42 +81,24 @@ const TreeStructure = ({
|
|
|
117
81
|
folders,
|
|
118
82
|
label,
|
|
119
83
|
loading,
|
|
120
|
-
|
|
84
|
+
maxLevel = MAX_LEVEL_FOR_FOLDERS,
|
|
121
85
|
onNewFolder,
|
|
122
86
|
onSelectFolder,
|
|
123
|
-
openOnFolderClick,
|
|
124
87
|
targetResource,
|
|
125
|
-
type
|
|
88
|
+
type,
|
|
126
89
|
}: TreeStructureProps) => {
|
|
127
|
-
const
|
|
128
|
-
|
|
129
|
-
const ref = useRef<HTMLDivElement>(null);
|
|
90
|
+
const ref = useRef<HTMLButtonElement>(null);
|
|
130
91
|
|
|
131
92
|
const defaultSelectedFolderId = defaultOpenFolders && defaultOpenFolders[defaultOpenFolders.length - 1];
|
|
132
93
|
|
|
133
94
|
const [openFolders, setOpenFolders] = useState<string[]>(defaultOpenFolders || []);
|
|
134
95
|
|
|
135
96
|
const [newFolderParentId, setNewFolderParentId] = useState<string | undefined>();
|
|
136
|
-
const [
|
|
97
|
+
const [focusedFolder, setFocusedFolder] = useState<FolderType | undefined>();
|
|
137
98
|
const [selectedFolder, setSelectedFolder] = useState<FolderType | undefined>();
|
|
138
|
-
const [showTree, setShowTree] = useState(type
|
|
99
|
+
const [showTree, setShowTree] = useState(type === 'navigation');
|
|
139
100
|
|
|
140
101
|
const flattenedFolders = useMemo(() => flattenFolders(folders, openFolders), [folders, openFolders]);
|
|
141
|
-
const visibleFolderIds = flattenedFolders.map((folder) => folder.id);
|
|
142
|
-
|
|
143
|
-
useEffect(() => {
|
|
144
|
-
const handleClickOutside = (e: MouseEvent) => {
|
|
145
|
-
if (e.target instanceof Element && ref.current && !ref.current.contains(e.target)) {
|
|
146
|
-
setShowTree(false);
|
|
147
|
-
}
|
|
148
|
-
};
|
|
149
|
-
if (type === 'picker') {
|
|
150
|
-
document.addEventListener('mousedown', handleClickOutside);
|
|
151
|
-
return () => {
|
|
152
|
-
document.removeEventListener('mousedown', handleClickOutside);
|
|
153
|
-
};
|
|
154
|
-
}
|
|
155
|
-
}, [ref, type]);
|
|
156
102
|
|
|
157
103
|
useEffect(() => {
|
|
158
104
|
if (defaultOpenFolders) {
|
|
@@ -165,25 +111,25 @@ const TreeStructure = ({
|
|
|
165
111
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
166
112
|
}, [defaultOpenFolders]);
|
|
167
113
|
|
|
168
|
-
useEffect(() => {
|
|
169
|
-
setNewFolderParentId(undefined);
|
|
170
|
-
}, [selectedFolder]);
|
|
171
|
-
|
|
172
114
|
useEffect(() => {
|
|
173
115
|
if (defaultSelectedFolderId !== undefined) {
|
|
174
116
|
const selected = flattenFolders(folders).find((folder) => folder.id === defaultSelectedFolderId);
|
|
175
117
|
if (selected) {
|
|
176
118
|
setSelectedFolder(selected);
|
|
119
|
+
if (type === 'picker') {
|
|
120
|
+
setFocusedFolder(selected);
|
|
121
|
+
}
|
|
177
122
|
}
|
|
178
123
|
}
|
|
179
124
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
180
125
|
}, [defaultSelectedFolderId]);
|
|
181
126
|
|
|
182
|
-
|
|
183
|
-
|
|
127
|
+
const onToggleTree = (open: boolean) => {
|
|
128
|
+
setShowTree(open);
|
|
129
|
+
if (!open) {
|
|
184
130
|
setNewFolderParentId(undefined);
|
|
185
131
|
}
|
|
186
|
-
}
|
|
132
|
+
};
|
|
187
133
|
|
|
188
134
|
const onCloseFolder = (id: string) => {
|
|
189
135
|
const closedFolder = flattenedFolders.find((folder) => folder.id === id);
|
|
@@ -191,11 +137,7 @@ const TreeStructure = ({
|
|
|
191
137
|
if (closedFolder) {
|
|
192
138
|
const subFolders = closedFolder.subfolders && flattenFolders(closedFolder.subfolders);
|
|
193
139
|
if (subFolders.some((folder) => folder.id === selectedFolder?.id)) {
|
|
194
|
-
|
|
195
|
-
setSelectedFolder(closedFolder);
|
|
196
|
-
onSelectFolder(closedFolder.id);
|
|
197
|
-
}
|
|
198
|
-
setFocusedId(closedFolder.id);
|
|
140
|
+
setFocusedFolder(closedFolder);
|
|
199
141
|
}
|
|
200
142
|
}
|
|
201
143
|
setOpenFolders(openFolders.filter((folderId) => folderId !== id));
|
|
@@ -208,86 +150,68 @@ const TreeStructure = ({
|
|
|
208
150
|
const onSaveNewFolder = (name: string, parentId: string) => {
|
|
209
151
|
onNewFolder?.(name, parentId).then((newFolder) => {
|
|
210
152
|
if (newFolder) {
|
|
211
|
-
setNewFolderParentId?.(undefined);
|
|
212
153
|
setSelectedFolder(newFolder);
|
|
213
154
|
onSelectFolder?.(newFolder.id);
|
|
214
|
-
|
|
155
|
+
setFocusedFolder(newFolder);
|
|
215
156
|
setOpenFolders(uniq(openFolders.concat(parentId)));
|
|
157
|
+
setNewFolderParentId?.(undefined);
|
|
158
|
+
ref.current?.focus();
|
|
216
159
|
}
|
|
217
160
|
});
|
|
218
161
|
};
|
|
219
162
|
|
|
220
163
|
const onCancelNewFolder = () => {
|
|
221
164
|
setNewFolderParentId?.(undefined);
|
|
165
|
+
ref.current?.focus();
|
|
222
166
|
};
|
|
223
167
|
|
|
224
|
-
const
|
|
168
|
+
const setFolderFocus = (folder: FolderType, focus?: boolean) => {
|
|
169
|
+
setFocusedFolder(folder);
|
|
170
|
+
|
|
171
|
+
if (focus) {
|
|
172
|
+
ref.current?.focus();
|
|
173
|
+
}
|
|
174
|
+
};
|
|
225
175
|
|
|
226
176
|
return (
|
|
227
|
-
<StyledTreeStructure
|
|
228
|
-
{label && <StyledLabel>{label}</StyledLabel>}
|
|
229
|
-
<TreeStructureWrapper
|
|
177
|
+
<StyledTreeStructure>
|
|
178
|
+
{label && <StyledLabel id={treestructureId(type, 'label')}>{label}</StyledLabel>}
|
|
179
|
+
<TreeStructureWrapper
|
|
180
|
+
aria-label={label}
|
|
181
|
+
type={type}
|
|
182
|
+
onBlur={(e) => {
|
|
183
|
+
if (type === 'picker' && !e.currentTarget.contains(e.relatedTarget)) {
|
|
184
|
+
onToggleTree(false);
|
|
185
|
+
}
|
|
186
|
+
}}>
|
|
230
187
|
{type === 'picker' && (
|
|
231
|
-
<
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
{
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
})
|
|
249
|
-
: t('treeStructure.maxFoldersAlreadyAdded')
|
|
250
|
-
}>
|
|
251
|
-
<StyledAddFolderButton
|
|
252
|
-
variant="outline"
|
|
253
|
-
shape="pill"
|
|
254
|
-
disabled={!canAddFolder}
|
|
255
|
-
aria-label={
|
|
256
|
-
canAddFolder
|
|
257
|
-
? t('myNdla.newFolderUnder', {
|
|
258
|
-
folderName: selectedFolder?.name,
|
|
259
|
-
})
|
|
260
|
-
: t('treeStructure.maxFoldersAlreadyAdded')
|
|
261
|
-
}
|
|
262
|
-
onClick={() => setNewFolderParentId(selectedFolder?.id)}>
|
|
263
|
-
<StyledPlus /> {t('myNdla.newFolder')}
|
|
264
|
-
</StyledAddFolderButton>
|
|
265
|
-
</Tooltip>
|
|
266
|
-
)}
|
|
267
|
-
<IconButtonDualStates
|
|
268
|
-
ariaLabelActive={t('treeStructure.hideFolders')}
|
|
269
|
-
ariaLabelInActive={t('treeStructure.showFolders')}
|
|
270
|
-
active={showTree}
|
|
271
|
-
variant="ghost"
|
|
272
|
-
colorTheme="greyLighter"
|
|
273
|
-
inactiveIcon={<ChevronDown />}
|
|
274
|
-
activeIcon={<ChevronUp />}
|
|
275
|
-
size="small"
|
|
276
|
-
onClick={() => {
|
|
277
|
-
setShowTree(!showTree);
|
|
278
|
-
}}
|
|
279
|
-
/>
|
|
280
|
-
</StyledRow>
|
|
188
|
+
<ComboboxButton
|
|
189
|
+
ref={ref}
|
|
190
|
+
showTree={showTree}
|
|
191
|
+
type={type}
|
|
192
|
+
label={label}
|
|
193
|
+
focusedFolder={focusedFolder}
|
|
194
|
+
selectedFolder={selectedFolder}
|
|
195
|
+
setSelectedFolder={setSelectedFolder}
|
|
196
|
+
setFocusedFolder={setFocusedFolder}
|
|
197
|
+
onToggleTree={onToggleTree}
|
|
198
|
+
flattenedFolders={flattenedFolders}
|
|
199
|
+
onCloseFolder={onCloseFolder}
|
|
200
|
+
onOpenFolder={onOpenFolder}
|
|
201
|
+
onNewFolder={onNewFolder}
|
|
202
|
+
maxLevel={maxLevel}
|
|
203
|
+
setNewFolderParentId={setNewFolderParentId}
|
|
204
|
+
/>
|
|
281
205
|
)}
|
|
282
206
|
{showTree && (
|
|
283
207
|
<ScrollableDiv type={type}>
|
|
284
208
|
<FolderItems
|
|
285
|
-
|
|
209
|
+
focusedFolder={focusedFolder}
|
|
286
210
|
folders={folders}
|
|
287
211
|
level={0}
|
|
288
212
|
loading={loading}
|
|
289
213
|
selectedFolder={selectedFolder}
|
|
290
|
-
maxLevel={
|
|
214
|
+
maxLevel={maxLevel}
|
|
291
215
|
newFolderParentId={newFolderParentId}
|
|
292
216
|
onCancelNewFolder={onCancelNewFolder}
|
|
293
217
|
onCloseFolder={onCloseFolder}
|
|
@@ -295,12 +219,12 @@ const TreeStructure = ({
|
|
|
295
219
|
onSaveNewFolder={onSaveNewFolder}
|
|
296
220
|
onSelectFolder={onSelectFolder}
|
|
297
221
|
openFolders={openFolders}
|
|
298
|
-
|
|
299
|
-
setFocusedId={setFocusedId}
|
|
222
|
+
setFocusedFolder={setFolderFocus}
|
|
300
223
|
setSelectedFolder={setSelectedFolder}
|
|
301
224
|
targetResource={targetResource}
|
|
302
|
-
visibleFolders={
|
|
225
|
+
visibleFolders={flattenedFolders}
|
|
303
226
|
type={type}
|
|
227
|
+
closeTree={() => onToggleTree(false)}
|
|
304
228
|
/>
|
|
305
229
|
</ScrollableDiv>
|
|
306
230
|
)}
|
|
@@ -7,27 +7,28 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import { KeyboardEvent } from 'react';
|
|
10
|
+
import { FolderType } from './types';
|
|
10
11
|
|
|
11
12
|
const navigateVertical = (
|
|
12
|
-
visibleFolders:
|
|
13
|
+
visibleFolders: FolderType[],
|
|
13
14
|
folderId: string,
|
|
14
|
-
setFocusedFolderId: (id:
|
|
15
|
+
setFocusedFolderId: (id: FolderType) => void,
|
|
15
16
|
direction: 1 | -1,
|
|
16
17
|
) => {
|
|
17
|
-
const currentIndex = visibleFolders.findIndex((
|
|
18
|
+
const currentIndex = visibleFolders.findIndex((folder) => folder.id === folderId);
|
|
18
19
|
const target = visibleFolders[currentIndex + direction];
|
|
19
20
|
if (target !== undefined) {
|
|
20
21
|
setFocusedFolderId(target);
|
|
21
22
|
}
|
|
22
23
|
};
|
|
23
24
|
|
|
24
|
-
const arrowKeys = ['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'];
|
|
25
|
+
const arrowKeys = ['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'Enter'];
|
|
25
26
|
|
|
26
27
|
export const arrowNavigation = (
|
|
27
28
|
e: KeyboardEvent<HTMLElement>,
|
|
28
29
|
id: string,
|
|
29
|
-
visibleFolders:
|
|
30
|
-
setFocusedFolderId: (id:
|
|
30
|
+
visibleFolders: FolderType[],
|
|
31
|
+
setFocusedFolderId: (id: FolderType) => void,
|
|
31
32
|
onOpen: (id: string) => void,
|
|
32
33
|
onClose: (id: string) => void,
|
|
33
34
|
) => {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { FolderType } from './types';
|
|
1
|
+
import { FolderType, TreeStructureType } from './types';
|
|
2
2
|
|
|
3
3
|
export const flattenFolders = (folders: FolderType[], openFolders?: string[]): FolderType[] => {
|
|
4
4
|
return folders.reduce((acc, { subfolders, id, ...rest }) => {
|
|
@@ -8,3 +8,7 @@ export const flattenFolders = (folders: FolderType[], openFolders?: string[]): F
|
|
|
8
8
|
return acc.concat({ subfolders, id, ...rest }, flattenFolders(subfolders, openFolders));
|
|
9
9
|
}, [] as FolderType[]);
|
|
10
10
|
};
|
|
11
|
+
|
|
12
|
+
export const treestructureId = (type: TreeStructureType, modifier: string) => {
|
|
13
|
+
return `${type}-treestructure-${modifier}`;
|
|
14
|
+
};
|
|
@@ -15,7 +15,7 @@ export interface FolderType extends IFolder {
|
|
|
15
15
|
isNavigation?: boolean;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
export type TreeStructureType = '
|
|
18
|
+
export type TreeStructureType = 'navigation' | 'picker';
|
|
19
19
|
|
|
20
20
|
export interface TreeStructureMenuProps extends Omit<MenuItemProps, 'onClick'> {
|
|
21
21
|
onClick: (e: MouseEvent<HTMLDivElement> | undefined, folder: FolderType) => void;
|
|
@@ -24,20 +24,19 @@ export interface TreeStructureMenuProps extends Omit<MenuItemProps, 'onClick'> {
|
|
|
24
24
|
export interface CommonTreeStructureProps {
|
|
25
25
|
loading?: boolean;
|
|
26
26
|
onSelectFolder?: (id: string) => void;
|
|
27
|
-
openOnFolderClick?: boolean;
|
|
28
27
|
targetResource?: IResource;
|
|
29
|
-
framed?: boolean;
|
|
30
28
|
type: TreeStructureType;
|
|
31
29
|
}
|
|
32
30
|
|
|
33
31
|
export interface CommonFolderItemsProps extends CommonTreeStructureProps {
|
|
34
|
-
|
|
32
|
+
focusedFolder?: FolderType;
|
|
35
33
|
level: number;
|
|
36
34
|
maxLevel: number;
|
|
37
35
|
selectedFolder?: FolderType;
|
|
38
36
|
onCloseFolder: (id: string) => void;
|
|
39
37
|
onOpenFolder: (id: string) => void;
|
|
40
|
-
|
|
41
|
-
setSelectedFolder: (
|
|
42
|
-
visibleFolders:
|
|
38
|
+
setFocusedFolder: (folder: FolderType, focus?: boolean) => void;
|
|
39
|
+
setSelectedFolder: (folder: FolderType) => void;
|
|
40
|
+
visibleFolders: FolderType[];
|
|
41
|
+
closeTree: () => void;
|
|
43
42
|
}
|
|
@@ -26,6 +26,7 @@ const messages = {
|
|
|
26
26
|
newFolder: {
|
|
27
27
|
placeholder: 'Add foldername',
|
|
28
28
|
defaultName: 'New folder',
|
|
29
|
+
folderName: 'Folder name',
|
|
29
30
|
},
|
|
30
31
|
},
|
|
31
32
|
tagSelector: {
|
|
@@ -857,6 +858,7 @@ const messages = {
|
|
|
857
858
|
},
|
|
858
859
|
cancel: 'Cancel',
|
|
859
860
|
close: 'Close',
|
|
861
|
+
loading: 'Loading',
|
|
860
862
|
title: 'Title',
|
|
861
863
|
save: 'Save',
|
|
862
864
|
image: {
|
|
@@ -994,11 +996,16 @@ const messages = {
|
|
|
994
996
|
edit: 'Edit folder',
|
|
995
997
|
missingName: 'Folder name required',
|
|
996
998
|
folderDeleted: '"{{folderName}}" deleted',
|
|
999
|
+
folderCreated: '"{{folderName}} created',
|
|
997
1000
|
},
|
|
1001
|
+
tagList: 'Tags',
|
|
998
1002
|
tags: '{{count}} tag',
|
|
999
1003
|
tags_plural: '{{count}} tags',
|
|
1004
|
+
moreTags: 'Show one more tag',
|
|
1005
|
+
moreTags_plural: 'Show {{count}} more tags',
|
|
1000
1006
|
confirmDeleteFolder:
|
|
1001
1007
|
'Are you sure you want to delete this folder? Subfolders of this folder will also be deleted. This action cannot be undone.',
|
|
1008
|
+
|
|
1002
1009
|
confirmDeleteTag: 'Are you sure you want to delete this tag? This process cannot be undone.',
|
|
1003
1010
|
myFolders: 'My folders',
|
|
1004
1011
|
myTags: 'My tags',
|
|
@@ -26,6 +26,7 @@ const messages = {
|
|
|
26
26
|
newFolder: {
|
|
27
27
|
placeholder: 'Skriv navn på mappe',
|
|
28
28
|
defaultName: 'Ny mappe',
|
|
29
|
+
folderName: 'Mappenavn',
|
|
29
30
|
},
|
|
30
31
|
},
|
|
31
32
|
tagSelector: {
|
|
@@ -854,6 +855,7 @@ const messages = {
|
|
|
854
855
|
close: 'Lukk meny',
|
|
855
856
|
},
|
|
856
857
|
close: 'Lukk',
|
|
858
|
+
loading: 'Laster',
|
|
857
859
|
title: 'Tittel',
|
|
858
860
|
cancel: 'Avbryt',
|
|
859
861
|
save: 'Lagre',
|
|
@@ -992,9 +994,13 @@ const messages = {
|
|
|
992
994
|
edit: 'Rediger mappe',
|
|
993
995
|
missingName: 'Skriv navn på mappe',
|
|
994
996
|
folderDeleted: '"{{folderName}}" er slettet',
|
|
997
|
+
folderCreated: '"{{folderName}}" er opprettet',
|
|
995
998
|
},
|
|
999
|
+
tagList: 'Emneknagger',
|
|
996
1000
|
tags: '{{count}} emneknagg',
|
|
997
1001
|
tags_plural: '{{count}} emneknagger',
|
|
1002
|
+
moreTags: 'Vis en emneknagg til',
|
|
1003
|
+
moreTags_plural: 'Vis {{count}} emneknagger til',
|
|
998
1004
|
confirmDeleteFolder:
|
|
999
1005
|
'Er du sikker på at du vil slette mappen? Dersom mappen har undermapper vil disse også slettes. Handlingen kan ikke endres.',
|
|
1000
1006
|
confirmDeleteTag: 'Er du sikker på at du vil slette emneknagg? Denne handlingen kan ikke endres.',
|
|
@@ -26,6 +26,7 @@ const messages = {
|
|
|
26
26
|
newFolder: {
|
|
27
27
|
placeholder: 'Skriv namn på mappe',
|
|
28
28
|
defaultName: 'Ny mappe',
|
|
29
|
+
folderName: 'Mappenavn',
|
|
29
30
|
},
|
|
30
31
|
},
|
|
31
32
|
tagSelector: {
|
|
@@ -856,6 +857,7 @@ const messages = {
|
|
|
856
857
|
},
|
|
857
858
|
cancel: 'Avbryt',
|
|
858
859
|
close: 'Lukk',
|
|
860
|
+
loading: 'Laster',
|
|
859
861
|
title: 'Tittel',
|
|
860
862
|
save: 'Lagre',
|
|
861
863
|
image: {
|
|
@@ -993,9 +995,13 @@ const messages = {
|
|
|
993
995
|
edit: 'Rediger mappe',
|
|
994
996
|
missingName: 'Skriv namn på mappe',
|
|
995
997
|
folderDeleted: '"{{folderName}}" er sletta',
|
|
998
|
+
folderCreated: '"{{folderName}}" er oppretta',
|
|
996
999
|
},
|
|
1000
|
+
tagList: 'Emneknaggar',
|
|
997
1001
|
tags: '{{count}} emneknagg',
|
|
998
1002
|
tags_plural: '{{count}} emneknaggar',
|
|
1003
|
+
moreTags: 'Vis ein emneknagg til',
|
|
1004
|
+
moreTags_plural: 'Vis {{count}} emneknaggar til',
|
|
999
1005
|
confirmDeleteFolder:
|
|
1000
1006
|
'Er du sikker på at du vil slette mappa? Dersom mappa har undermapper vil desse også slettast. Denne handlinga kan ikkje endrast.',
|
|
1001
1007
|
confirmDeleteTag: 'Er du sikker på at du vil slette tag? Denne handlinga kan ikkje endrast.',
|
|
@@ -26,6 +26,7 @@ const messages = {
|
|
|
26
26
|
newFolder: {
|
|
27
27
|
placeholder: 'Čále nama máhppii',
|
|
28
28
|
defaultName: 'Ođđa máhppa',
|
|
29
|
+
folderName: 'Mappenavn',
|
|
29
30
|
},
|
|
30
31
|
},
|
|
31
32
|
tagSelector: {
|
|
@@ -855,6 +856,7 @@ const messages = {
|
|
|
855
856
|
close: 'Govčča fálu',
|
|
856
857
|
},
|
|
857
858
|
close: 'Govčča',
|
|
859
|
+
loading: 'Laster',
|
|
858
860
|
title: 'Tihttel',
|
|
859
861
|
cancel: 'Botkke',
|
|
860
862
|
save: 'Vurke',
|
|
@@ -993,9 +995,13 @@ const messages = {
|
|
|
993
995
|
edit: 'Redigere',
|
|
994
996
|
missingName: 'Čále nama máhppii',
|
|
995
997
|
folderDeleted: '"{{folderName}}" lea sihkkojuvvon',
|
|
998
|
+
folderCreated: '"{{folderName}}" er oppretta',
|
|
996
999
|
},
|
|
1000
|
+
tagList: 'Emneknagger',
|
|
997
1001
|
tags: '{{count}} fáddágilkor',
|
|
998
1002
|
tags_plural: '{{count}} fáddágilkorat',
|
|
1003
|
+
moreTags: 'Vis ein emneknagg til',
|
|
1004
|
+
moreTags_plural: 'Vis {{count}} emneknaggar til',
|
|
999
1005
|
confirmDeleteFolder: 'Leat go áibbas sihkar ahte dáhtut sihkkut máhpa? Dan ii sáhte gáhtat.',
|
|
1000
1006
|
confirmDeleteTag: 'Leat go áibbas sihkar ahte dáhtut sihkkut fáddágilkora? Dan ii sáhte gáhtat.',
|
|
1001
1007
|
myFolders: 'Mu máhpat',
|
|
@@ -1012,6 +1018,7 @@ const messages = {
|
|
|
1012
1018
|
listView: 'Oppalašlistu',
|
|
1013
1019
|
detailView: 'Bienalaš oppalašlistu',
|
|
1014
1020
|
shortView: 'Oanehis listu',
|
|
1021
|
+
|
|
1015
1022
|
myPage: {
|
|
1016
1023
|
confirmDeleteAccount: 'Leat go áibbas sihkar ahte dáhtut sihkkut kontu?',
|
|
1017
1024
|
confirmDeleteAccountButton: 'Sihko kontu',
|
|
@@ -26,6 +26,7 @@ const messages = {
|
|
|
26
26
|
newFolder: {
|
|
27
27
|
placeholder: 'Skriv navn på mappe',
|
|
28
28
|
defaultName: 'Ny mappe',
|
|
29
|
+
folderName: 'Mappenavn',
|
|
29
30
|
},
|
|
30
31
|
},
|
|
31
32
|
tagSelector: {
|
|
@@ -855,6 +856,7 @@ const messages = {
|
|
|
855
856
|
close: 'Lukk meny',
|
|
856
857
|
},
|
|
857
858
|
close: 'Lukk',
|
|
859
|
+
loading: 'Laster',
|
|
858
860
|
title: 'Tittel',
|
|
859
861
|
cancel: 'Avbryt',
|
|
860
862
|
save: 'Lagre',
|
|
@@ -993,11 +995,16 @@ const messages = {
|
|
|
993
995
|
edit: 'Rediger mappe',
|
|
994
996
|
missingName: 'Skriv navn på mappe',
|
|
995
997
|
folderDeleted: '"{{folderName}}" er slettet',
|
|
998
|
+
folderCreated: '"{{folderName}}" er oppretta',
|
|
996
999
|
},
|
|
1000
|
+
tagList: 'Emneknagg',
|
|
997
1001
|
tags: '{{count}} emneknagg',
|
|
998
1002
|
tags_plural: '{{count}} emneknagger',
|
|
1003
|
+
moreTags: 'Vis ein emneknagg til',
|
|
1004
|
+
moreTags_plural: 'Vis {{count}} emneknaggar til',
|
|
999
1005
|
confirmDeleteFolder:
|
|
1000
1006
|
'Er du sikker på at du vil slette mappa? Dersom mappa har undermappar vil disse også slettes. Denne handlinga kan ikkje endrast.',
|
|
1007
|
+
|
|
1001
1008
|
confirmDeleteTag: 'Er du sikker på at du vil slette emneknagg? Denne handlingen kan ikke endres.',
|
|
1002
1009
|
myFolders: 'Mine mapper',
|
|
1003
1010
|
myTags: 'Mine emneknagger',
|