@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,160 @@
|
|
|
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, { useEffect, useRef } from 'react';
|
|
10
|
+
import styled from '@emotion/styled';
|
|
11
|
+
import { ArrowDropDown } from '@ndla/icons/common';
|
|
12
|
+
import { FolderOutlined } from '@ndla/icons/contentType';
|
|
13
|
+
import { colors, spacing, misc, animations } from '@ndla/core';
|
|
14
|
+
import { SetFocusedFolderId } from './TreeStructure.types';
|
|
15
|
+
|
|
16
|
+
const OpenButton = styled.button<{ isOpen: boolean }>`
|
|
17
|
+
background: transparent;
|
|
18
|
+
border: 0;
|
|
19
|
+
transform: rotate(${({ isOpen }) => (isOpen ? '0' : '-90')}deg);
|
|
20
|
+
padding: ${spacing.xsmall};
|
|
21
|
+
display: flex;
|
|
22
|
+
margin: 0;
|
|
23
|
+
color: ${colors.brand.secondary};
|
|
24
|
+
cursor: pointer;
|
|
25
|
+
&:hover {
|
|
26
|
+
color: ${colors.brand.primary};
|
|
27
|
+
}
|
|
28
|
+
svg {
|
|
29
|
+
width: 16px;
|
|
30
|
+
height: 16px;
|
|
31
|
+
transform: ${({ isOpen }) => (isOpen ? 'translateX(3px)' : 'translateY(3px)')};
|
|
32
|
+
}
|
|
33
|
+
`;
|
|
34
|
+
|
|
35
|
+
const FolderItemWrapper = styled.div`
|
|
36
|
+
display: flex;
|
|
37
|
+
align-items: center;
|
|
38
|
+
`;
|
|
39
|
+
|
|
40
|
+
const FolderName = styled.button<{ marked: boolean; noArrow?: boolean }>`
|
|
41
|
+
line-height: 1;
|
|
42
|
+
background: ${({ marked }) => (marked ? colors.brand.lighter : 'transparent')};
|
|
43
|
+
color: ${colors.text.primary};
|
|
44
|
+
&:hover,
|
|
45
|
+
&:focus {
|
|
46
|
+
background: ${({ marked }) => (marked ? colors.brand.light : colors.brand.lightest)};
|
|
47
|
+
color: ${colors.brand.primary};
|
|
48
|
+
}
|
|
49
|
+
transition: ${animations.durations.superFast};
|
|
50
|
+
border: 0;
|
|
51
|
+
border-radius: ${misc.borderRadius};
|
|
52
|
+
display: flex;
|
|
53
|
+
gap: ${spacing.xxsmall};
|
|
54
|
+
align-items: center;
|
|
55
|
+
cursor: pointer;
|
|
56
|
+
padding: ${spacing.xsmall};
|
|
57
|
+
margin: 0;
|
|
58
|
+
margin-left: ${({ noArrow }) => (noArrow ? `29px` : `0px`)};
|
|
59
|
+
flex-grow: 1;
|
|
60
|
+
box-shadow: none;
|
|
61
|
+
`;
|
|
62
|
+
|
|
63
|
+
const FolderNameLink = FolderName.withComponent('a');
|
|
64
|
+
|
|
65
|
+
interface Props {
|
|
66
|
+
name: string;
|
|
67
|
+
id: string;
|
|
68
|
+
onToggleOpen: (id: string) => void;
|
|
69
|
+
onMarkFolder: (id: string) => void;
|
|
70
|
+
isOpen: boolean;
|
|
71
|
+
markedFolderId?: string;
|
|
72
|
+
focusedFolderId?: string;
|
|
73
|
+
loading?: boolean;
|
|
74
|
+
openOnFolderClick?: boolean;
|
|
75
|
+
hideArrow?: boolean;
|
|
76
|
+
setFocusedFolderId: SetFocusedFolderId;
|
|
77
|
+
url?: string;
|
|
78
|
+
icon?: React.ReactNode;
|
|
79
|
+
noPaddingWhenArrowIsHidden?: boolean;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const FolderItem = ({
|
|
83
|
+
hideArrow,
|
|
84
|
+
loading,
|
|
85
|
+
name,
|
|
86
|
+
id,
|
|
87
|
+
onToggleOpen,
|
|
88
|
+
onMarkFolder,
|
|
89
|
+
isOpen,
|
|
90
|
+
markedFolderId,
|
|
91
|
+
focusedFolderId,
|
|
92
|
+
openOnFolderClick,
|
|
93
|
+
setFocusedFolderId,
|
|
94
|
+
icon,
|
|
95
|
+
url,
|
|
96
|
+
noPaddingWhenArrowIsHidden,
|
|
97
|
+
}: Props) => {
|
|
98
|
+
const folderNameLinkRef = useRef<HTMLAnchorElement | null>(null);
|
|
99
|
+
const folderNameButtonRef = useRef<HTMLButtonElement | null>(null);
|
|
100
|
+
useEffect(() => {
|
|
101
|
+
if (focusedFolderId === id) {
|
|
102
|
+
if (url && folderNameLinkRef.current) {
|
|
103
|
+
folderNameLinkRef.current.focus();
|
|
104
|
+
} else if (folderNameButtonRef.current) {
|
|
105
|
+
folderNameButtonRef.current.focus();
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}, [focusedFolderId, folderNameLinkRef, folderNameButtonRef, url, id]);
|
|
109
|
+
const marked = markedFolderId === id;
|
|
110
|
+
return (
|
|
111
|
+
<FolderItemWrapper>
|
|
112
|
+
{!hideArrow && (
|
|
113
|
+
<OpenButton tabIndex={-1} isOpen={isOpen} disabled={loading} onClick={() => onToggleOpen(id)}>
|
|
114
|
+
<ArrowDropDown />
|
|
115
|
+
</OpenButton>
|
|
116
|
+
)}
|
|
117
|
+
{url ? (
|
|
118
|
+
<FolderNameLink
|
|
119
|
+
ref={folderNameLinkRef}
|
|
120
|
+
noArrow={hideArrow}
|
|
121
|
+
tabIndex={marked ? 0 : -1}
|
|
122
|
+
marked={marked}
|
|
123
|
+
href={loading ? undefined : url}
|
|
124
|
+
onFocus={() => {
|
|
125
|
+
setFocusedFolderId(id);
|
|
126
|
+
}}
|
|
127
|
+
onClick={() => {
|
|
128
|
+
onMarkFolder(id);
|
|
129
|
+
if (openOnFolderClick) {
|
|
130
|
+
onToggleOpen(id);
|
|
131
|
+
}
|
|
132
|
+
}}>
|
|
133
|
+
{icon || <FolderOutlined />}
|
|
134
|
+
{name}
|
|
135
|
+
</FolderNameLink>
|
|
136
|
+
) : (
|
|
137
|
+
<FolderName
|
|
138
|
+
ref={folderNameButtonRef}
|
|
139
|
+
noArrow={hideArrow && !noPaddingWhenArrowIsHidden}
|
|
140
|
+
tabIndex={marked ? 0 : -1}
|
|
141
|
+
marked={marked}
|
|
142
|
+
disabled={loading}
|
|
143
|
+
onFocus={() => {
|
|
144
|
+
setFocusedFolderId(id);
|
|
145
|
+
}}
|
|
146
|
+
onClick={() => {
|
|
147
|
+
onMarkFolder(id);
|
|
148
|
+
if (openOnFolderClick) {
|
|
149
|
+
onToggleOpen(id);
|
|
150
|
+
}
|
|
151
|
+
}}>
|
|
152
|
+
{icon || <FolderOutlined />}
|
|
153
|
+
{name}
|
|
154
|
+
</FolderName>
|
|
155
|
+
)}
|
|
156
|
+
</FolderItemWrapper>
|
|
157
|
+
);
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
export default FolderItem;
|
|
@@ -0,0 +1,109 @@
|
|
|
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 from 'react';
|
|
10
|
+
import styled from '@emotion/styled';
|
|
11
|
+
import { animations, spacing } from '@ndla/core';
|
|
12
|
+
import FolderItem from './FolderItem';
|
|
13
|
+
import FolderNameInput from './FolderNameInput';
|
|
14
|
+
import { FolderItemsProps } from './TreeStructure.types';
|
|
15
|
+
import { MAX_LEVEL_FOR_FOLDERS } from './TreeStructure';
|
|
16
|
+
|
|
17
|
+
const StyledUL = styled.ul<{ firstLevel?: boolean }>`
|
|
18
|
+
${animations.fadeInLeft(animations.durations.fast)};
|
|
19
|
+
animation-fill-mode: forwards;
|
|
20
|
+
@media (prefers-reduced-motion: reduce) {
|
|
21
|
+
animation: none;
|
|
22
|
+
}
|
|
23
|
+
list-style: none;
|
|
24
|
+
margin: 0;
|
|
25
|
+
padding: 0;
|
|
26
|
+
margin-left: ${({ firstLevel }) => (firstLevel ? `-${spacing.xsmall}` : spacing.normal)};
|
|
27
|
+
`;
|
|
28
|
+
|
|
29
|
+
const StyledLI = styled.li`
|
|
30
|
+
margin: 0;
|
|
31
|
+
padding: 0;
|
|
32
|
+
`;
|
|
33
|
+
|
|
34
|
+
const FolderItems = ({
|
|
35
|
+
loading,
|
|
36
|
+
data,
|
|
37
|
+
idPaths,
|
|
38
|
+
editable,
|
|
39
|
+
onToggleOpen,
|
|
40
|
+
onCreateNewFolder,
|
|
41
|
+
onCancelNewFolder,
|
|
42
|
+
onSaveNewFolder,
|
|
43
|
+
newFolder,
|
|
44
|
+
openFolders,
|
|
45
|
+
markedFolderId,
|
|
46
|
+
onMarkFolder,
|
|
47
|
+
openOnFolderClick,
|
|
48
|
+
focusedFolderId,
|
|
49
|
+
setFocusedFolderId,
|
|
50
|
+
firstLevel,
|
|
51
|
+
}: FolderItemsProps) => (
|
|
52
|
+
<StyledUL role="group" firstLevel={firstLevel}>
|
|
53
|
+
{data.map(({ name, data: dataChildren, id, url, icon }, _index) => {
|
|
54
|
+
const newIdPaths = [...idPaths, _index];
|
|
55
|
+
const isOpen = openFolders?.has(id);
|
|
56
|
+
return (
|
|
57
|
+
<StyledLI key={id} role="treeitem">
|
|
58
|
+
<div>
|
|
59
|
+
<FolderItem
|
|
60
|
+
icon={icon}
|
|
61
|
+
url={url}
|
|
62
|
+
openOnFolderClick={openOnFolderClick}
|
|
63
|
+
loading={loading}
|
|
64
|
+
isOpen={isOpen}
|
|
65
|
+
id={id}
|
|
66
|
+
name={name}
|
|
67
|
+
markedFolderId={markedFolderId}
|
|
68
|
+
focusedFolderId={focusedFolderId}
|
|
69
|
+
onToggleOpen={onToggleOpen}
|
|
70
|
+
onMarkFolder={onMarkFolder}
|
|
71
|
+
hideArrow={dataChildren?.length === 0 || newIdPaths.length >= MAX_LEVEL_FOR_FOLDERS}
|
|
72
|
+
noPaddingWhenArrowIsHidden={editable && firstLevel && dataChildren?.length === 0}
|
|
73
|
+
setFocusedFolderId={setFocusedFolderId}
|
|
74
|
+
/>
|
|
75
|
+
</div>
|
|
76
|
+
{newFolder?.parentId === id && (
|
|
77
|
+
<FolderNameInput
|
|
78
|
+
loading={loading}
|
|
79
|
+
onCancelNewFolder={onCancelNewFolder}
|
|
80
|
+
onSaveNewFolder={onSaveNewFolder}
|
|
81
|
+
/>
|
|
82
|
+
)}
|
|
83
|
+
{dataChildren && isOpen && (
|
|
84
|
+
<FolderItems
|
|
85
|
+
loading={loading}
|
|
86
|
+
newFolder={newFolder}
|
|
87
|
+
openFolders={openFolders}
|
|
88
|
+
idPaths={newIdPaths}
|
|
89
|
+
editable={editable}
|
|
90
|
+
data={dataChildren}
|
|
91
|
+
onToggleOpen={onToggleOpen}
|
|
92
|
+
onCreateNewFolder={onCreateNewFolder}
|
|
93
|
+
onSaveNewFolder={onSaveNewFolder}
|
|
94
|
+
onCancelNewFolder={onCancelNewFolder}
|
|
95
|
+
markedFolderId={markedFolderId}
|
|
96
|
+
onMarkFolder={onMarkFolder}
|
|
97
|
+
openOnFolderClick={openOnFolderClick}
|
|
98
|
+
focusedFolderId={focusedFolderId}
|
|
99
|
+
setFocusedFolderId={setFocusedFolderId}
|
|
100
|
+
firstLevel={false}
|
|
101
|
+
/>
|
|
102
|
+
)}
|
|
103
|
+
</StyledLI>
|
|
104
|
+
);
|
|
105
|
+
})}
|
|
106
|
+
</StyledUL>
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
export default FolderItems;
|
|
@@ -0,0 +1,109 @@
|
|
|
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, { useEffect, useState, useRef } from 'react';
|
|
10
|
+
import styled from '@emotion/styled';
|
|
11
|
+
import { FolderOutlined } from '@ndla/icons/contentType';
|
|
12
|
+
import { ArrowDropDown as ArrowDropDownRaw } from '@ndla/icons/common';
|
|
13
|
+
import { Spinner } from '@ndla/editor';
|
|
14
|
+
import { spacing, colors, misc, animations } from '@ndla/core';
|
|
15
|
+
import { useTranslation } from 'react-i18next';
|
|
16
|
+
import { isMobile } from 'react-device-detect';
|
|
17
|
+
|
|
18
|
+
const ArrowRight = styled(ArrowDropDownRaw)`
|
|
19
|
+
color: ${colors.text.primary};
|
|
20
|
+
transform: rotate(-90deg);
|
|
21
|
+
`;
|
|
22
|
+
|
|
23
|
+
const NewFolderWrapper = styled.div`
|
|
24
|
+
padding-left: ${spacing.normal};
|
|
25
|
+
${animations.fadeInLeft(animations.durations.fast)};
|
|
26
|
+
animation-fill-mode: forwards;
|
|
27
|
+
@media (prefers-reduced-motion: reduce) {
|
|
28
|
+
animation: none;
|
|
29
|
+
}
|
|
30
|
+
`;
|
|
31
|
+
|
|
32
|
+
const InputWrapper = styled.div<{ loading?: boolean }>`
|
|
33
|
+
margin: ${spacing.xxsmall} ${spacing.small} ${spacing.xxsmall} 0;
|
|
34
|
+
display: flex;
|
|
35
|
+
align-items: center;
|
|
36
|
+
border: 1px solid ${({ loading }) => (loading ? colors.brand.lighter : colors.brand.primary)};
|
|
37
|
+
border-style: dashed;
|
|
38
|
+
border-radius: ${misc.borderRadius};
|
|
39
|
+
padding-right: ${spacing.normal};
|
|
40
|
+
padding-left: ${spacing.xsmall};
|
|
41
|
+
color: ${colors.brand.primary};
|
|
42
|
+
`;
|
|
43
|
+
|
|
44
|
+
const StyledInput = styled.input`
|
|
45
|
+
flex-grow: 1;
|
|
46
|
+
border: 0;
|
|
47
|
+
outline: none;
|
|
48
|
+
padding: ${spacing.small};
|
|
49
|
+
padding-left: ${spacing.xsmall};
|
|
50
|
+
background: transparent;
|
|
51
|
+
color: ${colors.text.primary};
|
|
52
|
+
scroll-margin-top: 100px;
|
|
53
|
+
`;
|
|
54
|
+
|
|
55
|
+
interface FolderNameInputProps {
|
|
56
|
+
onSaveNewFolder: (value: string) => void;
|
|
57
|
+
onCancelNewFolder: () => void;
|
|
58
|
+
loading?: boolean;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const FolderNameInput = ({ onSaveNewFolder, onCancelNewFolder, loading }: FolderNameInputProps) => {
|
|
62
|
+
const { t } = useTranslation();
|
|
63
|
+
const [value, setValue] = useState<string>(t('treeStructure.newFolder.defaultName'));
|
|
64
|
+
const inputRef = useRef<HTMLInputElement>(null);
|
|
65
|
+
|
|
66
|
+
useEffect(() => {
|
|
67
|
+
if (inputRef.current) {
|
|
68
|
+
inputRef.current.select();
|
|
69
|
+
if (isMobile) {
|
|
70
|
+
inputRef.current.scrollIntoView({ behavior: 'smooth' });
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}, []);
|
|
74
|
+
|
|
75
|
+
return (
|
|
76
|
+
<NewFolderWrapper>
|
|
77
|
+
<InputWrapper loading={loading}>
|
|
78
|
+
<ArrowRight />
|
|
79
|
+
<FolderOutlined />
|
|
80
|
+
<StyledInput
|
|
81
|
+
ref={inputRef}
|
|
82
|
+
autoFocus
|
|
83
|
+
placeholder={t('treeStructure.newFolder.placeholder')}
|
|
84
|
+
disabled={loading}
|
|
85
|
+
value={value}
|
|
86
|
+
onBlur={() => onCancelNewFolder()}
|
|
87
|
+
onKeyDown={(e: React.KeyboardEvent<HTMLInputElement>) => {
|
|
88
|
+
if (e.key === 'Escape') {
|
|
89
|
+
onCancelNewFolder();
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
if (e.key === 'Enter' || e.key === 'Tab') {
|
|
93
|
+
onSaveNewFolder(value);
|
|
94
|
+
e.preventDefault();
|
|
95
|
+
}
|
|
96
|
+
return;
|
|
97
|
+
}}
|
|
98
|
+
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
|
99
|
+
const target = e.target as HTMLInputElement;
|
|
100
|
+
setValue(target.value);
|
|
101
|
+
}}
|
|
102
|
+
/>
|
|
103
|
+
{loading && <Spinner size="small" />}
|
|
104
|
+
</InputWrapper>
|
|
105
|
+
</NewFolderWrapper>
|
|
106
|
+
);
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
export default FolderNameInput;
|
|
@@ -0,0 +1,184 @@
|
|
|
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, { useEffect, useState, useRef, useMemo } from 'react';
|
|
10
|
+
import { uuid } from '@ndla/util';
|
|
11
|
+
import Button from '@ndla/button';
|
|
12
|
+
import Tooltip from '@ndla/tooltip';
|
|
13
|
+
import { useTranslation } from 'react-i18next';
|
|
14
|
+
import styled from '@emotion/styled';
|
|
15
|
+
import { spacing, fonts } from '@ndla/core';
|
|
16
|
+
import TreeStructureStyledWrapper from './TreeStructureWrapper';
|
|
17
|
+
import FolderItems from './FolderItems';
|
|
18
|
+
import { getIdPathsOfFolder, getPathOfFolder, getFolderName } from './helperFunctions';
|
|
19
|
+
import keyboardNavigation, { KEYBOARD_KEYS_OF_INTEREST } from './keyboardNavigation/keyboardNavigation';
|
|
20
|
+
import { NewFolderProps, TreeStructureProps } from './TreeStructure.types';
|
|
21
|
+
|
|
22
|
+
export const MAX_LEVEL_FOR_FOLDERS = 4;
|
|
23
|
+
|
|
24
|
+
const StyledLabel = styled.label`
|
|
25
|
+
font-weight: ${fonts.weight.semibold};
|
|
26
|
+
`;
|
|
27
|
+
|
|
28
|
+
const AddFolderWrapper = styled.div`
|
|
29
|
+
display: flex;
|
|
30
|
+
margin-top: ${spacing.xsmall};
|
|
31
|
+
`;
|
|
32
|
+
|
|
33
|
+
const TreeStructure = ({
|
|
34
|
+
data,
|
|
35
|
+
label,
|
|
36
|
+
editable,
|
|
37
|
+
loading,
|
|
38
|
+
onNewFolder,
|
|
39
|
+
openOnFolderClick,
|
|
40
|
+
framed,
|
|
41
|
+
folderIdMarkedByDefault,
|
|
42
|
+
defaultOpenFolders,
|
|
43
|
+
}: TreeStructureProps) => {
|
|
44
|
+
const { t } = useTranslation();
|
|
45
|
+
const [newFolder, setNewFolder] = useState<NewFolderProps | undefined>();
|
|
46
|
+
const [openFolders, setOpenFolders] = useState<Set<string>>(new Set(defaultOpenFolders || []));
|
|
47
|
+
const [focusedFolderId, setFocusedFolderId] = useState<string | undefined>();
|
|
48
|
+
const [markedFolderId, setMarkedFolderId] = useState<string | undefined>(folderIdMarkedByDefault || data[0].id);
|
|
49
|
+
const treestructureRef = useRef<HTMLDivElement>(null);
|
|
50
|
+
const wrapperRef = useRef<HTMLDivElement>(null);
|
|
51
|
+
const rootLevelId = useMemo(() => uuid(), []); // TODO: use useId hook when we update to React 18
|
|
52
|
+
|
|
53
|
+
useEffect(() => {
|
|
54
|
+
setOpenFolders((prev) => {
|
|
55
|
+
defaultOpenFolders?.forEach((id) => prev.add(id));
|
|
56
|
+
return new Set(prev);
|
|
57
|
+
});
|
|
58
|
+
}, [defaultOpenFolders]);
|
|
59
|
+
|
|
60
|
+
useEffect(() => {
|
|
61
|
+
if (!loading) {
|
|
62
|
+
setNewFolder(undefined);
|
|
63
|
+
}
|
|
64
|
+
}, [loading]);
|
|
65
|
+
|
|
66
|
+
const onToggleOpen = (id: string) => {
|
|
67
|
+
setOpenFolders((prev) => {
|
|
68
|
+
if (prev.has(id)) {
|
|
69
|
+
prev.delete(id);
|
|
70
|
+
// Did we just closed a folder with a marked folder inside it?
|
|
71
|
+
// If so, we need to mark the folder we just closed.
|
|
72
|
+
if (markedFolderId) {
|
|
73
|
+
const closingFolderPath = getPathOfFolder(data, id);
|
|
74
|
+
const markedFolderPath = getPathOfFolder(data, markedFolderId);
|
|
75
|
+
const markedFolderIsSubPath = closingFolderPath.every(
|
|
76
|
+
(folderId, _index) => markedFolderPath[_index] === folderId,
|
|
77
|
+
);
|
|
78
|
+
if (markedFolderIsSubPath) {
|
|
79
|
+
setMarkedFolderId(closingFolderPath[closingFolderPath.length - 1]);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
} else {
|
|
83
|
+
prev.add(id);
|
|
84
|
+
}
|
|
85
|
+
return new Set(prev);
|
|
86
|
+
});
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
const onCreateNewFolder = (props: { idPaths: number[]; parentId?: string }) => {
|
|
90
|
+
setNewFolder(props);
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
const onSaveNewFolder = async (value: string) => {
|
|
94
|
+
if (newFolder) {
|
|
95
|
+
// We would like to create a new folder with the name of value.
|
|
96
|
+
// Its location in structure is based on newFolder object
|
|
97
|
+
const newFolderId = await onNewFolder({ ...newFolder, value });
|
|
98
|
+
if (newFolderId) {
|
|
99
|
+
setMarkedFolderId(newFolderId);
|
|
100
|
+
setFocusedFolderId(newFolderId);
|
|
101
|
+
// Open current folder in case it was closed..
|
|
102
|
+
setOpenFolders((prev) => {
|
|
103
|
+
if (newFolder.parentId) {
|
|
104
|
+
prev.add(newFolder.parentId);
|
|
105
|
+
}
|
|
106
|
+
return new Set(prev);
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
const onCancelNewFolder = () => {
|
|
113
|
+
setNewFolder(undefined);
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
const onMarkFolder = (id: string) => {
|
|
117
|
+
setMarkedFolderId(id);
|
|
118
|
+
setFocusedFolderId(id);
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
const disableAddFolderButton =
|
|
122
|
+
markedFolderId === undefined || getPathOfFolder(data, markedFolderId).length >= MAX_LEVEL_FOR_FOLDERS;
|
|
123
|
+
|
|
124
|
+
return (
|
|
125
|
+
<div
|
|
126
|
+
ref={treestructureRef}
|
|
127
|
+
onKeyDown={(e) => {
|
|
128
|
+
if (wrapperRef.current?.contains(document.activeElement) && KEYBOARD_KEYS_OF_INTEREST.includes(e.key)) {
|
|
129
|
+
keyboardNavigation({
|
|
130
|
+
e,
|
|
131
|
+
data,
|
|
132
|
+
setFocusedFolderId,
|
|
133
|
+
focusedFolderId,
|
|
134
|
+
onToggleOpen,
|
|
135
|
+
openFolders,
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
}}>
|
|
139
|
+
<StyledLabel htmlFor={rootLevelId}>{label}</StyledLabel>
|
|
140
|
+
<TreeStructureStyledWrapper ref={wrapperRef} id={rootLevelId} aria-label="Menu tree" role="tree" framed={framed}>
|
|
141
|
+
<FolderItems
|
|
142
|
+
idPaths={[]}
|
|
143
|
+
data={data}
|
|
144
|
+
editable={editable}
|
|
145
|
+
onToggleOpen={onToggleOpen}
|
|
146
|
+
newFolder={newFolder}
|
|
147
|
+
onCreateNewFolder={onCreateNewFolder}
|
|
148
|
+
onCancelNewFolder={onCancelNewFolder}
|
|
149
|
+
onSaveNewFolder={onSaveNewFolder}
|
|
150
|
+
openFolders={openFolders}
|
|
151
|
+
markedFolderId={markedFolderId}
|
|
152
|
+
onMarkFolder={onMarkFolder}
|
|
153
|
+
openOnFolderClick={openOnFolderClick}
|
|
154
|
+
loading={loading}
|
|
155
|
+
focusedFolderId={focusedFolderId}
|
|
156
|
+
setFocusedFolderId={setFocusedFolderId}
|
|
157
|
+
firstLevel
|
|
158
|
+
/>
|
|
159
|
+
</TreeStructureStyledWrapper>
|
|
160
|
+
{editable && (
|
|
161
|
+
<AddFolderWrapper>
|
|
162
|
+
<Tooltip
|
|
163
|
+
tooltip={t('myNdla.newFolderUnder', {
|
|
164
|
+
folderName: getFolderName(data, markedFolderId),
|
|
165
|
+
})}>
|
|
166
|
+
<Button
|
|
167
|
+
size="small"
|
|
168
|
+
light
|
|
169
|
+
disabled={disableAddFolderButton}
|
|
170
|
+
onClick={() => {
|
|
171
|
+
const paths = getPathOfFolder(data, markedFolderId || '');
|
|
172
|
+
const idPaths = getIdPathsOfFolder(data, markedFolderId || '');
|
|
173
|
+
setNewFolder({ idPaths, parentId: paths[paths.length - 1] });
|
|
174
|
+
}}>
|
|
175
|
+
{t('myNdla.newFolder')}
|
|
176
|
+
</Button>
|
|
177
|
+
</Tooltip>
|
|
178
|
+
</AddFolderWrapper>
|
|
179
|
+
)}
|
|
180
|
+
</div>
|
|
181
|
+
);
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
export default TreeStructure;
|
|
@@ -0,0 +1,69 @@
|
|
|
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 from 'react';
|
|
10
|
+
|
|
11
|
+
export interface FolderStructureProps {
|
|
12
|
+
id: string;
|
|
13
|
+
name: string;
|
|
14
|
+
isOpen?: boolean;
|
|
15
|
+
data?: FolderStructureProps[];
|
|
16
|
+
isFavorite?: boolean;
|
|
17
|
+
status?: string;
|
|
18
|
+
openAsDefault?: boolean;
|
|
19
|
+
url?: string;
|
|
20
|
+
icon?: React.ReactNode;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface NewFolderProps {
|
|
24
|
+
parentId?: string;
|
|
25
|
+
idPaths: number[];
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
interface CommonFolderProps {
|
|
29
|
+
data: FolderStructureProps[];
|
|
30
|
+
editable?: boolean;
|
|
31
|
+
loading?: boolean;
|
|
32
|
+
openOnFolderClick?: boolean;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface TreeStructureProps extends CommonFolderProps {
|
|
36
|
+
framed?: boolean;
|
|
37
|
+
label: string;
|
|
38
|
+
folderIdMarkedByDefault?: string;
|
|
39
|
+
onNewFolder: (props: { value: string; parentId?: string; idPaths: number[] }) => Promise<string>;
|
|
40
|
+
defaultOpenFolders?: string[];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export type onCreateNewFolderProp = ({
|
|
44
|
+
idPaths,
|
|
45
|
+
parentId,
|
|
46
|
+
}: {
|
|
47
|
+
idPaths: number[];
|
|
48
|
+
parentId: string | undefined;
|
|
49
|
+
}) => void;
|
|
50
|
+
|
|
51
|
+
export type SetOpenFolderProp = React.Dispatch<React.SetStateAction<Set<string>>>;
|
|
52
|
+
export type SetFocusedFolderId = React.Dispatch<React.SetStateAction<string | undefined>>;
|
|
53
|
+
|
|
54
|
+
export interface FolderItemsProps extends CommonFolderProps {
|
|
55
|
+
onToggleOpen: (id: string) => void;
|
|
56
|
+
onSaveNewFolder: (value: string) => void;
|
|
57
|
+
onCancelNewFolder: () => void;
|
|
58
|
+
onCreateNewFolder: onCreateNewFolderProp;
|
|
59
|
+
newFolder: NewFolderProps | undefined;
|
|
60
|
+
openFolders: Set<string>;
|
|
61
|
+
markedFolderId?: string;
|
|
62
|
+
onMarkFolder: (id: string) => void;
|
|
63
|
+
idPaths: number[];
|
|
64
|
+
focusedFolderId: string | undefined;
|
|
65
|
+
setFocusedFolderId: SetFocusedFolderId;
|
|
66
|
+
firstLevel: boolean;
|
|
67
|
+
keyNavigationFocusIsCreateFolderButton?: boolean;
|
|
68
|
+
icon?: React.ReactElement;
|
|
69
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
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 styled from '@emotion/styled';
|
|
10
|
+
import { css } from '@emotion/core';
|
|
11
|
+
import { colors, misc, spacing } from '@ndla/core';
|
|
12
|
+
|
|
13
|
+
const TreeStructureWrapper = styled.div<{ framed?: boolean }>`
|
|
14
|
+
padding: ${spacing.xsmall};
|
|
15
|
+
${({ framed }) =>
|
|
16
|
+
framed
|
|
17
|
+
? css`
|
|
18
|
+
border: 1px solid ${colors.brand.greyLighter};
|
|
19
|
+
border-radius: ${misc.borderRadius};
|
|
20
|
+
max-height: 400px;
|
|
21
|
+
overflow-y: scroll;
|
|
22
|
+
scroll-behavior: smooth;
|
|
23
|
+
padding: ${spacing.small};
|
|
24
|
+
`
|
|
25
|
+
: css`
|
|
26
|
+
margin-left: -${spacing.medium};
|
|
27
|
+
`}
|
|
28
|
+
transition: ${misc.transition.default};
|
|
29
|
+
&:focus-within {
|
|
30
|
+
border-color: ${colors.brand.primary};
|
|
31
|
+
}
|
|
32
|
+
`;
|
|
33
|
+
|
|
34
|
+
export default TreeStructureWrapper;
|