@ndla/ui 13.2.1 → 15.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/Article/Article.js +22 -3
- package/es/Article/ArticleFavoritesButton.js +38 -0
- package/es/Article/index.js +2 -1
- package/es/Breadcrumb/ActionBreadcrumb.js +57 -0
- package/es/Breadcrumb/index.js +1 -0
- package/es/Footer/FooterAuth.js +15 -22
- package/es/InfoBlock/InfoBlock.js +55 -0
- package/es/InfoBlock/index.js +1 -0
- package/es/LearningPaths/LearningPathMenu.js +3 -4
- package/es/Masthead/MastheadAuthModal.js +2 -2
- package/es/MyNdla/Navigation/VerticalNavigation.js +51 -0
- package/es/MyNdla/Navigation/index.js +2 -0
- package/es/MyNdla/Resource/Folder.js +86 -0
- package/{lib/MyNdla/ResourceDash/ResourcesView.d.ts → es/MyNdla/Resource/index.js} +2 -3
- package/es/MyNdla/index.js +3 -4
- package/es/Notion/ConceptNotion.js +2 -1
- package/es/Notion/FigureNotion.js +13 -9
- package/es/Notion/NotionVisualElement.js +3 -2
- package/es/Resource/BlockResource.js +73 -0
- package/es/Resource/ListResource.js +66 -0
- package/es/Resource/index.js +10 -0
- package/es/Resource/resourceComponents.js +97 -0
- package/es/ResourceGroup/ResourceGroup.js +7 -5
- package/es/ResourceGroup/ResourceItem.js +28 -30
- package/es/ResourceGroup/ResourceList.js +18 -6
- package/es/Search/ActiveFilters.js +6 -7
- package/es/Search/ContentTypeResult.js +6 -8
- package/es/SearchTypeResult/ActiveFilters.js +6 -10
- package/es/SearchTypeResult/SearchViewType.js +5 -5
- package/es/SnackBar/SnackBar.js +117 -0
- package/es/SnackBar/index.js +9 -0
- package/es/TagSelector/SuggestionInput.js +240 -0
- package/es/TagSelector/Suggestions.js +93 -0
- package/es/TagSelector/TagSelector.js +137 -0
- package/es/TagSelector/index.js +9 -0
- package/es/TopicIntroductionList/TopicIntroduction.js +2 -4
- package/es/TopicIntroductionList/TopicShortcutItem.js +1 -3
- package/es/TreeStructure/FolderItem.js +130 -0
- package/es/TreeStructure/FolderItems.js +123 -0
- package/es/TreeStructure/FolderNameInput.js +112 -0
- package/es/TreeStructure/TreeStructure.js +254 -0
- package/es/TreeStructure/TreeStructure.types.js +0 -0
- package/es/TreeStructure/TreeStructureWrapper.js +13 -0
- package/es/TreeStructure/helperFunctions.js +92 -0
- package/es/TreeStructure/index.js +9 -0
- package/es/TreeStructure/keyboardNavigation/keyboardNavigation.js +182 -0
- package/es/TreeStructure/keyboardNavigation/keyboardNavigation.types.js +0 -0
- package/es/User/AuthModal.js +15 -24
- package/es/User/UserInfo.js +70 -0
- package/es/User/apiTypes.js +0 -0
- package/es/User/index.js +2 -0
- package/es/User/parseUserObject.js +102 -0
- package/es/all.css +90 -0
- package/es/index.js +9 -3
- package/es/locale/messages-en.js +75 -8
- package/es/locale/messages-nb.js +74 -7
- package/es/locale/messages-nn.js +74 -7
- package/es/locale/messages-se.js +74 -7
- package/es/locale/messages-sma.js +74 -7
- package/lib/Article/Article.d.ts +3 -1
- package/lib/Article/Article.js +43 -23
- package/lib/Article/ArticleFavoritesButton.d.ts +15 -0
- package/lib/Article/ArticleFavoritesButton.js +56 -0
- package/lib/Article/index.d.ts +2 -1
- package/lib/Article/index.js +8 -0
- package/lib/Breadcrumb/ActionBreadcrumb.d.ts +16 -0
- package/lib/Breadcrumb/ActionBreadcrumb.js +72 -0
- package/lib/Breadcrumb/index.d.ts +1 -0
- package/lib/Breadcrumb/index.js +8 -0
- package/lib/Footer/FooterAuth.d.ts +1 -1
- package/lib/Footer/FooterAuth.js +17 -17
- package/lib/InfoBlock/InfoBlock.d.ts +8 -0
- package/lib/InfoBlock/InfoBlock.js +58 -0
- package/lib/InfoBlock/index.d.ts +1 -0
- package/lib/InfoBlock/index.js +13 -0
- package/lib/LearningPaths/LearningPathMenu.js +3 -4
- package/lib/Masthead/MastheadAuthModal.d.ts +3 -3
- package/lib/Masthead/MastheadAuthModal.js +3 -3
- package/lib/MyNdla/Navigation/VerticalNavigation.d.ts +10 -0
- package/lib/MyNdla/Navigation/VerticalNavigation.js +61 -0
- package/lib/MyNdla/Navigation/index.d.ts +2 -0
- package/lib/MyNdla/Navigation/index.js +15 -0
- package/lib/MyNdla/Resource/Folder.d.ts +20 -0
- package/lib/MyNdla/Resource/Folder.js +100 -0
- package/lib/MyNdla/Resource/index.d.ts +9 -0
- package/lib/MyNdla/Resource/index.js +15 -0
- package/lib/MyNdla/index.d.ts +3 -4
- package/lib/MyNdla/index.js +9 -11
- package/lib/Notion/ConceptNotion.js +2 -1
- package/lib/Notion/FigureNotion.d.ts +1 -1
- package/lib/Notion/FigureNotion.js +12 -8
- package/lib/Notion/NotionVisualElement.js +3 -2
- package/lib/Resource/BlockResource.d.ts +20 -0
- package/lib/Resource/BlockResource.js +84 -0
- package/lib/Resource/ListResource.d.ts +20 -0
- package/lib/Resource/ListResource.js +78 -0
- package/lib/Resource/index.d.ts +11 -0
- package/lib/Resource/index.js +29 -0
- package/lib/Resource/resourceComponents.d.ts +24 -0
- package/lib/Resource/resourceComponents.js +106 -0
- package/lib/ResourceGroup/ResourceGroup.d.ts +2 -1
- package/lib/ResourceGroup/ResourceGroup.js +7 -5
- package/lib/ResourceGroup/ResourceItem.d.ts +5 -1
- package/lib/ResourceGroup/ResourceItem.js +29 -30
- package/lib/ResourceGroup/ResourceList.d.ts +3 -1
- package/lib/ResourceGroup/ResourceList.js +18 -6
- package/lib/Search/ActiveFilters.js +6 -7
- package/lib/Search/ContentTypeResult.js +6 -8
- package/lib/SearchTypeResult/ActiveFilters.js +6 -10
- package/lib/SearchTypeResult/SearchViewType.js +5 -5
- package/lib/SnackBar/SnackBar.d.ts +23 -0
- package/lib/SnackBar/SnackBar.js +127 -0
- package/lib/SnackBar/index.d.ts +10 -0
- package/lib/SnackBar/index.js +15 -0
- package/lib/TagSelector/SuggestionInput.d.ts +19 -0
- package/lib/TagSelector/SuggestionInput.js +255 -0
- package/lib/TagSelector/Suggestions.d.ts +12 -0
- package/lib/TagSelector/Suggestions.js +96 -0
- package/lib/TagSelector/TagSelector.d.ts +16 -0
- package/lib/TagSelector/TagSelector.js +150 -0
- package/lib/TagSelector/index.d.ts +10 -0
- package/lib/TagSelector/index.js +19 -0
- package/lib/TopicIntroductionList/TopicIntroduction.js +2 -4
- package/lib/TopicIntroductionList/TopicShortcutItem.js +1 -3
- package/lib/TreeStructure/FolderItem.d.ts +27 -0
- package/lib/TreeStructure/FolderItem.js +140 -0
- package/lib/TreeStructure/FolderItems.d.ts +11 -0
- package/lib/TreeStructure/FolderItems.js +130 -0
- package/lib/TreeStructure/FolderNameInput.d.ts +15 -0
- package/lib/TreeStructure/FolderNameInput.js +125 -0
- package/lib/TreeStructure/TreeStructure.d.ts +12 -0
- package/lib/TreeStructure/TreeStructure.js +273 -0
- package/lib/TreeStructure/TreeStructure.types.d.ts +63 -0
- package/lib/TreeStructure/TreeStructure.types.js +1 -0
- package/lib/TreeStructure/TreeStructureWrapper.d.ts +12 -0
- package/lib/TreeStructure/TreeStructureWrapper.js +24 -0
- package/lib/TreeStructure/helperFunctions.d.ts +5 -0
- package/lib/TreeStructure/helperFunctions.js +103 -0
- package/lib/TreeStructure/index.d.ts +10 -0
- package/lib/TreeStructure/index.js +15 -0
- package/lib/TreeStructure/keyboardNavigation/keyboardNavigation.d.ts +11 -0
- package/lib/TreeStructure/keyboardNavigation/keyboardNavigation.js +186 -0
- package/lib/TreeStructure/keyboardNavigation/keyboardNavigation.types.d.ts +26 -0
- package/lib/TreeStructure/keyboardNavigation/keyboardNavigation.types.js +1 -0
- package/lib/User/AuthModal.d.ts +3 -3
- package/lib/User/AuthModal.js +16 -23
- package/lib/User/UserInfo.d.ts +13 -0
- package/lib/User/UserInfo.js +84 -0
- package/lib/User/apiTypes.d.ts +61 -0
- package/lib/User/apiTypes.js +1 -0
- package/lib/User/index.d.ts +4 -0
- package/lib/User/index.js +8 -0
- package/lib/User/parseUserObject.d.ts +32 -0
- package/lib/User/parseUserObject.js +105 -0
- package/lib/all.css +90 -0
- package/lib/index.d.ts +14 -3
- package/lib/index.js +76 -10
- package/lib/locale/messages-en.d.ts +67 -0
- package/lib/locale/messages-en.js +75 -8
- package/lib/locale/messages-nb.d.ts +67 -0
- package/lib/locale/messages-nb.js +74 -7
- package/lib/locale/messages-nn.d.ts +67 -0
- package/lib/locale/messages-nn.js +74 -7
- package/lib/locale/messages-se.d.ts +67 -0
- package/lib/locale/messages-se.js +74 -7
- package/lib/locale/messages-sma.d.ts +67 -0
- package/lib/locale/messages-sma.js +74 -7
- package/lib/types.d.ts +1 -1
- package/package.json +11 -11
- package/src/Article/Article.tsx +31 -0
- package/src/Article/ArticleFavoritesButton.tsx +40 -0
- package/src/Article/index.ts +2 -0
- package/src/Breadcrumb/ActionBreadcrumb.tsx +68 -0
- package/src/Breadcrumb/index.ts +2 -0
- package/src/Footer/FooterAuth.tsx +7 -9
- package/src/InfoBlock/InfoBlock.tsx +61 -0
- package/src/InfoBlock/index.ts +1 -0
- package/src/LearningPaths/LearningPathMenu.tsx +1 -1
- package/src/Masthead/MastheadAuthModal.tsx +4 -5
- package/src/MyNdla/Navigation/VerticalNavigation.tsx +93 -0
- package/src/MyNdla/Navigation/index.ts +2 -0
- package/src/MyNdla/Resource/Folder.tsx +143 -0
- package/src/MyNdla/Resource/index.ts +10 -0
- package/src/MyNdla/index.ts +3 -5
- package/src/Notion/ConceptNotion.tsx +1 -0
- package/src/Notion/FigureNotion.tsx +12 -5
- package/src/Notion/NotionVisualElement.tsx +1 -1
- package/src/Resource/BlockResource.tsx +101 -0
- package/src/Resource/ListResource.tsx +111 -0
- package/src/Resource/index.ts +12 -0
- package/src/Resource/resourceComponents.tsx +143 -0
- package/src/ResourceGroup/ResourceGroup.tsx +3 -0
- package/src/ResourceGroup/ResourceItem.tsx +20 -3
- package/src/ResourceGroup/ResourceList.tsx +16 -3
- package/src/Search/ActiveFilters.jsx +0 -1
- package/src/Search/ContentTypeResult.tsx +8 -9
- package/src/SearchTypeResult/ActiveFilters.tsx +1 -3
- package/src/SearchTypeResult/SearchViewType.tsx +1 -1
- package/src/SnackBar/SnackBar.tsx +183 -0
- package/src/SnackBar/index.ts +13 -0
- package/src/TagSelector/SuggestionInput.tsx +230 -0
- package/src/TagSelector/Suggestions.tsx +125 -0
- package/src/TagSelector/TagSelector.tsx +111 -0
- package/src/TagSelector/index.ts +13 -0
- package/src/TopicIntroductionList/TopicIntroduction.tsx +2 -2
- package/src/TopicIntroductionList/TopicShortcutItem.tsx +1 -5
- package/src/TreeStructure/FolderItem.tsx +160 -0
- package/src/TreeStructure/FolderItems.tsx +109 -0
- package/src/TreeStructure/FolderNameInput.tsx +109 -0
- package/src/TreeStructure/TreeStructure.tsx +184 -0
- package/src/TreeStructure/TreeStructure.types.ts +69 -0
- package/src/TreeStructure/TreeStructureWrapper.tsx +34 -0
- package/src/TreeStructure/helperFunctions.ts +52 -0
- package/src/TreeStructure/index.ts +11 -0
- package/src/TreeStructure/keyboardNavigation/keyboardNavigation.ts +161 -0
- package/src/TreeStructure/keyboardNavigation/keyboardNavigation.types.ts +28 -0
- package/src/User/AuthModal.tsx +5 -26
- package/src/User/UserInfo.tsx +80 -0
- package/src/User/__tests__/parseUserObject-test.ts +315 -0
- package/src/User/apiTypes.ts +74 -0
- package/src/User/index.ts +4 -0
- package/src/User/parseUserObject.ts +83 -0
- package/src/all.scss +2 -0
- package/src/index.ts +15 -4
- package/src/locale/messages-en.ts +69 -7
- package/src/locale/messages-nb.ts +68 -6
- package/src/locale/messages-nn.ts +68 -6
- package/src/locale/messages-se.ts +68 -6
- package/src/locale/messages-sma.ts +68 -6
- package/src/types.ts +1 -1
- package/es/MyNdla/ResourceDash/Breadcrumbs.js +0 -22
- package/es/MyNdla/ResourceDash/ResourceElement.js +0 -27
- package/es/MyNdla/ResourceDash/ResourcesView.js +0 -43
- package/es/MyNdla/ResourceDash/index.js +0 -4
- package/lib/MyNdla/ResourceDash/Breadcrumbs.d.ts +0 -15
- package/lib/MyNdla/ResourceDash/Breadcrumbs.js +0 -35
- package/lib/MyNdla/ResourceDash/ResourceElement.d.ts +0 -18
- package/lib/MyNdla/ResourceDash/ResourceElement.js +0 -38
- package/lib/MyNdla/ResourceDash/ResourcesView.js +0 -57
- package/lib/MyNdla/ResourceDash/index.d.ts +0 -4
- package/lib/MyNdla/ResourceDash/index.js +0 -31
- package/src/MyNdla/ResourceDash/Breadcrumbs.tsx +0 -31
- package/src/MyNdla/ResourceDash/ResourceElement.tsx +0 -50
- package/src/MyNdla/ResourceDash/ResourcesView.tsx +0 -42
- package/src/MyNdla/ResourceDash/index.ts +0 -5
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { FolderStructureProps } from './TreeStructure.types';
|
|
2
|
+
|
|
3
|
+
const getPathOfFolder = (data: FolderStructureProps[], findId: string): string[] => {
|
|
4
|
+
const paths = (dataChildren: FolderStructureProps[], path: string[]): string[] => {
|
|
5
|
+
for (const { id, data: dataChildrenSub } of dataChildren) {
|
|
6
|
+
if (id === findId) {
|
|
7
|
+
return [...path, id];
|
|
8
|
+
} else if (dataChildrenSub?.length) {
|
|
9
|
+
return paths(dataChildrenSub, [...path, id]);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
return [];
|
|
13
|
+
};
|
|
14
|
+
return paths(data, []);
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const getIdPathsOfFolder = (data: FolderStructureProps[], findId: string): number[] => {
|
|
18
|
+
let currentPath: number[] = [];
|
|
19
|
+
const paths = (dataChildren: FolderStructureProps[], path: number[]) => {
|
|
20
|
+
dataChildren.forEach(({ id, data: dataChildrenSub }, _index) => {
|
|
21
|
+
if (id === findId) {
|
|
22
|
+
currentPath = [...path, _index];
|
|
23
|
+
} else if (dataChildrenSub?.length) {
|
|
24
|
+
paths(dataChildrenSub, [...path, _index]);
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
};
|
|
28
|
+
paths(data, []);
|
|
29
|
+
return currentPath;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const getFolderName = (data: FolderStructureProps[], findId: string | undefined): string | undefined => {
|
|
33
|
+
if (!findId) {
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
36
|
+
let folderName: string | undefined;
|
|
37
|
+
const paths = (dataChildren: FolderStructureProps[]) => {
|
|
38
|
+
dataChildren.some(({ id, name, data: dataChildrenSub }, _index) => {
|
|
39
|
+
if (id === findId) {
|
|
40
|
+
folderName = name;
|
|
41
|
+
return true;
|
|
42
|
+
} else if (dataChildrenSub?.length) {
|
|
43
|
+
return paths(dataChildrenSub);
|
|
44
|
+
}
|
|
45
|
+
return false;
|
|
46
|
+
});
|
|
47
|
+
};
|
|
48
|
+
paths(data);
|
|
49
|
+
return folderName;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export { getPathOfFolder, getIdPathsOfFolder, getFolderName };
|
|
@@ -0,0 +1,11 @@
|
|
|
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 TreeStructure from './TreeStructure';
|
|
10
|
+
export type { FolderStructureProps, TreeStructureProps } from './TreeStructure.types';
|
|
11
|
+
export { TreeStructure };
|
|
@@ -0,0 +1,161 @@
|
|
|
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 { FolderStructureProps, SetFocusedFolderId } from '../TreeStructure.types';
|
|
10
|
+
import { KeyboardNavigationProps, ElementWithKeyFocusProps } from './keyboardNavigation.types';
|
|
11
|
+
import { MAX_LEVEL_FOR_FOLDERS } from '../TreeStructure';
|
|
12
|
+
|
|
13
|
+
export const KEYBOARD_KEYS_OF_INTEREST = ['ArrowDown', 'ArrowUp', 'ArrowRight', 'ArrowLeft', ' '];
|
|
14
|
+
|
|
15
|
+
// Traverse upwards, incase parent is last element of its parent..
|
|
16
|
+
const traverseUpwards = (
|
|
17
|
+
inital: FolderStructureProps[],
|
|
18
|
+
setFocusedFolderId: SetFocusedFolderId,
|
|
19
|
+
paths: number[],
|
|
20
|
+
index: number,
|
|
21
|
+
) => {
|
|
22
|
+
let findParent: FolderStructureProps[] = inital;
|
|
23
|
+
const parentNextIds: (string | false)[] = [];
|
|
24
|
+
paths.forEach((pathIndex) => {
|
|
25
|
+
const nextParent = findParent ? findParent[pathIndex + 1] : undefined;
|
|
26
|
+
parentNextIds.push(nextParent?.id || false);
|
|
27
|
+
findParent = findParent[pathIndex].data || [];
|
|
28
|
+
});
|
|
29
|
+
if (!parentNextIds.length) {
|
|
30
|
+
parentNextIds.push(findParent[index + 1]?.id || false);
|
|
31
|
+
}
|
|
32
|
+
// We use a reversed version of parentNextIds, filtered out falses, to find the next element
|
|
33
|
+
// No newId? We are at the end of the tree so we wont update.
|
|
34
|
+
const newId = parentNextIds.reverse().filter((id) => id)[0];
|
|
35
|
+
if (newId) {
|
|
36
|
+
setFocusedFolderId(newId);
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const keyboardNavigation = ({
|
|
41
|
+
e,
|
|
42
|
+
data,
|
|
43
|
+
onToggleOpen,
|
|
44
|
+
setFocusedFolderId,
|
|
45
|
+
focusedFolderId: id,
|
|
46
|
+
openFolders,
|
|
47
|
+
}: KeyboardNavigationProps): string | undefined => {
|
|
48
|
+
if (e.key === ' ' && document.activeElement?.nodeName === 'INPUT') {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// We are navigating in the tree.
|
|
53
|
+
// We need to find the next folder in the tree
|
|
54
|
+
const elementWithKeyFocus: ElementWithKeyFocusProps = {
|
|
55
|
+
paths: [],
|
|
56
|
+
index: 0,
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const updatePathToElementWithKeyFocus = (
|
|
60
|
+
data: FolderStructureProps[],
|
|
61
|
+
paths: number[],
|
|
62
|
+
parent: FolderStructureProps[],
|
|
63
|
+
parentId?: string,
|
|
64
|
+
): boolean =>
|
|
65
|
+
data.some(({ data: childData, id: dataId, url }, _index) => {
|
|
66
|
+
if (dataId === id) {
|
|
67
|
+
elementWithKeyFocus.paths = paths;
|
|
68
|
+
elementWithKeyFocus.index = _index;
|
|
69
|
+
elementWithKeyFocus.isOpen = openFolders.has(dataId) && childData && childData.length > 0;
|
|
70
|
+
elementWithKeyFocus.data = childData;
|
|
71
|
+
elementWithKeyFocus.parent = parent;
|
|
72
|
+
elementWithKeyFocus.parentId = parentId;
|
|
73
|
+
elementWithKeyFocus.url = url;
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
return childData ? updatePathToElementWithKeyFocus(childData, [...paths, _index], [...childData], dataId) : false;
|
|
77
|
+
});
|
|
78
|
+
if (!updatePathToElementWithKeyFocus(data, [], data)) {
|
|
79
|
+
// Couldn't find its location in the tree.
|
|
80
|
+
// This should not happen, reset its value to root.
|
|
81
|
+
setFocusedFolderId(e.key === 'ArrowDown' ? data[0].id : undefined);
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
e.preventDefault();
|
|
85
|
+
e.stopPropagation();
|
|
86
|
+
|
|
87
|
+
if (e.key === ' ') {
|
|
88
|
+
const simulatedEvent = new MouseEvent('click', {
|
|
89
|
+
bubbles: true,
|
|
90
|
+
cancelable: true,
|
|
91
|
+
view: window,
|
|
92
|
+
});
|
|
93
|
+
document.activeElement && document.activeElement.dispatchEvent(simulatedEvent);
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (e.key === 'ArrowRight') {
|
|
98
|
+
if (
|
|
99
|
+
!elementWithKeyFocus.isOpen &&
|
|
100
|
+
elementWithKeyFocus.data?.length &&
|
|
101
|
+
id &&
|
|
102
|
+
elementWithKeyFocus.paths.length < MAX_LEVEL_FOR_FOLDERS - 1
|
|
103
|
+
) {
|
|
104
|
+
onToggleOpen(id);
|
|
105
|
+
}
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
if (e.key === 'ArrowLeft') {
|
|
109
|
+
if (id && elementWithKeyFocus.isOpen) {
|
|
110
|
+
onToggleOpen(id);
|
|
111
|
+
}
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (!id && e.key === 'ArrowDown') {
|
|
116
|
+
setFocusedFolderId(data[0].id);
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
if (!id) {
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
// Move up
|
|
123
|
+
if (e.key === 'ArrowUp') {
|
|
124
|
+
if (elementWithKeyFocus.index > 0) {
|
|
125
|
+
// Move upwards to the parent folder
|
|
126
|
+
setFocusedFolderId(
|
|
127
|
+
elementWithKeyFocus.parent ? elementWithKeyFocus.parent[elementWithKeyFocus.index - 1].id : undefined,
|
|
128
|
+
);
|
|
129
|
+
} else if (elementWithKeyFocus.paths.length > 0) {
|
|
130
|
+
elementWithKeyFocus.paths.pop();
|
|
131
|
+
let findParent = data;
|
|
132
|
+
elementWithKeyFocus.paths.forEach((index) => {
|
|
133
|
+
findParent = findParent[index].data as FolderStructureProps[];
|
|
134
|
+
});
|
|
135
|
+
const parentsCurrentIndex = findParent.findIndex(({ id }) => id === elementWithKeyFocus.parentId);
|
|
136
|
+
setFocusedFolderId(findParent[parentsCurrentIndex].id);
|
|
137
|
+
}
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
if (elementWithKeyFocus.isOpen) {
|
|
142
|
+
if (elementWithKeyFocus.data?.length) {
|
|
143
|
+
setFocusedFolderId(elementWithKeyFocus.data[0].id);
|
|
144
|
+
} else {
|
|
145
|
+
// move to next child of parent if any... need new traverse :-/
|
|
146
|
+
traverseUpwards(data, setFocusedFolderId, elementWithKeyFocus.paths, elementWithKeyFocus.index);
|
|
147
|
+
}
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (elementWithKeyFocus.parent && elementWithKeyFocus.index < elementWithKeyFocus.parent?.length - 1) {
|
|
152
|
+
// Move downwards to the next child
|
|
153
|
+
setFocusedFolderId(elementWithKeyFocus.parent[elementWithKeyFocus.index + 1].id);
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
traverseUpwards(data, setFocusedFolderId, elementWithKeyFocus.paths, elementWithKeyFocus.index);
|
|
158
|
+
return;
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
export default keyboardNavigation;
|
|
@@ -0,0 +1,28 @@
|
|
|
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 { FolderStructureProps, SetFocusedFolderId } from '../TreeStructure.types';
|
|
10
|
+
|
|
11
|
+
export interface KeyboardNavigationProps {
|
|
12
|
+
e: React.KeyboardEvent<HTMLElement>;
|
|
13
|
+
data: FolderStructureProps[];
|
|
14
|
+
setFocusedFolderId: SetFocusedFolderId;
|
|
15
|
+
openFolders: Set<string>;
|
|
16
|
+
onToggleOpen: (id: string) => void;
|
|
17
|
+
focusedFolderId: string | undefined;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface ElementWithKeyFocusProps {
|
|
21
|
+
paths: number[];
|
|
22
|
+
index: number;
|
|
23
|
+
data?: FolderStructureProps[];
|
|
24
|
+
parent?: FolderStructureProps[];
|
|
25
|
+
parentId?: string;
|
|
26
|
+
isOpen?: boolean;
|
|
27
|
+
url?: string;
|
|
28
|
+
}
|
package/src/User/AuthModal.tsx
CHANGED
|
@@ -13,6 +13,8 @@ import Modal, { ModalCloseButton } from '@ndla/modal';
|
|
|
13
13
|
import Button from '@ndla/button';
|
|
14
14
|
import { FeideText, LogIn, LogOut, HumanMaleBoard } from '@ndla/icons/common';
|
|
15
15
|
import { fonts, spacing } from '@ndla/core';
|
|
16
|
+
import { UserInfo } from './UserInfo';
|
|
17
|
+
import { FeideUserApiType } from './apiTypes';
|
|
16
18
|
|
|
17
19
|
const StyledModalBody = styled.div`
|
|
18
20
|
padding: ${spacing.normal} ${spacing.medium} ${spacing.medium};
|
|
@@ -38,17 +40,6 @@ const StyledHeading = styled.h2`
|
|
|
38
40
|
}
|
|
39
41
|
`;
|
|
40
42
|
|
|
41
|
-
const StyledAuthorizedInfoList = styled.ul`
|
|
42
|
-
margin: 0;
|
|
43
|
-
padding: 0 0 0 ${spacing.normal};
|
|
44
|
-
list-style-image: unset;
|
|
45
|
-
|
|
46
|
-
li {
|
|
47
|
-
margin: 0;
|
|
48
|
-
font-weight: ${fonts.weight.semibold};
|
|
49
|
-
}
|
|
50
|
-
`;
|
|
51
|
-
|
|
52
43
|
const StyledHumanMaleBoardIconWrapper = styled.span`
|
|
53
44
|
margin-left: ${spacing.xsmall};
|
|
54
45
|
`;
|
|
@@ -63,9 +54,8 @@ const StyledButtonWrapper = styled.div`
|
|
|
63
54
|
|
|
64
55
|
export type AuthModalProps = {
|
|
65
56
|
isAuthenticated?: boolean;
|
|
57
|
+
user?: FeideUserApiType;
|
|
66
58
|
showGeneralMessage?: boolean;
|
|
67
|
-
authorizedRole?: string;
|
|
68
|
-
authorizedCollectedInfo?: string[];
|
|
69
59
|
onAuthenticateClick: () => void;
|
|
70
60
|
position?: 'top' | 'bottom';
|
|
71
61
|
activateButton?: ReactElement;
|
|
@@ -76,9 +66,8 @@ export type AuthModalProps = {
|
|
|
76
66
|
|
|
77
67
|
const AuthModal = ({
|
|
78
68
|
isAuthenticated,
|
|
69
|
+
user,
|
|
79
70
|
showGeneralMessage = true,
|
|
80
|
-
authorizedRole,
|
|
81
|
-
authorizedCollectedInfo,
|
|
82
71
|
onAuthenticateClick,
|
|
83
72
|
position = 'top',
|
|
84
73
|
activateButton,
|
|
@@ -104,17 +93,7 @@ const AuthModal = ({
|
|
|
104
93
|
<ModalCloseButton onClick={onClose} title="Lukk" />
|
|
105
94
|
</StyledModalHeader>
|
|
106
95
|
<StyledModalContent>
|
|
107
|
-
{
|
|
108
|
-
{authorizedCollectedInfo && authorizedCollectedInfo.length > 0 && (
|
|
109
|
-
<div>
|
|
110
|
-
{t('user.modal.collectedInfo')}
|
|
111
|
-
<StyledAuthorizedInfoList>
|
|
112
|
-
{authorizedCollectedInfo.map((value) => (
|
|
113
|
-
<li key={value}>{value}</li>
|
|
114
|
-
))}
|
|
115
|
-
</StyledAuthorizedInfoList>
|
|
116
|
-
</div>
|
|
117
|
-
)}
|
|
96
|
+
{user && <UserInfo user={user} />}
|
|
118
97
|
{children}
|
|
119
98
|
{showGeneralMessage && (
|
|
120
99
|
<p>
|
|
@@ -0,0 +1,80 @@
|
|
|
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
|
+
import styled from '@emotion/styled';
|
|
9
|
+
import { spacing } from '@ndla/core';
|
|
10
|
+
import React from 'react';
|
|
11
|
+
import { useTranslation } from 'react-i18next';
|
|
12
|
+
import { FeideUserApiType } from './apiTypes';
|
|
13
|
+
import { parseUserObject } from './parseUserObject';
|
|
14
|
+
|
|
15
|
+
const InfoList = styled.ul`
|
|
16
|
+
padding: 0 0 0 ${spacing.normal};
|
|
17
|
+
`;
|
|
18
|
+
|
|
19
|
+
interface Props {
|
|
20
|
+
user: FeideUserApiType;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const ShortInfoDiv = styled.div`
|
|
24
|
+
margin: 2rem auto;
|
|
25
|
+
`;
|
|
26
|
+
|
|
27
|
+
export const UserInfo = ({ user }: Props) => {
|
|
28
|
+
const { t } = useTranslation();
|
|
29
|
+
|
|
30
|
+
const parsedUser = parseUserObject(user);
|
|
31
|
+
|
|
32
|
+
return (
|
|
33
|
+
<div>
|
|
34
|
+
{
|
|
35
|
+
<p>
|
|
36
|
+
{t('user.loggedInAs', {
|
|
37
|
+
role: t(`user.role.${parsedUser.primaryAffiliation}`),
|
|
38
|
+
})}
|
|
39
|
+
</p>
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
<ShortInfoDiv>
|
|
43
|
+
<div>
|
|
44
|
+
{t('user.username')}: <b>{user.uid}</b>
|
|
45
|
+
</div>
|
|
46
|
+
<div>
|
|
47
|
+
{t('user.name')}: <b>{user.displayName}</b>
|
|
48
|
+
</div>
|
|
49
|
+
<div>
|
|
50
|
+
{t('user.mail')}: <b>{user.mail?.join(', ')}</b>
|
|
51
|
+
</div>
|
|
52
|
+
</ShortInfoDiv>
|
|
53
|
+
|
|
54
|
+
{t('user.modal.collectedInfo')}
|
|
55
|
+
|
|
56
|
+
<InfoList>
|
|
57
|
+
{parsedUser.organizations.map((org) => (
|
|
58
|
+
<li key={org.id}>
|
|
59
|
+
{`${org.displayName}${org.membership.primarySchool ? ` (${t('user.primarySchool')})` : ''}`}
|
|
60
|
+
<InfoList>
|
|
61
|
+
{Object.entries(org.children).map(([groupType, val]) => {
|
|
62
|
+
if (val.length < 1) return null;
|
|
63
|
+
return (
|
|
64
|
+
<li key={groupType}>
|
|
65
|
+
{t(`user.groupTypes.${groupType}`)}
|
|
66
|
+
<InfoList>
|
|
67
|
+
{val.map((group) => (
|
|
68
|
+
<li key={group.id}>{`${group.displayName}${group.grep ? ` (${group.grep.code})` : ''}`}</li>
|
|
69
|
+
))}
|
|
70
|
+
</InfoList>
|
|
71
|
+
</li>
|
|
72
|
+
);
|
|
73
|
+
})}
|
|
74
|
+
</InfoList>
|
|
75
|
+
</li>
|
|
76
|
+
))}
|
|
77
|
+
</InfoList>
|
|
78
|
+
</div>
|
|
79
|
+
);
|
|
80
|
+
};
|