@ndla/ui 6.0.0 → 6.1.2

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/lib/index.d.ts CHANGED
@@ -12,7 +12,7 @@ export { default as Table } from './Table';
12
12
  export { default as ResourcesWrapper, ResourcesTitle, ResourcesTopicTitle } from './ResourcesWrapper';
13
13
  export { createUniversalPortal } from './utils/createUniversalPortal';
14
14
  export { default as NoContentBox } from './NoContentBox';
15
- export { default as Masthead, MastheadItem, getMastheadHeight } from './Masthead';
15
+ export { default as Masthead, MastheadItem, getMastheadHeight, useMastheadHeight } from './Masthead';
16
16
  export { default as Portrait } from './Portrait';
17
17
  export { default as ContentLoader } from './ContentLoader';
18
18
  export { default as RelatedArticleList, RelatedArticle } from './RelatedArticleList';
package/lib/index.js CHANGED
@@ -24,6 +24,7 @@ var _exportNames = {
24
24
  Masthead: true,
25
25
  MastheadItem: true,
26
26
  getMastheadHeight: true,
27
+ useMastheadHeight: true,
27
28
  Portrait: true,
28
29
  ContentLoader: true,
29
30
  RelatedArticleList: true,
@@ -280,6 +281,12 @@ Object.defineProperty(exports, "getMastheadHeight", {
280
281
  return _Masthead.getMastheadHeight;
281
282
  }
282
283
  });
