@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 +24 -0
- package/README.md +1 -1
- package/jest-addon.config.js +2 -2
- package/package.json +1 -1
- package/src/components/Blocks/Hero/Copyright.test.jsx +35 -0
- package/src/components/Blocks/Hero/Edit.jsx +3 -1
- package/src/components/Blocks/Hero/Hero.jsx +5 -4
- package/src/components/Blocks/Hero/Hero.test.jsx +40 -0
- package/src/components/Blocks/Hero/View.jsx +3 -1
- package/src/components/Blocks/Hero/schema.js +12 -0
- package/src/helpers.js +19 -1
- package/src/helpers.test.js +66 -0
- package/src/hooks.js +7 -7
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
package/jest-addon.config.js
CHANGED
|
@@ -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>/
|
|
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
|
@@ -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,
|
|
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 {
|
|
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 =
|
|
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,
|
|
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
|
|
5
|
-
const [
|
|
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
|
-
|
|
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
|
|
27
|
+
}, [ref, rootMargin, intersected]);
|
|
28
|
+
return intersected;
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
export {
|
|
31
|
+
export { useFirstVisited };
|