@ndla/ui 34.6.6 → 35.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ndla/ui",
3
- "version": "34.6.6",
3
+ "version": "35.0.0",
4
4
  "description": "UI component library for NDLA.",
5
5
  "license": "GPL-3.0",
6
6
  "main": "lib/index.js",
@@ -32,16 +32,16 @@
32
32
  ],
33
33
  "dependencies": {
34
34
  "@ndla/article-scripts": "^3.0.15",
35
- "@ndla/button": "^9.1.4",
35
+ "@ndla/button": "^10.0.0",
36
36
  "@ndla/carousel": "^3.0.3",
37
37
  "@ndla/core": "^3.1.2",
38
- "@ndla/forms": "^4.2.7",
38
+ "@ndla/forms": "^4.2.8",
39
39
  "@ndla/hooks": "^2.0.2",
40
40
  "@ndla/icons": "^2.2.3",
41
41
  "@ndla/licenses": "^7.0.1",
42
42
  "@ndla/modal": "^2.2.7",
43
- "@ndla/notion": "^4.2.4",
44
- "@ndla/safelink": "^4.0.9",
43
+ "@ndla/notion": "^4.2.5",
44
+ "@ndla/safelink": "^4.0.10",
45
45
  "@ndla/switch": "^1.0.7",
46
46
  "@ndla/tabs": "^2.1.8",
47
47
  "@ndla/tooltip": "^4.0.10",
@@ -87,5 +87,5 @@
87
87
  "publishConfig": {
88
88
  "access": "public"
89
89
  },
90
- "gitHead": "662adf62096bf0099d342cf51f13060da39ff2bb"
90
+ "gitHead": "908efc9af085f4cd4ef3533250956ab2c66cb570"
91
91
  }
@@ -69,6 +69,8 @@ const BrightcoveEmbed = ({ embed, isConcept }: Props) => {
69
69
  if (iframe) {
70
70
  const [width, height] = [parseInt(iframe.width), parseInt(iframe.height)];
71
71
  iframe.style.aspectRatio = `${width}/${height}`;
72
+ iframe.width = '';
73
+ iframe.height = '';
72
74
  }
73
75
  }, []);
74
76
  if (embed.status === 'error') {
@@ -34,6 +34,8 @@ const ExternalEmbed = ({ embed, isConcept }: Props) => {
34
34
  if (iframe) {
35
35
  const [width, height] = [parseInt(iframe.width), parseInt(iframe.height)];
36
36
  iframe.style.aspectRatio = `${width ? width : 16}/${height ? height : 9}`;
37
+ iframe.width = '';
38
+ iframe.height = '';
37
39
  }
38
40
  }, []);
