@ndla/ui 19.1.0 → 20.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.
Files changed (83) hide show
  1. package/es/MyNdla/Resource/FolderInput.js +29 -36
  2. package/es/NDLAFilm/FilmSlideshow.js +8 -8
  3. package/es/Search/LoadingWrapper.js +2 -2
  4. package/es/Search/SearchResult.js +1 -1
  5. package/es/SearchTypeResult/SearchTypeResult.js +3 -3
  6. package/es/TreeStructure/FolderItem.js +54 -38
  7. package/es/TreeStructure/FolderItems.js +29 -35
  8. package/es/TreeStructure/FolderNameInput.js +12 -16
  9. package/es/TreeStructure/TreeStructure.js +64 -91
  10. package/es/TreeStructure/arrowNavigation.js +44 -0
  11. package/es/TreeStructure/helperFunctions.js +41 -35
  12. package/es/index.js +0 -1
  13. package/es/locale/messages-en.js +4 -1
  14. package/es/locale/messages-nb.js +4 -1
  15. package/es/locale/messages-nn.js +4 -1
  16. package/es/locale/messages-se.js +4 -1
  17. package/es/locale/messages-sma.js +4 -1
  18. package/lib/MyNdla/Resource/FolderInput.d.ts +2 -2
  19. package/lib/MyNdla/Resource/FolderInput.js +26 -33
  20. package/lib/NDLAFilm/FilmSlideshow.js +10 -10
  21. package/lib/Search/LoadingWrapper.js +3 -3
  22. package/lib/Search/SearchResult.js +2 -2
  23. package/lib/SearchTypeResult/SearchTypeResult.js +4 -4
  24. package/lib/TreeStructure/FolderItem.d.ts +6 -3
  25. package/lib/TreeStructure/FolderItem.js +55 -38
  26. package/lib/TreeStructure/FolderItems.d.ts +1 -1
  27. package/lib/TreeStructure/FolderItems.js +29 -35
  28. package/lib/TreeStructure/FolderNameInput.d.ts +3 -2
  29. package/lib/TreeStructure/FolderNameInput.js +13 -17
  30. package/lib/TreeStructure/TreeStructure.d.ts +1 -6
  31. package/lib/TreeStructure/TreeStructure.js +63 -92
  32. package/lib/TreeStructure/TreeStructure.types.d.ts +13 -20
  33. package/lib/TreeStructure/arrowNavigation.d.ts +9 -0
  34. package/lib/TreeStructure/arrowNavigation.js +54 -0
  35. package/lib/TreeStructure/helperFunctions.d.ts +3 -4
  36. package/lib/TreeStructure/helperFunctions.js +45 -35
  37. package/lib/index.d.ts +0 -1
  38. package/lib/index.js +0 -9
  39. package/lib/locale/messages-en.d.ts +3 -0
  40. package/lib/locale/messages-en.js +4 -1
  41. package/lib/locale/messages-nb.d.ts +3 -0
  42. package/lib/locale/messages-nb.js +4 -1
  43. package/lib/locale/messages-nn.d.ts +3 -0
  44. package/lib/locale/messages-nn.js +4 -1
  45. package/lib/locale/messages-se.d.ts +3 -0
  46. package/lib/locale/messages-se.js +4 -1
  47. package/lib/locale/messages-sma.d.ts +3 -0
  48. package/lib/locale/messages-sma.js +4 -1
  49. package/package.json +11 -10
  50. package/src/MyNdla/Resource/FolderInput.tsx +41 -44
  51. package/src/NDLAFilm/FilmSlideshow.tsx +1 -1
  52. package/src/Search/LoadingWrapper.tsx +1 -1
  53. package/src/Search/SearchResult.jsx +1 -1
  54. package/src/SearchTypeResult/SearchTypeResult.tsx +1 -1
  55. package/src/TreeStructure/FolderItem.tsx +63 -40
  56. package/src/TreeStructure/FolderItems.tsx +26 -19
  57. package/src/TreeStructure/FolderNameInput.tsx +10 -12
  58. package/src/TreeStructure/TreeStructure.tsx +56 -71
  59. package/src/TreeStructure/TreeStructure.types.ts +13 -17
  60. package/src/TreeStructure/arrowNavigation.ts +53 -0
  61. package/src/TreeStructure/helperFunctions.ts +17 -25
  62. package/src/index.ts +0 -2
  63. package/src/locale/messages-en.ts +3 -0
  64. package/src/locale/messages-nb.ts +3 -0
  65. package/src/locale/messages-nn.ts +3 -0
  66. package/src/locale/messages-se.ts +3 -0
  67. package/src/locale/messages-sma.ts +3 -0
  68. package/es/Spinner/Spinner.js +0 -42
  69. package/es/Spinner/index.js +0 -2
  70. package/es/TreeStructure/keyboardNavigation/keyboardNavigation.js +0 -194
  71. package/es/TreeStructure/keyboardNavigation/keyboardNavigation.types.js +0 -0
  72. package/lib/Spinner/Spinner.d.ts +0 -16
  73. package/lib/Spinner/Spinner.js +0 -54
  74. package/lib/Spinner/index.d.ts +0 -2
  75. package/lib/Spinner/index.js +0 -13
  76. package/lib/TreeStructure/keyboardNavigation/keyboardNavigation.d.ts +0 -11
  77. package/lib/TreeStructure/keyboardNavigation/keyboardNavigation.js +0 -198
  78. package/lib/TreeStructure/keyboardNavigation/keyboardNavigation.types.d.ts +0 -26
  79. package/lib/TreeStructure/keyboardNavigation/keyboardNavigation.types.js +0 -1
  80. package/src/Spinner/Spinner.tsx +0 -46
  81. package/src/Spinner/index.ts +0 -3
  82. package/src/TreeStructure/keyboardNavigation/keyboardNavigation.ts +0 -161
  83. package/src/TreeStructure/keyboardNavigation/keyboardNavigation.types.ts +0 -28
