@eeacms/volto-hero-block 5.3.0 → 5.4.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/CHANGELOG.md CHANGED
@@ -4,6 +4,30 @@ All notable changes to this project will be documented in this file. Dates are d
4
4
 
5
5
  Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
6
6
 
7
+ ### [5.4.0](https://github.com/eea/volto-hero-block/compare/5.3.1...5.4.0) - 12 June 2023
8
+
9
+ #### :house: Internal changes
10
+
11
+
12
+ #### :hammer_and_wrench: Others
13
+
14
+ - Release 5.4.0 [Alin Voinea - [`1b54e52`](https://github.com/eea/volto-hero-block/commit/1b54e52ad0f3185917d19015220037efb407422c)]
15
+ - test: jest should look for addons in node_modules Refs #253277 [valentinab25 - [`531ac2a`](https://github.com/eea/volto-hero-block/commit/531ac2a53eec82921d21d2606553580597fc8c82)]
16
+ - test: Add cypress test for basic functionality and demo gif to README - refs #253277 [ana-oprea - [`9f8cd97`](https://github.com/eea/volto-hero-block/commit/9f8cd978e1cd776f44be1adc23aae19cf1efda49)]
17
+ - test: Add unit tests for Hero, Copyright and helpers - refs #253277 [ana-oprea - [`3949378`](https://github.com/eea/volto-hero-block/commit/3949378060a7eb373e8ded529f7047d5c5a60aa9)]
18
+ - test: Fix test config, coverage Refs #253277 [valentinab25 - [`33c1d94`](https://github.com/eea/volto-hero-block/commit/33c1d949c32b69556c05a74cc28ed9aef4112f83)]
19
+ - merge develop into this branch [Miu Razvan - [`cc1cda3`](https://github.com/eea/volto-hero-block/commit/cc1cda3edcbd2c2cbbdda8a3ec03d7084b6eca5c)]
20
+ - clean up [Miu Razvan - [`2a51fcf`](https://github.com/eea/volto-hero-block/commit/2a51fcf5a79a6497a3f7609216efe944c45a0af0)]
21
+ - other: update getFieldURL function [Miu Razvan - [`8c9ee98`](https://github.com/eea/volto-hero-block/commit/8c9ee980e898cb09a553f5956871c0b285c80280)]
22
+ - update with getFieldURL on buttonLink [tedw87 - [`4d1fd61`](https://github.com/eea/volto-hero-block/commit/4d1fd61faba366a96a54c23e67d7d306364924fe)]
23
+ - refactor code [tedw87 - [`0bf669d`](https://github.com/eea/volto-hero-block/commit/0bf669d7d150d1b9e33ff6e727d6cf47f6d4871e)]
24
+ ### [5.3.1](https://github.com/eea/volto-hero-block/compare/5.3.0...5.3.1) - 22 May 2023
25
+
26
+ #### :hammer_and_wrench: Others
27
+
28
+ - put return statement [Dobricean Ioan Dorian - [`8eff5fd`](https://github.com/eea/volto-hero-block/commit/8eff5fdf977fcbb8cc952d3f45b577b02ca59cb9)]
29
+ - change name and refactor to be more efficent [Dobricean Ioan Dorian - [`ff24145`](https://github.com/eea/volto-hero-block/commit/ff2414542833998ef282376de3fbda8698287849)]
30
+ - stop-image-disappear over and over [Dobricean Ioan Dorian - [`c5b6f54`](https://github.com/eea/volto-hero-block/commit/c5b6f545ac422d95b8d802349aa4cf27af820829)]
7
31
  ### [5.3.0](https://github.com/eea/volto-hero-block/compare/5.2.0...5.3.0) - 27 March 2023
8
32
 
9
33
  #### :rocket: New Features
package/README.md CHANGED
@@ -19,7 +19,7 @@ Enhanced Hero Block [Volto](https://github.com/plone/volto) add-on
19
19
 
20
20
  ## Features
21
21
 
22
- Demo GIF
22
+ ![Hero Block](https://github.com/eea/volto-hero-block/raw/docs/docs/volto-hero.gif)
23
23
 
24
24
  ## Upgrade
25
25
 
@@ -5,19 +5,19 @@ module.exports = {
5
5
  '!src/**/*.d.ts',
6
6
  ],
7
7
  moduleNameMapper: {
8
+ '\\.(css|less|scss|sass)$': 'identity-obj-proxy',
8
9
  '@plone/volto/cypress': '<rootDir>/node_modules/@plone/volto/cypress',
9
10
  '@plone/volto/babel': '<rootDir>/node_modules/@plone/volto/babel',
10
11
  '@plone/volto/(.*)$': '<rootDir>/node_modules/@plone/volto/src/$1',
11
12
  '@package/(.*)$': '<rootDir>/src/$1',
12
13
  '@root/(.*)$': '<rootDir>/src/$1',
13
14
  '@plone/volto-quanta/(.*)$': '<rootDir>/src/addons/volto-quanta/src/$1',
14
- '@eeacms/(.*?)/(.*)$': '<rootDir>/src/addons/$1/src/$2',
15
+ '@eeacms/(.*?)/(.*)$': '<rootDir>/node_modules/@eeacms/$1/src/$2',
15
16
  '@plone/volto-slate':
16
17
  '<rootDir>/node_modules/@plone/volto/packages/volto-slate/src',
17
18
  '~/(.*)$': '<rootDir>/src/$1',
18
19
  'load-volto-addons':
19
20
  '<rootDir>/node_modules/@plone/volto/jest-addons-loader.js',
20
- '\\.(css|less|scss|sass)$': 'identity-obj-proxy',
21
21
  },
22
22
  transform: {
23
23
  '^.+\\.js(x)?$': 'babel-jest',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eeacms/volto-hero-block",
3
- "version": "5.3.0",
3
+ "version": "5.4.0",
4
4
  "description": "@eeacms/volto-hero-block: Volto add-on",
5
5
  "main": "src/index.js",
6
6
  "author": "European Environment Agency: IDM2 A-Team",
@@ -0,0 +1,35 @@
1
+ import React from 'react';
2
+ import renderer from 'react-test-renderer';
3
+ import Copyright from './Copyright';
4
+ import { Icon } from 'semantic-ui-react';
5
+ import { Provider } from 'react-intl-redux';
6
+ import configureStore from 'redux-mock-store';
7
+ import config from '@plone/volto/registry';
8
+
9
+ const mockStore = configureStore();
10
+
11
+ test('renders copyright', () => {
12
+ const store = mockStore({
13
+ intl: {
14
+ locale: 'en',
15
+ messages: {},
16
+ },
17
+ });
18
+ const copyrightPrefix =
19
+ config.blocks.blocksConfig.hero?.copyrightPrefix || '';
20
+
21
+ const component = renderer.create(
22
+ <Provider store={store}>
23
+ <Copyright copyrightPosition={'left'}>
24
+ <Copyright.Prefix>{copyrightPrefix}</Copyright.Prefix>
25
+ <Copyright.Icon>
26
+ <Icon className={'copyright outline'} />
27
+ </Copyright.Icon>
28
+ <Copyright.Text>Copyright Text Test</Copyright.Text>
29
+ </Copyright>
30
+ </Provider>,
31
+ );
32
+
33
+ const json = component.toJSON();
34
+ expect(json).toMatchSnapshot();
35
+ });
@@ -18,11 +18,13 @@ import {
18
18
  } from '@plone/volto-slate/actions';
19
19
 
20
20
  import { createSlateHeader } from '@eeacms/volto-hero-block/helpers';
21
+ import { getFieldURL } from '@eeacms/volto-hero-block/helpers';
21
22
 
22
23
  import Copyright from './Copyright';
23
24
  import Hero from './Hero';
24
25
 
25
- const Metadata = ({ buttonLabel, buttonLink, inverted, styles }) => {
26
+ const Metadata = ({ buttonLabel, inverted, styles, ...props }) => {
27
+ const buttonLink = getFieldURL(props.buttonLink);
26
28
  const { buttonVariant } = styles || {};
27
29
 
28
30
  return buttonLabel ? (
@@ -2,8 +2,8 @@ import React from 'react';
2
2
  import cx from 'classnames';
3
3
  import PropTypes from 'prop-types';
4
4
  import { isInternalURL } from '@plone/volto/helpers/Url/Url';
5
- import { isImageGif } from '@eeacms/volto-hero-block/helpers';
6
- import { useOnScreen } from '@eeacms/volto-hero-block/hooks';
5
+ import { isImageGif, getFieldURL } from '@eeacms/volto-hero-block/helpers';
6
+ import { useFirstVisited } from '@eeacms/volto-hero-block/hooks';
7
7
 
8
8
  Hero.propTypes = {
9
9
  image: PropTypes.string,
@@ -19,7 +19,6 @@ Hero.propTypes = {
19
19
  };
20
20
 
21
21
  function Hero({
22
- image,
23
22
  overlay = true,
24
23
  fullWidth = true,
25
24
  fullHeight = true,
@@ -27,13 +26,15 @@ function Hero({
27
26
  spaced = false,
28
27
  inverted = true,
29
28
  styles,
29
+ ...props
30
30
  }) {
31
+ const image = getFieldURL(props.image);
31
32
  const isExternal = !isInternalURL(image);
32
33
  const { alignContent = 'center', backgroundVariant = 'primary' } =
33
34
  styles || {};
34
35
 
35
36
  const bgImgRef = React.useRef();
36
- const onScreen = useOnScreen(bgImgRef);
37
+ const onScreen = useFirstVisited(bgImgRef);
37
38
  return (
38
39
  <div
39
40
  className={cx(
@@ -0,0 +1,40 @@
1
+ import React from 'react';
2
+ import renderer from 'react-test-renderer';
3
+ import Hero from './Hero';
4
+ import { Provider } from 'react-intl-redux';
5
+ import configureStore from 'redux-mock-store';
6
+
7
+ const mockStore = configureStore();
8
+
9
+ test('renders a hero component', () => {
10
+ const store = mockStore({
11
+ intl: {
12
+ locale: 'en',
13
+ messages: {},
14
+ },
15
+ });
16
+ const component = renderer.create(
17
+ <Provider store={store}>
18
+ <Hero
19
+ image=""
20
+ overlay={true}
21
+ fullWidth={true}
22
+ fullHeight={true}
23
+ spaced={false}
24
+ inverted={true}
25
+ styles={{ alignContent: 'center', backgroundVariant: 'primary' }}
26
+ >
27
+ <Hero.Text
28
+ quoted={false}
29
+ styles={{ textVariant: 'white', textAlign: 'left' }}
30
+ >
31
+ Text test
32
+ </Hero.Text>
33
+ <Hero.Meta styles={{ buttonAlign: 'left' }}>Test meta</Hero.Meta>
34
+ </Hero>
35
+ </Provider>,
36
+ );
37
+
38
+ const json = component.toJSON();
39
+ expect(json).toMatchSnapshot();
40
+ });
@@ -6,9 +6,11 @@ import { BodyClass } from '@plone/volto/helpers';
6
6
  import Hero from './Hero';
7
7
  import Copyright from './Copyright';
8
8
  import { serializeText } from '@eeacms/volto-hero-block/helpers';
9
+ import { getFieldURL } from '@eeacms/volto-hero-block/helpers';
9
10
  import config from '@plone/volto/registry';
10
11
 
11
- const Metadata = ({ buttonLabel, buttonLink, inverted, styles }) => {
12
+ const Metadata = ({ buttonLabel, inverted, styles, ...props }) => {
13
+ const buttonLink = getFieldURL(props.buttonLink);
12
14
  const { buttonVariant = 'white' } = styles || {};
13
15
 
14
16
  return buttonLabel ? (
@@ -84,6 +84,18 @@ export default () => {
84
84
  },
85
85
  copyrightIcon: {
86
86
  title: 'Icon',
87
+ description: (
88
+ <>
89
+ Ex. ri-copyright-line. See{' '}
90
+ <a
91
+ target="_blank"
92
+ rel="noopener noreferrer"
93
+ href="https://remixicon.com/"
94
+ >
95
+ Remix Icon set
96
+ </a>
97
+ </>
98
+ ),
87
99
  default: 'ri-copyright-line',
88
100
  },
89
101
  copyrightPosition: {
package/src/helpers.js CHANGED
@@ -1,5 +1,23 @@
1
- import { isArray } from 'lodash';
2
1
  import { serializeNodes } from '@plone/volto-slate/editor/render';
2
+ import isArray from 'lodash/isArray';
3
+ import isObject from 'lodash/isObject';
4
+ import isString from 'lodash/isString';
5
+ import { isInternalURL, flattenToAppURL } from '@plone/volto/helpers';
6
+
7
+ export const getFieldURL = (data) => {
8
+ let url = data;
9
+ const _isObject = data && isObject(data) && !isArray(data);
10
+ if (_isObject && data['@type'] === 'URL') {
11
+ url = data['value'] ?? data['url'] ?? data['href'] ?? data;
12
+ } else if (_isObject) {
13
+ url = data['@id'] ?? data['url'] ?? data['href'] ?? data;
14
+ }
15
+ if (isArray(data)) {
16
+ url = data.map((item) => getFieldURL(item));
17
+ }
18
+ if (isString(url) && isInternalURL(url)) return flattenToAppURL(url);
19
+ return url;
20
+ };
3
21
 
4
22
  const createEmptyHeader = () => {
5
23
  return {
@@ -0,0 +1,66 @@
1
+ import { createSlateHeader, serializeText, isImageGif } from './helpers';
2
+ import { isArray } from 'lodash';
3
+ import { serializeNodes } from '@plone/volto-slate/editor/render';
4
+
5
+ jest.mock('@plone/volto-slate/editor/render', () => ({
6
+ serializeNodes: jest.fn(),
7
+ }));
8
+
9
+ describe('createSlateHeader', () => {
10
+ it('should return the text if it is an array', () => {
11
+ const text = ['some', 'text'];
12
+ expect(createSlateHeader(text)).toEqual(text);
13
+ });
14
+
15
+ it('should return an array with an empty header if the text is not an array', () => {
16
+ const text = 'some text';
17
+ expect(createSlateHeader(text)).toEqual([
18
+ {
19
+ type: 'h2',
20
+ children: [{ text: '' }],
21
+ },
22
+ ]);
23
+ });
24
+ });
25
+
26
+ describe('serializeText', () => {
27
+ it('should return the text when it is not an array', () => {
28
+ const text = 'Hello, World!';
29
+
30
+ expect(serializeText(text)).toEqual(text);
31
+ expect(isArray(text)).toBe(false);
32
+ expect(serializeNodes).not.toHaveBeenCalled();
33
+ });
34
+
35
+ it('should call serializeNodes when text is an array', () => {
36
+ const text = ['Hello', 'World!'];
37
+
38
+ serializeText(text);
39
+ expect(isArray(text)).toBe(true);
40
+ expect(serializeNodes).toHaveBeenCalledWith(text);
41
+ });
42
+ });
43
+
44
+ describe('isImageGif', () => {
45
+ it('should return true when input is a gif image', () => {
46
+ const input = 'image.gif';
47
+ const result = isImageGif(input);
48
+ expect(result).toBeTruthy();
49
+ });
50
+
51
+ it('should return false when input is not a gif image', () => {
52
+ const input = 'image.jpg';
53
+ const result = isImageGif(input);
54
+ expect(result).toBeFalsy();
55
+ });
56
+
57
+ it('should return false when input is null or undefined', () => {
58
+ let input;
59
+ let result = isImageGif(input);
60
+ expect(result).toBeFalsy();
61
+
62
+ input = null;
63
+ result = isImageGif(input);
64
+ expect(result).toBeFalsy();
65
+ });
66
+ });
package/src/hooks.js CHANGED
@@ -1,13 +1,13 @@
1
1
  /* eslint-disable react-hooks/exhaustive-deps */
2
2
  import React from 'react';
3
3
 
4
- function useOnScreen(ref, rootMargin = '0px') {
5
- const [isIntersecting, setIntersecting] = React.useState(false);
6
-
4
+ function useFirstVisited(ref, rootMargin = '0px') {
5
+ const [intersected, setIntersected] = React.useState(false);
7
6
  React.useEffect(() => {
7
+ if (intersected) return;
8
8
  const observer = new IntersectionObserver(
9
9
  ([entry]) => {
10
- setIntersecting(entry.isIntersecting);
10
+ setIntersected(intersected === false ? entry.isIntersecting : true);
11
11
  },
12
12
  {
13
13
  rootMargin,
@@ -24,8 +24,8 @@ function useOnScreen(ref, rootMargin = '0px') {
24
24
  }
25
25
  observer.disconnect();
26
26
  };
27
- }, [ref, rootMargin]);
28
- return isIntersecting;
27
+ }, [ref, rootMargin, intersected]);
28
+ return intersected;
29
29
  }
30
30
 
31
- export { useOnScreen };
31
+ export { useFirstVisited };