39
41
  if (embed.status === 'error') {
@@ -8,7 +8,7 @@
8
8
 
9
9
  import styled from '@emotion/styled';
10
10
  import { H5pMetaData } from '@ndla/types-embed';
11
- import { useEffect, useRef } from 'react';
11
+ import React from 'react';
12
12
  import { useTranslation } from 'react-i18next';
13
13
  import { errorSvgSrc } from './ImageEmbed';
14
14
 
@@ -26,18 +26,6 @@ const StyledFigure = styled.figure`
26
26
  const H5pEmbed = ({ embed, isConcept }: Props) => {
27
27
  const { t } = useTranslation();
28
28
 
29
- const iframeRef = useRef<HTMLIFrameElement>(null);
30
- const figRef = useRef<HTMLElement>(null);
31
-
32
- useEffect(() => {
33
- const iframe =
34
- embed.status === 'success' && embed.data.oembed ? figRef.current?.querySelector('iframe') : iframeRef.current;
35
- if (iframe) {
36
- const [width, height] = [parseInt(iframe.width), parseInt(iframe.height)];
37
- iframe.style.aspectRatio = `${width ? width : 16}/${height ? height : 9}`;
38
- }
39
- }, [embed]);
40
-
41
29
  if (embed.status === 'error') {
42
30
  return (
43
31
  <figure className={isConcept ? '' : 'c-figure'}>
@@ -50,23 +38,12 @@ const H5pEmbed = ({ embed, isConcept }: Props) => {
50
38
  const classes = `c-figure ${fullColumnClass} c-figure--resize`;
51
39
 
52
40
  if (embed.data.oembed) {
53
- return (
54
- <StyledFigure
55
- className={classes}
56
- ref={figRef}
57
- //@ts-ignore
58
- // eslint-disable-next-line react/no-unknown-property
59
- resizeiframe="true"
60
- dangerouslySetInnerHTML={{ __html: embed.data.oembed.html ?? '' }}
61
- />
62
- );
41
+ return <StyledFigure className={classes} dangerouslySetInnerHTML={{ __html: embed.data.oembed.html ?? '' }} />;
63
42
  }
64
43
 
65
44
  return (
66
- //@ts-ignore
67
- // eslint-disable-next-line react/no-unknown-property
68
- <StyledFigure className={classes} resizeiframe="true">
69
- <iframe title={embed.embedData.url} ref={iframeRef} aria-label={embed.embedData.url} src={embed.embedData.url} />
45
+ <StyledFigure className={classes}>
46
+ <iframe title={embed.embedData.url} aria-label={embed.embedData.url} src={embed.embedData.url} />
70
47
  </StyledFigure>
71
48
  );
72
49
  };
@@ -29,6 +29,8 @@ const ExternalEmbed = ({ embed, isConcept }: Props) => {
29
29
  if (iframe) {
30
30
  const [width, height] = [parseInt(iframe.width), parseInt(iframe.height)];
31
31
  iframe.style.aspectRatio = `${width ? width : 16}/${height ? height : 9}`;
32
+ iframe.width = '';
33
+ iframe.height = '';
32
34
  }
33
35
  }, []);
34
36
 
@@ -255,6 +255,8 @@ export const ConceptNotionV2 = forwardRef<HTMLDivElement, ConceptNotionProps>(
255
255
  if (iframe) {
256
256
  const [width, height] = [parseInt(iframe.width), parseInt(iframe.height)];
257
257
  iframe.style.aspectRatio = `${width ? width : 16}/${height ? height : 9}`;
258
+ iframe.width = '';
259
+ iframe.height = '';
258
260
  }
259
261
  }, []);
260
262
 
@@ -10,6 +10,7 @@ import { useTranslation } from 'react-i18next';
10
10
  import styled from '@emotion/styled';
11
11
  import { breakpoints, fonts, mq, spacing } from '@ndla/core';
12
12
  import { ButtonV2 } from '@ndla/button';
13
+ import { Spinner } from '@ndla/icons';
13
14
 
14
15
  import SearchFieldHeader from './SearchFieldHeader';
15
16
  import { CompetenceGoalsItemType } from '../types';
@@ -71,6 +72,7 @@ type Props = {
71
72
  onSearchValueChange: (value: string) => void;
72
73
  onSubmit: (event: FormEvent<HTMLFormElement>) => void;
73
74
  noResults?: boolean;
75
+ loading: boolean;
74
76
  };
75
77
 
76
78
  const SearchHeader = ({
@@ -84,6 +86,7 @@ const SearchHeader = ({
84
86
  filters,
85
87
  competenceGoals,
86
88
  noResults,
89
+ loading,
87
90
  }: Props) => {
88
91
  const { t } = useTranslation();
89
92
  const [isNarrowScreen, setIsNarrowScreen] = useState<boolean | undefined>();
@@ -122,12 +125,15 @@ const SearchHeader = ({
122
125
  />
123
126
  </SearchInputWrapper>
124
127
  <PhraseWrapper>
125
- {searchPhrase && (
126
- <>
127
- <PhraseText>{phraseText}</PhraseText>
128
- {removeFilterSuggestion && <PhraseText>{removeFilterSuggestion}</PhraseText>}
129
- </>
130
- )}
128
+ <div aria-live="assertive">
129
+ {!loading && searchPhrase && (
130
+ <>
131
+ <PhraseText>{phraseText}</PhraseText>
132
+ <PhraseText>{removeFilterSuggestion}</PhraseText>
133
+ </>
134
+ )}
135
+ {loading && <div aria-label={t('loading')} />}
136
+ </div>
131
137
  {searchPhraseSuggestion && (
132
138
  <PhraseSuggestionText>
133
139
  {t('searchPage.resultType.searchPhraseSuggestion')}{' '}
@@ -43,6 +43,12 @@ const Container = styled.article`
43
43
  }
44
44
  `;
45
45
 
46
+ const ButtonWrapper = styled.div`
47
+ z-index: 1;
48
+ display: flex;
49
+ flex-direction: column;
50
+ `;
51
+
46
52
  const ItemTitle = styled.h3<ItemTypeProps>`
47
53
  display: inline;
48
54
  ${fonts.sizes('24px', '28px')};
@@ -87,6 +93,10 @@ const ContentWrapper = styled.main`
87
93
  padding: ${spacing.small} ${spacing.normal};
88
94
  `;
89
95
 
96
+ const ButtonContainer = styled.div`
97
+ z-index: 1;
98
+ `;
99
+
90
100
  export interface SearchItemProps {
91
101
  id: string | number;
92
102
  title: string;
@@ -105,7 +115,7 @@ export interface SearchItemType {
105
115
  }
106
116
 
107
117
  const SearchItem = ({ item, type }: SearchItemType) => {
108
- const { title, url, ingress, contexts = [], img = null, labels = [] } = item;
118
+ const { title, url, ingress, contexts = [], img = null, labels = [], children } = item;
109
119
  const linkRef = useRef<HTMLAnchorElement>(null);
110
120
 
111
121
  const isTopic = type === contentTypes.TOPIC || type === contentTypes.MULTIDISCIPLINARY_TOPIC;
@@ -130,6 +140,7 @@ const SearchItem = ({ item, type }: SearchItemType) => {
130
140
  <ItemText isTopic={isTopic}>{parse(ingress)}</ItemText>
131
141
  {contexts.length > 0 && <ItemContexts contexts={contexts} id={item.id} title={item.title} />}
132
142
  </ContentWrapper>
143
+ <ButtonWrapper>{children}</ButtonWrapper>
133
144
  </Container>
134
145
  );
135
146
  };