package/lib/index.js CHANGED
@@ -83,7 +83,6 @@ var _exportNames = {
83
83
  Translation: true,
84
84
  TranslationLine: true,
85
85
  TranslationBox: true,
86
- Spinner: true,
87
86
  SearchResultSleeve: true,
88
87
  ContentTypeResult: true,
89
88
  SearchFieldForm: true,
@@ -650,12 +649,6 @@ Object.defineProperty(exports, "TranslationBox", {
650
649
  return _Translation.TranslationBox;
651
650
  }
652
651
  });
653
- Object.defineProperty(exports, "Spinner", {
654
- enumerable: true,
655
- get: function get() {
656
- return _Spinner["default"];
657
- }
658
- });
659
652
  Object.defineProperty(exports, "SearchResultSleeve", {
660
653
  enumerable: true,
661
654
  get: function get() {
@@ -1336,8 +1329,6 @@ var _LearningPaths = require("./LearningPaths");
1336
1329
 
1337
1330
  var _Translation = require("./Translation");
1338
1331
 
1339
- var _Spinner = _interopRequireDefault(require("./Spinner"));
1340
-
1341
1332
  var _SearchResultSleeve = _interopRequireDefault(require("./Search/SearchResultSleeve"));
1342
1333
 
1343
1334
  var _ContentTypeResult = _interopRequireDefault(require("./Search/ContentTypeResult"));
@@ -62,6 +62,7 @@ declare const messages: {
62
62
  folder: string;
63
63
  delete: string;
64
64
  edit: string;
65
+ missingName: string;
65
66
  };
66
67
  confirmDeleteFolder: string;
67
68
  confirmDeleteTag: string;
@@ -964,8 +965,10 @@ declare const messages: {
964
965
  open: string;
965
966
  close: string;
966
967
  };
968
+ cancel: string;
967
969
  close: string;
968
970
  title: string;
971
+ save: string;
969
972
  image: {
970
973
  altText: string;
971
974
  caption: string;
@@ -823,8 +823,10 @@ var messages = _objectSpread(_objectSpread({
823
823
  open: 'Open menu',
824
824
  close: 'Close menu'
825
825
  },
826
+ cancel: 'Cancel',
826
827
  close: 'Close',
827
828
  title: 'Title',
829
+ save: 'Save',
828
830
  image: {
829
831
  altText: 'Alt-text',
830
832
  caption: 'Caption',
@@ -954,7 +956,8 @@ var messages = _objectSpread(_objectSpread({
954
956
  folder: {
955
957
  folder: 'Folder',
956
958
  "delete": 'Delete',
957
- edit: 'Edit'
959
+ edit: 'Edit',
960
+ missingName: 'Folder name required'
958
961
  },
959
962
  confirmDeleteFolder: 'Are you sure you want to delete this folder? This process cannot be undone.',
960
963
  confirmDeleteTag: 'Are you sure you want to delete this tag? This process cannot be undone.',
@@ -62,6 +62,7 @@ declare const messages: {
62
62
  folder: string;
63
63
  delete: string;
64
64
  edit: string;
65
+ missingName: string;
65
66
  };
66
67
  confirmDeleteFolder: string;
67
68
  confirmDeleteTag: string;
@@ -966,6 +967,8 @@ declare const messages: {
966
967
  };
967
968
  close: string;
968
969
  title: string;
970
+ cancel: string;
971
+ save: string;
969
972
  image: {
970
973
  altText: string;
971
974
  caption: string;
@@ -825,6 +825,8 @@ var messages = _objectSpread(_objectSpread({
825
825
  },
826
826
  close: 'Lukk',
827
827
  title: 'Tittel',
828
+ cancel: 'Avbryt',
829
+ save: 'Lagre',
828
830
  image: {
829
831
  altText: 'Alt-tekst',
830
832
  caption: 'Bildetekst',
@@ -954,7 +956,8 @@ var messages = _objectSpread(_objectSpread({
954
956
  folder: {
955
957
  folder: 'Mappe',
956
958
  "delete": 'Slett',
957
- edit: 'Rediger'
959
+ edit: 'Rediger',
960
+ missingName: 'Mappenavn er påkrevd'
958
961
  },
959
962
  confirmDeleteFolder: 'Er du sikker på at du vil slette mappen? Denne handlingen kan ikke angres.',
960
963
  confirmDeleteTag: 'Er du sikker på at du vil slette tag? Denne handlingen kan ikke angres.',
@@ -62,6 +62,7 @@ declare const messages: {
62
62
  folder: string;
63
63
  delete: string;
64
64
  edit: string;
65
+ missingName: string;
65
66
  };
66
67
  confirmDeleteFolder: string;
67
68
  confirmDeleteTag: string;
@@ -964,8 +965,10 @@ declare const messages: {
964
965
  open: string;
965
966
  close: string;
966
967
  };
968
+ cancel: string;
967
969
  close: string;
968
970
  title: string;
971
+ save: string;
969
972
  image: {
970
973
  altText: string;
971
974
  caption: string;
@@ -823,8 +823,10 @@ var messages = _objectSpread(_objectSpread({
823
823
  open: 'Åpne meny',
824
824
  close: 'Lukk meny'
825
825
  },
826
+ cancel: 'Avbryt',
826
827
  close: 'Lukk',
827
828
  title: 'Tittel',
829
+ save: 'Lagre',
828
830
  image: {
829
831
  altText: 'Alt-tekst',
830
832
  caption: 'Bilettekst',
@@ -954,7 +956,8 @@ var messages = _objectSpread(_objectSpread({
954
956
  folder: {
955
957
  folder: 'Mappe',
956
958
  "delete": 'Slett',
957
- edit: 'Rediger'
959
+ edit: 'Rediger',
960
+ missingName: 'Mappenavn er påkrevd'
958
961
  },
959
962
  confirmDeleteFolder: 'Er du sikker på at du vil slette mappa? Denne handlinga kan ikkje angres.',
960
963
  confirmDeleteTag: 'Er du sikker på at du vil slette tag? Denne handlinga kan ikkje angres.',
@@ -62,6 +62,7 @@ declare const messages: {
62
62
  folder: string;
63
63
  delete: string;
64
64
  edit: string;
65
+ missingName: string;
65
66
  };
66
67
  confirmDeleteFolder: string;
67
68
  confirmDeleteTag: string;
@@ -964,8 +965,10 @@ declare const messages: {
964
965
  open: string;
965
966
  close: string;
966
967
  };
968
+ cancel: string;
967
969
  close: string;
968
970
  title: string;
971
+ save: string;
969
972
  image: {
970
973
  altText: string;
971
974
  caption: string;
@@ -823,8 +823,10 @@ var messages = _objectSpread(_objectSpread({
823
823
  open: 'Åpne meny',
824
824
  close: 'Lukk meny'
825
825
  },
826
+ cancel: 'Avbryt',
826
827
  close: 'Lukk',
827
828
  title: 'Tittel',
829
+ save: 'Lagre',
828
830
  image: {
829
831
  altText: 'Alt-tekst',
830
832
  caption: 'Bilettekst',
@@ -954,7 +956,8 @@ var messages = _objectSpread(_objectSpread({
954
956
  folder: {
955
957
  folder: 'Mappe',
956
958
  "delete": 'Slett',
957
- edit: 'Rediger'
959
+ edit: 'Rediger',
960
+ missingName: 'Mappenavn er påkrevd'
958
961
  },
959
962
  confirmDeleteFolder: 'Er du sikker på at du vil slette mappen? Denne handlingen kan ikke angres.',
960
963
  confirmDeleteTag: 'Er du sikker på at du vil slette tag? Denne handlingen kan ikke angres.',
@@ -62,6 +62,7 @@ declare const messages: {
62
62
  folder: string;
63
63
  delete: string;
64
64
  edit: string;
65
+ missingName: string;
65
66
  };
66
67
  confirmDeleteFolder: string;
67
68
  confirmDeleteTag: string;
@@ -964,8 +965,10 @@ declare const messages: {
964
965
  open: string;
965
966
  close: string;
966
967
  };
968
+ cancel: string;
967
969
  close: string;
968
970
  title: string;
971
+ save: string;
969
972
  image: {
970
973
  altText: string;
971
974
  caption: string;
@@ -823,8 +823,10 @@ var messages = _objectSpread(_objectSpread({
823
823
  open: 'Åpne meny',
824
824
  close: 'Lukk meny'
825
825
  },
826
+ cancel: 'Avbryt',
826
827
  close: 'Lukk',
827
828
  title: 'Tittel',
829
+ save: 'Lagre',
828
830
  image: {
829
831
  altText: 'Alt-tekst',
830
832
  caption: 'Bilettekst',
@@ -954,7 +956,8 @@ var messages = _objectSpread(_objectSpread({
954
956
  folder: {
955
957
  folder: 'Mappe',
956
958
  "delete": 'Slett',
957
- edit: 'Rediger'
959
+ edit: 'Rediger',
960
+ missingName: 'Mappenavn er påkrevd'
958
961
  },
959
962
  confirmDeleteFolder: 'Er du sikker på at du vil slette mappen? Denne handlingen kan ikke angres.',
960
963
  confirmDeleteTag: 'Er du sikker på at du vil slette tag? Denne handlingen kan ikke angres.',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ndla/ui",
3
- "version": "19.1.0",
3
+ "version": "20.0.0",
4
4
  "description": "UI component library for NDLA.",
5
5
  "license": "GPL-3.0",
6
6
  "main": "lib/index.js",
@@ -31,17 +31,18 @@
31
31
  "types"
32
32
  ],
33
33
  "dependencies": {
34
- "@ndla/button": "^3.1.0",
35
- "@ndla/carousel": "^1.2.11",
34
+ "@ndla/button": "^3.1.3",
35
+ "@ndla/carousel": "^1.2.12",
36
36
  "@ndla/core": "^2.3.0",
37
+ "@ndla/forms": "^3.1.0",
37
38
  "@ndla/hooks": "^1.1.4",
38
- "@ndla/icons": "^1.10.0",
39
- "@ndla/licenses": "^5.0.2",
40
- "@ndla/modal": "^1.2.12",
41
- "@ndla/notion": "^3.1.20",
42
- "@ndla/safelink": "^2.1.1",
39
+ "@ndla/icons": "^1.11.0",
40
+ "@ndla/licenses": "^5.0.3",
41
+ "@ndla/modal": "^1.2.13",
42
+ "@ndla/notion": "^3.1.23",
43
+ "@ndla/safelink": "^2.2.1",
43
44
  "@ndla/switch": "^0.1.7",
44
- "@ndla/tabs": "^1.1.10",
45
+ "@ndla/tabs": "^1.1.11",
45
46
  "@ndla/tooltip": "^2.1.2",
46
47
  "@ndla/util": "^3.0.0",
47
48
  "@reach/menu-button": "^0.16.2",
@@ -81,5 +82,5 @@
81
82
  "publishConfig": {
82
83
  "access": "public"
83
84
  },
84
- "gitHead": "74b5027e25a33f81802c72b11901d59085bb290a"
85
+ "gitHead": "92e4a15ab1e19af2c7b1055f56f90f5c415f87e7"
85
86
  }
@@ -10,24 +10,17 @@ import styled from '@emotion/styled';
10
10
  import { IconButton } from '@ndla/button';
11
11
  import { FolderOutlined } from '@ndla/icons/contentType';
12
12
  import { Cross } from '@ndla/icons/action';
13
- import React, { ChangeEvent, KeyboardEvent, useEffect, useRef, useState } from 'react';
13
+ import React, { ChangeEvent, KeyboardEvent, useRef, useState } from 'react';
14
14
  import { useTranslation } from 'react-i18next';
15
15
  import { colors, spacing } from '@ndla/core';
16
+ import { Input } from '@ndla/forms';
17
+ import { css } from '@emotion/core';
16
18
 
17
19
  // Source: https://kovart.github.io/dashed-border-generator/
18
20
  const borderStyle = `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(
19
21
  colors.brand.tertiary,
20
22
  )}' stroke-width='2' stroke-dasharray='8%2c8' stroke-dashoffset='4' stroke-linecap='square'/%3e%3c/svg%3e")`;
21
23
 
22
- const FolderInputWrapper = styled.div`
23
- display: flex;
24
- flex-direction: row;
25
- align-items: center;
26
- padding: ${spacing.small};
27
-
28
- background-image: ${borderStyle};
29
- `;
30
-
31
24
  const StyledFolderIcon = styled.span`
32
25
  display: flex;
33
26
  padding: ${spacing.small};
@@ -38,29 +31,33 @@ const StyledFolderIcon = styled.span`
38
31
  }
39
32
  `;
40
33
 
41
- const StyledInput = styled.input`
42
- color: ${colors.brand.primary};
43
- outline: none;
34
+ const inputWrapperStyle = css`
35
+ padding: ${spacing.small};
36
+ background: none;
37
+ background-image: ${borderStyle};
44
38
  border: none;
45
- margin-right: auto;
46
- line-height: 1.75em;
39
+ `;
47
40
 
48
- ::selection {
49
- background: ${colors.brand.lighter};
41
+ const StyledInput = styled(Input)`
42
+ && {
43
+ line-height: 1.75em;
44
+ color: ${colors.brand.primary};
45
+ ::selection {
46
+ background: ${colors.brand.lighter};
47
+ }
50
48
  }
51
49
  `;
52
50
 
53
51
  interface Props {
54
52
  onAddFolder: (name: string) => void;
55
53
  onClose: () => void;
56
- autoFocus?: boolean;
54
+ autoSelect?: boolean;
57
55
  }
58
56
 
59
- const FolderInput = ({ onAddFolder, onClose, autoFocus }: Props) => {
57
+ const FolderInput = ({ onAddFolder, onClose, autoSelect }: Props) => {
60
58
  const { t } = useTranslation();
61
59
  const newFolderText = t('treeStructure.newFolder.defaultName');
62
60
  const [input, setInput] = useState<string>(newFolderText);
63
- const [mounted, setMounted] = useState(false);
64
61
  const inputRef = useRef<HTMLInputElement>(null);
65
62
 
66
63
  const handleInputChange = (e: ChangeEvent<HTMLInputElement>) => {
@@ -68,36 +65,36 @@ const FolderInput = ({ onAddFolder, onClose, autoFocus }: Props) => {
68
65
  };
69
66
 
70
67
  const onKeydown = (e: KeyboardEvent<HTMLInputElement>) => {
71
- if (e.key === 'Enter' && input) {
68
+ if (e.key === 'Enter' && input.trim()) {
72
69
  e.preventDefault();
73
70
  onAddFolder(input);
71
+ } else if (e.key === 'Escape') {
72
+ e.preventDefault();
73
+ onClose();
74
74
  }
75
75
  };
76
76
 
77
- useEffect(() => {
78
- if (mounted && autoFocus) {
79
- inputRef.current?.select();
80
- } else {
81
- setMounted(true);
82
- }
83
- }, [mounted, autoFocus]);
84
-
85
77
  return (
86
- <FolderInputWrapper>
87
- <StyledFolderIcon>
88
- <FolderOutlined />
89
- </StyledFolderIcon>
90
- <StyledInput
91
- ref={inputRef}
92
- value={input}
93
- onChange={handleInputChange}
94
- onKeyDown={onKeydown}
95
- aria-label={newFolderText}
96
- />
97
- <IconButton aria-label={t('close')} size="small" ghostPill onClick={onClose}>
98
- <Cross />
99
- </IconButton>
100
- </FolderInputWrapper>
78
+ <StyledInput
79
+ autoSelect={autoSelect}
80
+ customCss={inputWrapperStyle}
81
+ warningText={!input.trim() ? t('myNdla.folder.missingName') : undefined}
82
+ ref={inputRef}
83
+ value={input}
84
+ onChange={handleInputChange}
85
+ onKeyDown={onKeydown}
86
+ aria-label={newFolderText}
87
+ iconLeft={
88
+ <StyledFolderIcon>
89
+ <FolderOutlined />
90
+ </StyledFolderIcon>
91
+ }
92
+ iconRight={
93
+ <IconButton aria-label={t('close')} size="small" ghostPill onClick={onClose}>
94
+ <Cross />
95
+ </IconButton>
96
+ }
97
+ />
101
98
  );
102
99
  };
103
100
 
@@ -12,8 +12,8 @@ import styled from '@emotion/styled';
12
12
  import { css } from '@emotion/core';
13
13
  import { breakpoints, mq, spacing, spacingUnit, fonts, colors } from '@ndla/core';
14
14
  import SafeLink from '@ndla/safelink';
15
+ import { Spinner } from '@ndla/icons';
15
16
  import { OneColumn } from '../Layout';
16
- import Spinner from '../Spinner';
17
17
  import NavigationArrow, { StyledNavigationArrow } from './NavigationArrow';
18
18
  import SlideshowIndicator from './SlideshowIndicator';
19
19
  import { MovieType } from './types';
@@ -1,7 +1,7 @@
1
1
  import React from 'react';
2
2
  import styled from '@emotion/styled';
3
3
  import { spacing, spacingUnit, animations } from '@ndla/core';
4
- import Spinner from '../Spinner';
4
+ import { Spinner } from '@ndla/icons';
5
5
 
6
6
  const StyledWrapper = styled.div`
7
7
  position: absolute;
@@ -9,7 +9,7 @@ import Button from '@ndla/button';
9
9
  import { FilterTabs } from '@ndla/tabs';
10
10
  import Tooltip from '@ndla/tooltip';
11
11
  import SafeLink from '@ndla/safelink';
12
- import Spinner from '../../lib/Spinner';
12
+ import { Spinner } from '@ndla/icons';
13
13
 
14
14
  const resultClasses = BEMHelper('c-search-result');
15
15
 
@@ -9,7 +9,7 @@
9
9
  import React, { memo, ReactNode } from 'react';
10
10
  import styled from '@emotion/styled';
11
11
  import { spacing } from '@ndla/core';
12
- import Spinner from '../Spinner';
12
+ import { Spinner } from '@ndla/icons';
13
13
  import constants from '../model';
14
14
  import SearchTypeHeader, { FilterOptionsType } from './SearchTypeHeader';
15
15
  import SearchItems from './SearchItems';
@@ -6,13 +6,14 @@
6
6
  *
7
7
  */
8
8
 
9
- import React, { useEffect, useRef } from 'react';
9
+ import React, { KeyboardEvent, useEffect, useRef } from 'react';
10
10
  import styled from '@emotion/styled';
11
11
  import { ArrowDropDown } from '@ndla/icons/common';
12
12
  import { FolderOutlined } from '@ndla/icons/contentType';
13
13
  import { colors, spacing, misc, animations } from '@ndla/core';
14
14
  import SafeLink from '@ndla/safelink';
15
15
  import { SetFocusedFolderId, FolderChildFuncType } from './TreeStructure.types';
16
+ import { arrowNavigation } from './arrowNavigation';
16
17
 
17
18
  const OpenButton = styled.button<{ isOpen: boolean }>`
18
19
  background: transparent;
@@ -49,7 +50,10 @@ const WrapperForFolderChild = styled.div<{ marked: boolean }>`
49
50
  }
50
51
  `;
51
52
 
52
- const FolderName = styled.button<{ marked: boolean; noArrow?: boolean }>`
53
+ const FolderName = styled('button', { shouldForwardProp: (name) => !['marked', 'noArrow'].includes(name) })<{
54
+ marked: boolean;
55
+ noArrow?: boolean;
56
+ }>`
53
57
  line-height: 1;
54
58
  background: ${({ marked }) => (marked ? colors.brand.lighter : 'transparent')};
55
59
  color: ${colors.text.primary};
@@ -81,16 +85,19 @@ const FolderNameLink = FolderName.withComponent(SafeLink);
81
85
  interface Props {
82
86
  name: string;
83
87
  id: string;
84
- onToggleOpen: (id: string) => void;
88
+ level: number;
89
+ onCloseFolder: (id: string) => void;
90
+ onOpenFolder: (id: string) => void;
85
91
  onMarkFolder: (id: string) => void;
92
+ onSelectFolder?: (id: string) => void;
86
93
  isOpen: boolean;
87
94
  markedFolderId?: string;
88
95
  focusedFolderId?: string;
96
+ visibleFolders: string[];
89
97
  loading?: boolean;
90
98
  openOnFolderClick?: boolean;
91
99
  hideArrow?: boolean;
92
100
  setFocusedFolderId: SetFocusedFolderId;
93
- url?: string;
94
101
  icon?: React.ReactNode;
95
102
  noPaddingWhenArrowIsHidden?: boolean;
96
103
  folderChild?: FolderChildFuncType;
@@ -99,62 +106,61 @@ interface Props {
99
106
  const FolderItem = ({
100
107
  hideArrow,
101
108
  loading,
109
+ level,
102
110
  name,
103
111
  id,
104
- onToggleOpen,
112
+ visibleFolders,
113
+ onCloseFolder,
114
+ onOpenFolder,
105
115
  onMarkFolder,
116
+ onSelectFolder,
106
117
  isOpen,
107
118
  markedFolderId,
108
119
  focusedFolderId,
109
120
  openOnFolderClick,
110
121
  setFocusedFolderId,
111
122
  icon,
112
- url,
113
123
  noPaddingWhenArrowIsHidden,
114
124
  folderChild,
115
125
  }: Props) => {
116
- const folderNameLinkRef = useRef<HTMLAnchorElement | null>(null);
117
- const folderNameButtonRef = useRef<HTMLButtonElement | null>(null);
126
+ const ref = useRef<HTMLButtonElement & HTMLAnchorElement>(null);
127
+ const marked = markedFolderId === id;
128
+
129
+ const handleMarkFolder = () => {
130
+ onMarkFolder(id);
131
+ if (openOnFolderClick) {
132
+ if (isOpen) {
133
+ onCloseFolder(id);
134
+ } else {
135
+ onOpenFolder(id);
136
+ }
137
+ }
138
+ };
139
+
118
140
  useEffect(() => {
119
141
  if (focusedFolderId === id) {
120
- if (url && folderNameLinkRef.current) {
121
- folderNameLinkRef.current.focus();
122
- } else if (folderNameButtonRef.current) {
123
- folderNameButtonRef.current.focus();
142
+ if (ref.current) {
143
+ ref.current.focus();
124
144
  }
125
145
  }
126
- }, [focusedFolderId, folderNameLinkRef, folderNameButtonRef, url, id]);
127
- const marked = markedFolderId === id;
146
+ }, [focusedFolderId, ref, id]);
147
+
128
148
  return (
129
149
  <FolderItemWrapper>
130
150
  {!hideArrow && (
131
- <OpenButton tabIndex={-1} isOpen={isOpen} disabled={loading} onClick={() => onToggleOpen(id)}>
151
+ <OpenButton
152
+ tabIndex={-1}
153
+ isOpen={isOpen}
154
+ disabled={loading}
155
+ onClick={() => (isOpen ? onCloseFolder(id) : onOpenFolder(id))}>
132
156
  <ArrowDropDown />
133
157
  </OpenButton>
134
158
  )}
135
- {url ? (
136
- <FolderNameLink
137
- ref={folderNameLinkRef}
138
- noArrow={hideArrow}
139
- to={loading ? '' : url}
140
- tabIndex={marked ? 0 : -1}
141
- marked={marked}
142
- onFocus={() => {
143
- setFocusedFolderId(id);
144
- }}
145
- onClick={() => {
146
- onMarkFolder(id);
147
- if (openOnFolderClick) {
148
- onToggleOpen(id);
149
- }
150
- }}>
151
- {icon || <FolderOutlined />}
152
- {name}
153
- </FolderNameLink>
154
- ) : (
159
+ {onSelectFolder ? (
155
160
  <>
156
161
  <FolderName
157
- ref={folderNameButtonRef}
162
+ ref={ref}
163
+ onKeyDown={(e) => arrowNavigation(e, id, visibleFolders, setFocusedFolderId, onOpenFolder, onCloseFolder)}
158
164
  noArrow={hideArrow && !noPaddingWhenArrowIsHidden}
159
165
  tabIndex={marked ? 0 : -1}
160
166
  marked={marked}
@@ -163,10 +169,8 @@ const FolderItem = ({
163
169
  setFocusedFolderId(id);
164
170
  }}
165
171
  onClick={() => {
166
- onMarkFolder(id);
167
- if (openOnFolderClick) {
168
- onToggleOpen(id);
169
- }
172
+ handleMarkFolder();
173
+ onSelectFolder(id);
170
174
  }}>
171
175
  {icon || <FolderOutlined />}
172
176
  {name}
@@ -177,6 +181,25 @@ const FolderItem = ({
177
181
  </WrapperForFolderChild>
178
182
  )}
179
183
  </>
184
+ ) : (
185
+ <FolderNameLink
186
+ ref={ref}
187
+ onKeyDown={(e: KeyboardEvent<HTMLElement>) =>
188
+ arrowNavigation(e, id, visibleFolders, setFocusedFolderId, onOpenFolder, onCloseFolder)
189
+ }
190
+ noArrow={hideArrow}
191
+ to={loading ? '' : `/minndla/${level > 1 ? 'folders/' : ''}${id}`}
192
+ tabIndex={marked || level === 1 ? 0 : -1}
193
+ marked={marked}
194
+ onFocus={() => {
195
+ setFocusedFolderId(id);
196
+ }}
197
+ onClick={() => {
198
+ handleMarkFolder();
199
+ }}>
200
+ {icon || <FolderOutlined />}
201
+ {name}
202
+ </FolderNameLink>
180
203
  )}
181
204
  </FolderItemWrapper>
182
205
  );