284
+ Object.defineProperty(exports, "useMastheadHeight", {
285
+ enumerable: true,
286
+ get: function get() {
287
+ return _Masthead.useMastheadHeight;
288
+ }
289
+ });
283
290
  Object.defineProperty(exports, "Portrait", {
284
291
  enumerable: true,
285
292
  get: function get() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ndla/ui",
3
- "version": "6.0.0",
3
+ "version": "6.1.2",
4
4
  "description": "UI component library for NDLA.",
5
5
  "license": "GPL-3.0",
6
6
  "main": "lib/index.js",
@@ -34,15 +34,15 @@
34
34
  "@ndla/button": "^2.1.2",
35
35
  "@ndla/carousel": "^1.2.2",
36
36
  "@ndla/core": "^2.0.0",
37
- "@ndla/hooks": "^1.1.1",
37
+ "@ndla/hooks": "^1.1.2",
38
38
  "@ndla/icons": "^1.6.1",
39
39
  "@ndla/licenses": "^4.0.1",
40
40
  "@ndla/modal": "^1.2.2",
41
- "@ndla/safelink": "^1.1.2",
41
+ "@ndla/safelink": "^1.1.3",
42
42
  "@ndla/switch": "^0.1.2",
43
- "@ndla/tabs": "^1.1.1",
43
+ "@ndla/tabs": "^1.1.2",
44
44
  "@ndla/tooltip": "^0.3.2",
45
- "@ndla/util": "^2.0.3",
45
+ "@ndla/util": "^2.0.4",
46
46
  "@reach/menu-button": "^0.16.2",
47
47
  "@reach/slider": "^0.16.0",
48
48
  "focus-trap-react": "^8.9.2",
@@ -81,5 +81,5 @@
81
81
  "publishConfig": {
82
82
  "access": "public"
83
83
  },
84
- "gitHead": "011253f838aa8a5d856c2909ba023eeec0e99ab8"
84
+ "gitHead": "6002d3517851d20c9b1c2ab5267d0c91ec74721b"
85
85
  }
@@ -19,12 +19,14 @@ import {
19
19
  import SafeLink from '@ndla/safelink';
20
20
  import { useTranslation } from 'react-i18next';
21
21
  import MessageBoxTag from '../MessageBox/MessageBoxTag';
22
+ import { useMastheadHeight } from '../Masthead';
22
23
 
23
24
  type WrapperProps = {
24
25
  startOffset?: number;
25
26
  isVisible?: boolean;
26
27
  leftAlign?: boolean;
27
28
  hideOnNarrow?: boolean;
29
+ mastheadHeight?: number;
28
30
  };
29
31
 
30
32
  type InvertItProps = {
@@ -46,11 +48,11 @@ const Wrapper = styled.div<WrapperProps>`
46
48
  width: 240px;
47
49
  position: fixed;
48
50
  left: 22px;
49
- top: 85px;
51
+ top: ${(props) => props.mastheadHeight || 85}px;
50
52
  ${(props) =>
51
53
  props.startOffset &&
52
54
  `
53
- top: calc(${props.startOffset}px + 85px);
55
+ top: calc(${props.startOffset}px + ${props.mastheadHeight || 85}px);
54
56
  `}
55
57
  }
56
58
  ${mq.range({ from: breakpoints.wide })} {
@@ -230,6 +232,8 @@ const Breadcrumblist = ({
230
232
  const [wrapperOffset, setWrapperOffset] = useState(startOffset);
231
233
  const [useScrollEvent, setUseScrollEvent] = useState(false);
232
234
 
235
+ const { height: mastheadHeight } = useMastheadHeight();
236
+
233
237
  useEffect(() => {
234
238
  const handleScroll = () => {
235
239
  let position = 0;
@@ -270,7 +274,12 @@ const Breadcrumblist = ({
270
274
 
271
275
  return (
272
276
  <>
273
- <Wrapper leftAlign={leftAlign} startOffset={wrapperOffset} hideOnNarrow={hideOnNarrow} isVisible={isVisible}>
277
+ <Wrapper
278
+ leftAlign={leftAlign}
279
+ startOffset={wrapperOffset}
280
+ hideOnNarrow={hideOnNarrow}
281
+ isVisible={isVisible}
282
+ mastheadHeight={mastheadHeight}>
274
283
  {items.length > 0 && (
275
284
  <>
276
285
  <Heading invertedStyle={invertedStyle}>{t('breadcrumb.youAreHere')}</Heading>
@@ -6,7 +6,7 @@
6
6
  *
7
7
  */
8
8
 
9
- import React, { ReactNode, MouseEvent, useState } from 'react';
9
+ import React, { ReactNode, MouseEvent } from 'react';
10
10
  import BEMHelper from 'react-bem-helper';
11
11
  import Button from '@ndla/button';
12
12
  import { useTranslation } from 'react-i18next';
@@ -21,23 +21,21 @@ interface Props {
21
21
  children?: ReactNode;
22
22
  }
23
23
 
24
+ const toggleFactBox = (event: MouseEvent<HTMLButtonElement>) => {
25
+ const button = event.currentTarget;
26
+ const aside = button?.previousSibling?.parentElement;
27
+ aside?.classList?.toggle('expanded');
28
+ };
24
29
  const FactBox = ({ children, dangerouslySetInnerHTML }: Props) => {
25
- const [open, setOpen] = useState(false);
26
30
  const { t } = useTranslation();
27
31
 
28
- const toggleFactBox = (event: MouseEvent<HTMLButtonElement>) => {
29
- const button = event.currentTarget;
30
- const aside = button?.previousSibling?.parentElement;
31
- aside?.classList?.toggle('expanded');
32
- setOpen((prev) => !prev);
33
- };
34
-
35
32
  return (
36
33
  <aside {...classes()}>
37
34
  <div {...classes('content')} dangerouslySetInnerHTML={dangerouslySetInnerHTML}>
38
35
  {children}
39
36
  </div>
40
- <Button {...classes('button')} onClick={toggleFactBox} title={t(open ? 'factbox.close' : 'factbox.open')} />
37
+ <Button {...classes('button', 'collapsed')} onClick={toggleFactBox} title={t('factbox.open')} />
38
+ <Button {...classes('button', 'open')} onClick={toggleFactBox} title={t('factbox.close')} />
41
39
  </aside>
42
40
  );
43
41
  };
@@ -82,8 +82,20 @@ $padding-bottom: 17px;
82
82
  transform: rotate(180deg);
83
83
  top: 38%;
84
84
  }
85
+ &__button--open {
86
+ visibility: visible;
87
+ }
88
+ &__button--collapsed {
89
+ visibility: hidden;
90
+ }
85
91
  }
86
92
  }
93
+ &__button--open {
94
+ visibility: hidden;
95
+ }
96
+ &__button--collapsed {
97
+ visibility: visible;
98
+ }
87
99
 
88
100
  &__button {
89
101
  position: absolute;
@@ -144,6 +144,13 @@ const FrontpageSearch = ({
144
144
  }, [inputHasFocus]);
145
145
 
146
146
  const onBlur = () => {
147
+ setTimeout(() => {
148
+ if (searchFieldRef.current) {
149
+ if (!searchFieldRef.current.contains(document.activeElement)) {
150
+ onInputBlur();
151
+ }
152
+ }
153
+ }, 0);
147
154
  // This is needed when user tabs out of field
148
155
  if (!searchFieldValue) {
149
156
  onInputBlur();
@@ -8,8 +8,8 @@
8
8
 
9
9
  import Masthead, { MastheadItem } from './Masthead';
10
10
 
11
- import { getMastheadHeight } from './utils';
11
+ import { getMastheadHeight, useMastheadHeight } from './utils';
12
12
 
13
- export { MastheadItem, getMastheadHeight };
13
+ export { MastheadItem, getMastheadHeight, useMastheadHeight };
14
14
 
15
15
  export default Masthead;
@@ -6,7 +6,40 @@
6
6
  *
7
7
  */
8
8
 
9
+ import { useEffect, useState } from 'react';
10
+ import { resizeObserver } from '@ndla/util';
11
+
9
12
  export const getMastheadHeight = (): number | undefined => {
10
- const masthead = document.getElementById('masthead');
11
- return masthead?.getBoundingClientRect().height;
13
+ if (typeof window !== 'undefined') {
14
+ const masthead = document.getElementById('masthead');
15
+ return masthead?.getBoundingClientRect().height;
16
+ }
17
+ };
18
+
19
+ export const useMastheadHeight = () => {
20
+ const [height, setHeight] = useState<number>();
21
+ const [mounted, setMounted] = useState(false);
22
+
23
+ useEffect(() => {
24
+ setMounted(true);
25
+ }, []);
26
+
27
+ useEffect(() => {
28
+ if (mounted) {
29
+ const masthead = document.getElementById('masthead');
30
+
31
+ const handleHeightChange = (el: HTMLElement) => {
32
+ const newHeight = el.getBoundingClientRect().height;
33
+ setHeight(newHeight);
34
+ };
35
+
36
+ if (masthead) {
37
+ resizeObserver(masthead, handleHeightChange);
38
+ }
39
+ }
40
+ }, [mounted]);
41
+
42
+ return {
43
+ height,
44
+ };
12
45
  };
@@ -130,6 +130,7 @@ const ContentTypeResult = ({
130
130
  return (
131
131
  <StyledListItem key={path} delayAnimation={delayAnimation}>
132
132
  <SafeLink
133
+ tabIndex={-1}
133
134
  css={shouldHighlight && highlightStyle}
134
135
  data-highlighted={shouldHighlight || false}
135
136
  {...linkProps}
@@ -153,7 +154,8 @@ const ContentTypeResult = ({
153
154
  ghostPill
154
155
  css={[showAllButtonStyle, shouldHighlightShowAllButton && noWidthhighlightStyle]}
155
156
  data-highlighted={shouldHighlightShowAllButton}
156
- onClick={() => toggleShowAll(!showAll)}>
157
+ onClick={() => toggleShowAll(!showAll)}
158
+ tabIndex={-1}>
157
159
  {showAll ? messages.showLessResultLabel : messages.allResultLabel}
158
160
  {showAll ? <ChevronUp /> : <ChevronDown />}
159
161
  </Button>
@@ -123,7 +123,8 @@ const SearchField = ({
123
123
  if (inputRef) {
124
124
  inputRef.current.focus();
125
125
  }
126
- }}>
126
+ }}
127
+ onBlur={onBlur}>
127
128
  {t('welcomePage.resetSearch')}
128
129
  </button>
129
130
  )}
@@ -315,13 +315,19 @@ const SearchResultSleeve = ({
315
315
  )}
316
316
  <div>
317
317
  <SearchLinkContainer>
318
- <StyledSearchLink css={keyboardPathNavigation === GO_TO_SEARCHPAGE && highlightStyle} to={allResultUrl}>
318
+ <StyledSearchLink
319
+ css={keyboardPathNavigation === GO_TO_SEARCHPAGE && highlightStyle}
320
+ to={allResultUrl}
321
+ tabIndex={-1}>
319
322
  <SearchIcon className="c-icon--22" />
320
323
  <strong ref={searchAllRef}>{searchString}</strong>
321
324
  <small>{t('welcomePage.searchAllInfo')}</small>
322
325
  </StyledSearchLink>
323
326
  {suggestion && suggestionUrl && (
324
- <StyledSearchLink css={keyboardPathNavigation === GO_TO_SUGGESTION && highlightStyle} to={suggestionUrl}>
327
+ <StyledSearchLink
328
+ css={keyboardPathNavigation === GO_TO_SUGGESTION && highlightStyle}
329
+ to={suggestionUrl}
330
+ tabIndex={-1}>
325
331
  <SearchIcon className="c-icon--22" />
326
332
  <small>{t('searchPage.resultType.searchPhraseSuggestion')}</small>
327
333
  <strong ref={searchSuggestionRef}>{suggestion}</strong>
package/src/index.ts CHANGED
@@ -32,7 +32,7 @@ export { createUniversalPortal } from './utils/createUniversalPortal';
32
32
 
33
33
  export { default as NoContentBox } from './NoContentBox';
34
34
 
35
- export { default as Masthead, MastheadItem, getMastheadHeight } from './Masthead';
35
+ export { default as Masthead, MastheadItem, getMastheadHeight, useMastheadHeight } from './Masthead';
36
36
 
37
37
  export { default as Portrait } from './Portrait';
38
38