@eeacms/volto-eea-website-theme 1.4.2 → 1.5.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,11 @@ 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
+ ### [1.5.0](https://github.com/eea/volto-eea-website-theme/compare/1.4.2...1.5.0) - 9 January 2023
8
+
9
+ #### :hammer_and_wrench: Others
10
+
11
+ - Release 1.5.0 [Alin Voinea - [`1b87380`](https://github.com/eea/volto-eea-website-theme/commit/1b87380b5eb5cd7324b1816c08e932c52c7e107b)]
7
12
  ### [1.4.2](https://github.com/eea/volto-eea-website-theme/compare/1.4.1...1.4.2) - 29 December 2022
8
13
 
9
14
  #### :bug: Bug Fixes
@@ -32,7 +37,6 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
32
37
 
33
38
  - Release 1.4.0 [Alin Voinea - [`bd42a0d`](https://github.com/eea/volto-eea-website-theme/commit/bd42a0d26e928cac5d99933194755da3db06b341)]
34
39
  - bump version to use as volto-eea-design-system [David Ichim - [`f4be047`](https://github.com/eea/volto-eea-website-theme/commit/f4be047328b46399b03b612d378b18aaf82e7dc1)]
35
- - Add Sonarqube tag using advisory-board-frontend addons list [EEA Jenkins - [`9b7cfef`](https://github.com/eea/volto-eea-website-theme/commit/9b7cfefb4d34fc1c948015e491feb370f9795bd8)]
36
40
  - test(Jenkins): Run tests and cypress with latest canary @plone/volto [Alin Voinea - [`df252a9`](https://github.com/eea/volto-eea-website-theme/commit/df252a9bfed0bb86cadf53c59dd1603b1e2cd822)]
37
41
  ### [1.3.2](https://github.com/eea/volto-eea-website-theme/compare/1.3.1...1.3.2) - 16 December 2022
38
42
 
@@ -42,7 +46,6 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
42
46
 
43
47
  #### :hammer_and_wrench: Others
44
48
 
45
- - Add Sonarqube tag using cca-frontend addons list [EEA Jenkins - [`a43c658`](https://github.com/eea/volto-eea-website-theme/commit/a43c658a7920c8df95e763b9a637f38ce77eba2c)]
46
49
  - Better razzle.config [Tiberiu Ichim - [`81dbf48`](https://github.com/eea/volto-eea-website-theme/commit/81dbf48815fb27facb4f82c9b764540fdf188b2e)]
47
50
  - Better razzle.config [Tiberiu Ichim - [`7bc9da2`](https://github.com/eea/volto-eea-website-theme/commit/7bc9da2cd837ab62a95cd29979cdd9b0055b7d67)]
48
51
  ### [1.3.1](https://github.com/eea/volto-eea-website-theme/compare/1.3.0...1.3.1) - 28 November 2022
@@ -51,9 +54,6 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
51
54
 
52
55
  - feat(Footer): Bring back footer contacts extra actions - refs #151856 [Alin Voinea - [`6c19413`](https://github.com/eea/volto-eea-website-theme/commit/6c194139420c9fd847692d180db1c1593e2483de)]
53
56
 
54
- #### :hammer_and_wrench: Others
55
-
56
- - yarn 3 [Alin Voinea - [`ea7a709`](https://github.com/eea/volto-eea-website-theme/commit/ea7a7094945312776e9b6f44e371178603e92139)]
57
57
  ### [1.3.0](https://github.com/eea/volto-eea-website-theme/compare/1.2.0...1.3.0) - 22 November 2022
58
58
 
59
59
  #### :rocket: New Features
@@ -94,7 +94,6 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
94
94
  - Add subsite class to body [Tiberiu Ichim - [`74d700f`](https://github.com/eea/volto-eea-website-theme/commit/74d700fbfd6249a8604762a7e4e49cce857db0f3)]
95
95
  - Add subsite info to header [Tiberiu Ichim - [`47daf8b`](https://github.com/eea/volto-eea-website-theme/commit/47daf8bb6374a1222040626b19d4154df7ba1b83)]
96
96
  - fix eslint [Miu Razvan - [`eb8d0a7`](https://github.com/eea/volto-eea-website-theme/commit/eb8d0a790bc70c0aae256c6ff35f63c4885f338e)]
97
- - Add Sonarqube tag using circularity-frontend addons list [EEA Jenkins - [`cc578a4`](https://github.com/eea/volto-eea-website-theme/commit/cc578a413b205a8e61e091fab3a88f94cedefc89)]
98
97
  ### [1.1.0](https://github.com/eea/volto-eea-website-theme/compare/1.0.0...1.1.0) - 28 October 2022
99
98
 
100
99
  #### :nail_care: Enhancements
@@ -142,7 +141,6 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
142
141
 
143
142
  #### :hammer_and_wrench: Others
144
143
 
145
- - Add Sonarqube tag using eea-website-frontend addons list [EEA Jenkins - [`33b56ac`](https://github.com/eea/volto-eea-website-theme/commit/33b56acb13fbaf0c5b79e8fc6e13c4b699c79c90)]
146
144
  ### [0.7.3](https://github.com/eea/volto-eea-website-theme/compare/0.7.2...0.7.3) - 22 September 2022
147
145
 
148
146
  #### :hammer_and_wrench: Others
@@ -410,7 +408,6 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
410
408
  - Header refactor, add custom logo #5 [ichim-david - [`4950235`](https://github.com/eea/volto-eea-website-theme/commit/49502358105437cfeac3b144e6d301cb59aa2346)]
411
409
  - Update footer.config with new publication card component [ichim-david - [`2e38e9a`](https://github.com/eea/volto-eea-website-theme/commit/2e38e9a417f835009d60c80d4eb4b30229f55e45)]
412
410
  - feature(breadcrumbs): implement eea-design-system breadcrumb as Volto component #32 #7 [ichim-david - [`181af41`](https://github.com/eea/volto-eea-website-theme/commit/181af4125ce2b9ddac56dab4723cb11c26633221)]
413
- - Add Sonarqube tag using eea-website-frontend addons list [EEA Jenkins - [`da8ceb6`](https://github.com/eea/volto-eea-website-theme/commit/da8ceb68ea68bfbc9504e48ccd4d68277f11ab9a)]
414
411
  - use breadcrumbs from eea-design-system [nileshgulia1 - [`db2f9e9`](https://github.com/eea/volto-eea-website-theme/commit/db2f9e9a4327420a3cce9a9903cd88549b129eab)]
415
412
  - Update theme.config [ichim-david - [`8eca4f4`](https://github.com/eea/volto-eea-website-theme/commit/8eca4f40397a4aeca6d39029c92db78968d37064)]
416
413
  - Added keyContent component to theme.config [ichim-david - [`d86f202`](https://github.com/eea/volto-eea-website-theme/commit/d86f202d0274d839487a88b51cae9a0e899beb23)]
@@ -452,5 +449,4 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
452
449
 
453
450
  #### :hammer_and_wrench: Others
454
451
 
455
- - yarn bootstrap [Alin Voinea - [`6995e9e`](https://github.com/eea/volto-eea-website-theme/commit/6995e9e091f21fdbbdffa8a44fc0e2c626f6d46a)]
456
452
  - Initial commit [Alin Voinea - [`6a9c03a`](https://github.com/eea/volto-eea-website-theme/commit/6a9c03a7cebe71ca87e82cf58c42904063e9d8d3)]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eeacms/volto-eea-website-theme",
3
- "version": "1.4.2",
3
+ "version": "1.5.0",
4
4
  "description": "@eeacms/volto-eea-website-theme: Volto add-on",
5
5
  "main": "src/index.js",
6
6
  "author": "European Environment Agency: IDM2 A-Team",
@@ -0,0 +1,408 @@
1
+ /**
2
+ * Edit image block.
3
+ * @module components/manage/Blocks/Image/Edit
4
+ */
5
+
6
+ import React, { Component } from 'react';
7
+ import PropTypes from 'prop-types';
8
+ import { connect } from 'react-redux';
9
+ import { compose } from 'redux';
10
+ import { readAsDataURL } from 'promise-file-reader';
11
+ import { Button, Dimmer, Input, Loader, Message } from 'semantic-ui-react';
12
+ import { defineMessages, injectIntl } from 'react-intl';
13
+ import loadable from '@loadable/component';
14
+ import cx from 'classnames';
15
+ import { isEqual } from 'lodash';
16
+
17
+ import { Icon, ImageSidebar, SidebarPortal } from '@plone/volto/components';
18
+ import { Icon as IconSemantic } from 'semantic-ui-react';
19
+ import { withBlockExtensions } from '@plone/volto/helpers';
20
+ import { createContent } from '@plone/volto/actions';
21
+ import { Copyright } from '@eeacms/volto-eea-design-system/ui';
22
+
23
+ import {
24
+ flattenToAppURL,
25
+ getBaseUrl,
26
+ isInternalURL,
27
+ } from '@plone/volto/helpers';
28
+
29
+ import imageBlockSVG from '@plone/volto/components/manage/Blocks/Image/block-image.svg';
30
+ import clearSVG from '@plone/volto/icons/clear.svg';
31
+ import navTreeSVG from '@plone/volto/icons/nav.svg';
32
+ import aheadSVG from '@plone/volto/icons/ahead.svg';
33
+ import uploadSVG from '@plone/volto/icons/upload.svg';
34
+ import './style.less';
35
+ const Dropzone = loadable(() => import('react-dropzone'));
36
+
37
+ const messages = defineMessages({
38
+ ImageBlockInputPlaceholder: {
39
+ id: 'Browse the site, drop an image, or type an URL',
40
+ defaultMessage: 'Browse the site, drop an image, or type an URL',
41
+ },
42
+ });
43
+
44
+ /**
45
+ * Edit image block class.
46
+ * @class Edit
47
+ * @extends Component
48
+ */
49
+ class Edit extends Component {
50
+ /**
51
+ * Property types.
52
+ * @property {Object} propTypes Property types.
53
+ * @static
54
+ */
55
+ static propTypes = {
56
+ selected: PropTypes.bool.isRequired,
57
+ block: PropTypes.string.isRequired,
58
+ index: PropTypes.number.isRequired,
59
+ data: PropTypes.objectOf(PropTypes.any).isRequired,
60
+ content: PropTypes.objectOf(PropTypes.any).isRequired,
61
+ request: PropTypes.shape({
62
+ loading: PropTypes.bool,
63
+ loaded: PropTypes.bool,
64
+ }).isRequired,
65
+ pathname: PropTypes.string.isRequired,
66
+ onChangeBlock: PropTypes.func.isRequired,
67
+ onSelectBlock: PropTypes.func.isRequired,
68
+ onDeleteBlock: PropTypes.func.isRequired,
69
+ onFocusPreviousBlock: PropTypes.func.isRequired,
70
+ onFocusNextBlock: PropTypes.func.isRequired,
71
+ handleKeyDown: PropTypes.func.isRequired,
72
+ createContent: PropTypes.func.isRequired,
73
+ openObjectBrowser: PropTypes.func.isRequired,
74
+ };
75
+
76
+ state = {
77
+ uploading: false,
78
+ url: '',
79
+ dragging: false,
80
+ };
81
+
82
+ /**
83
+ * Component will receive props
84
+ * @method componentWillReceiveProps
85
+ * @param {Object} nextProps Next properties
86
+ * @returns {undefined}
87
+ */
88
+ UNSAFE_componentWillReceiveProps(nextProps) {
89
+ if (
90
+ this.props.request.loading &&
91
+ nextProps.request.loaded &&
92
+ this.state.uploading
93
+ ) {
94
+ this.setState({
95
+ uploading: false,
96
+ });
97
+ this.props.onChangeBlock(this.props.block, {
98
+ ...this.props.data,
99
+ url: nextProps.content['@id'],
100
+ alt: '',
101
+ });
102
+ }
103
+ }
104
+
105
+ /**
106
+ * @param {*} nextProps
107
+ * @returns {boolean}
108
+ * @memberof Edit
109
+ */
110
+ shouldComponentUpdate(nextProps) {
111
+ return (
112
+ this.props.selected ||
113
+ nextProps.selected ||
114
+ !isEqual(this.props.data, nextProps.data)
115
+ );
116
+ }
117
+
118
+ /**
119
+ * Upload image handler (not used), but useful in case that we want a button
120
+ * not powered by react-dropzone
121
+ * @method onUploadImage
122
+ * @returns {undefined}
123
+ */
124
+ onUploadImage = (e) => {
125
+ e.stopPropagation();
126
+ const file = e.target.files[0];
127
+ this.setState({
128
+ uploading: true,
129
+ });
130
+ readAsDataURL(file).then((data) => {
131
+ const fields = data.match(/^data:(.*);(.*),(.*)$/);
132
+ this.props.createContent(
133
+ getBaseUrl(this.props.pathname),
134
+ {
135
+ '@type': 'Image',
136
+ title: file.name,
137
+ image: {
138
+ data: fields[3],
139
+ encoding: fields[2],
140
+ 'content-type': fields[1],
141
+ filename: file.name,
142
+ },
143
+ },
144
+ this.props.block,
145
+ );
146
+ });
147
+ };
148
+
149
+ /**
150
+ * Change url handler
151
+ * @method onChangeUrl
152
+ * @param {Object} target Target object
153
+ * @returns {undefined}
154
+ */
155
+ onChangeUrl = ({ target }) => {
156
+ this.setState({
157
+ url: target.value,
158
+ });
159
+ };
160
+
161
+ /**
162
+ * Submit url handler
163
+ * @method onSubmitUrl
164
+ * @param {object} e Event
165
+ * @returns {undefined}
166
+ */
167
+ onSubmitUrl = () => {
168
+ this.props.onChangeBlock(this.props.block, {
169
+ ...this.props.data,
170
+ url: flattenToAppURL(this.state.url),
171
+ });
172
+ };
173
+
174
+ /**
175
+ * Drop handler
176
+ * @method onDrop
177
+ * @param {array} files File objects
178
+ * @returns {undefined}
179
+ */
180
+ onDrop = (file) => {
181
+ this.setState({
182
+ uploading: true,
183
+ });
184
+
185
+ readAsDataURL(file[0]).then((data) => {
186
+ const fields = data.match(/^data:(.*);(.*),(.*)$/);
187
+ this.props.createContent(
188
+ getBaseUrl(this.props.pathname),
189
+ {
190
+ '@type': 'Image',
191
+ title: file[0].name,
192
+ image: {
193
+ data: fields[3],
194
+ encoding: fields[2],
195
+ 'content-type': fields[1],
196
+ filename: file[0].name,
197
+ },
198
+ },
199
+ this.props.block,
200
+ );
201
+ });
202
+ };
203
+
204
+ /**
205
+ * Keydown handler on Variant Menu Form
206
+ * This is required since the ENTER key is already mapped to a onKeyDown
207
+ * event and needs to be overriden with a child onKeyDown.
208
+ * @method onKeyDownVariantMenuForm
209
+ * @param {Object} e Event object
210
+ * @returns {undefined}
211
+ */
212
+ onKeyDownVariantMenuForm = (e) => {
213
+ if (e.key === 'Enter') {
214
+ e.preventDefault();
215
+ e.stopPropagation();
216
+ this.onSubmitUrl();
217
+ } else if (e.key === 'Escape') {
218
+ e.preventDefault();
219
+ e.stopPropagation();
220
+ // TODO: Do something on ESC key
221
+ }
222
+ };
223
+ onDragEnter = () => {
224
+ this.setState({ dragging: true });
225
+ };
226
+ onDragLeave = () => {
227
+ this.setState({ dragging: false });
228
+ };
229
+
230
+ node = React.createRef();
231
+
232
+ /**
233
+ * Render method.
234
+ * @method render
235
+ * @returns {string} Markup for the component.
236
+ */
237
+ render() {
238
+ const { data } = this.props;
239
+ const placeholder =
240
+ this.props.data.placeholder ||
241
+ this.props.intl.formatMessage(messages.ImageBlockInputPlaceholder);
242
+ const { copyright, copyrightIcon, copyrightPosition } = data;
243
+ return (
244
+ <div
245
+ className={cx(
246
+ 'block image align',
247
+ {
248
+ center: !Boolean(data.align),
249
+ },
250
+ data.align,
251
+ )}
252
+ >
253
+ {data.url ? (
254
+ <div className="image-block">
255
+ <img
256
+ className={cx({
257
+ 'full-width': data.align === 'full',
258
+ large: data.size === 'l',
259
+ medium: data.size === 'm',
260
+ small: data.size === 's',
261
+ })}
262
+ src={
263
+ isInternalURL(data.url)
264
+ ? // Backwards compat in the case that the block is storing the full server URL
265
+ (() => {
266
+ if (data.size === 'l')
267
+ return `${flattenToAppURL(data.url)}/@@images/image`;
268
+ if (data.size === 'm')
269
+ return `${flattenToAppURL(
270
+ data.url,
271
+ )}/@@images/image/preview`;
272
+ if (data.size === 's')
273
+ return `${flattenToAppURL(
274
+ data.url,
275
+ )}/@@images/image/mini`;
276
+ return `${flattenToAppURL(data.url)}/@@images/image`;
277
+ })()
278
+ : data.url
279
+ }
280
+ alt={data.alt || ''}
281
+ />
282
+ <div className="copyright-image">
283
+ {copyright ? (
284
+ <Copyright copyrightPosition={copyrightPosition}>
285
+ <Copyright.Icon>
286
+ <IconSemantic name={copyrightIcon} />
287
+ </Copyright.Icon>
288
+ <Copyright.Text>{copyright}</Copyright.Text>
289
+ </Copyright>
290
+ ) : (
291
+ ''
292
+ )}
293
+ </div>
294
+ </div>
295
+ ) : (
296
+ <div>
297
+ {this.props.editable && (
298
+ <Dropzone
299
+ noClick
300
+ onDrop={this.onDrop}
301
+ onDragEnter={this.onDragEnter}
302
+ onDragLeave={this.onDragLeave}
303
+ className="dropzone"
304
+ >
305
+ {({ getRootProps, getInputProps }) => (
306
+ <div {...getRootProps()}>
307
+ <Message>
308
+ {this.state.dragging && <Dimmer active></Dimmer>}
309
+ {this.state.uploading && (
310
+ <Dimmer active>
311
+ <Loader indeterminate>Uploading image</Loader>
312
+ </Dimmer>
313
+ )}
314
+ <div className="no-image-wrapper">
315
+ <img src={imageBlockSVG} alt="" />
316
+ <div className="toolbar-inner">
317
+ <Button.Group>
318
+ <Button
319
+ basic
320
+ icon
321
+ onClick={(e) => {
322
+ e.stopPropagation();
323
+ e.preventDefault();
324
+ this.props.openObjectBrowser();
325
+ }}
326
+ >
327
+ <Icon name={navTreeSVG} size="24px" />
328
+ </Button>
329
+ </Button.Group>
330
+ <Button.Group>
331
+ <label className="ui button basic icon">
332
+ <Icon name={uploadSVG} size="24px" />
333
+ <input
334
+ {...getInputProps({
335
+ type: 'file',
336
+ onChange: this.onUploadImage,
337
+ style: { display: 'none' },
338
+ })}
339
+ />
340
+ </label>
341
+ </Button.Group>
342
+ <Input
343
+ onKeyDown={this.onKeyDownVariantMenuForm}
344
+ onChange={this.onChangeUrl}
345
+ placeholder={placeholder}
346
+ value={this.state.url}
347
+ onClick={(e) => {
348
+ e.target.focus();
349
+ }}
350
+ onFocus={(e) => {
351
+ this.props.onSelectBlock(this.props.id);
352
+ }}
353
+ />
354
+ {this.state.url && (
355
+ <Button.Group>
356
+ <Button
357
+ basic
358
+ className="cancel"
359
+ onClick={(e) => {
360
+ e.stopPropagation();
361
+ this.setState({ url: '' });
362
+ }}
363
+ >
364
+ <Icon name={clearSVG} size="30px" />
365
+ </Button>
366
+ </Button.Group>
367
+ )}
368
+ <Button.Group>
369
+ <Button
370
+ basic
371
+ primary
372
+ disabled={!this.state.url}
373
+ onClick={(e) => {
374
+ e.stopPropagation();
375
+ this.onSubmitUrl();
376
+ }}
377
+ >
378
+ <Icon name={aheadSVG} size="30px" />
379
+ </Button>
380
+ </Button.Group>
381
+ </div>
382
+ </div>
383
+ </Message>
384
+ </div>
385
+ )}
386
+ </Dropzone>
387
+ )}
388
+ </div>
389
+ )}
390
+ <SidebarPortal selected={this.props.selected}>
391
+ <ImageSidebar {...this.props} />
392
+ </SidebarPortal>
393
+ </div>
394
+ );
395
+ }
396
+ }
397
+
398
+ export default compose(
399
+ injectIntl,
400
+ withBlockExtensions,
401
+ connect(
402
+ (state, ownProps) => ({
403
+ request: state.content.subrequests[ownProps.block] || {},
404
+ content: state.content.subrequests[ownProps.block]?.data,
405
+ }),
406
+ { createContent },
407
+ ),
408
+ )(Edit);
@@ -0,0 +1,111 @@
1
+ /**
2
+ * View image block.
3
+ * @module components/manage/Blocks/Image/View
4
+ */
5
+
6
+ import React from 'react';
7
+ import PropTypes from 'prop-types';
8
+ import { UniversalLink } from '@plone/volto/components';
9
+ import { Icon } from 'semantic-ui-react';
10
+ import cx from 'classnames';
11
+ import { withBlockExtensions } from '@plone/volto/helpers';
12
+ import { flattenToAppURL, isInternalURL } from '@plone/volto/helpers';
13
+ import { Copyright } from '@eeacms/volto-eea-design-system/ui';
14
+ import './style.less';
15
+ /**
16
+ * View image block class.
17
+ * @class View
18
+ * @extends Component
19
+ */
20
+ export const View = ({ data, detached }) => {
21
+ const href = data?.href?.[0]?.['@id'] || '';
22
+ const { copyright, copyrightIcon, copyrightPosition } = data;
23
+ return (
24
+ <p
25
+ className={cx(
26
+ 'block image align',
27
+ {
28
+ center: !Boolean(data.align),
29
+ detached,
30
+ },
31
+ data.align,
32
+ )}
33
+ >
34
+ {data.url && (
35
+ <>
36
+ {(() => {
37
+ const image = (
38
+ <div className="image-block">
39
+ <img
40
+ className={cx({
41
+ 'full-width': data.align === 'full',
42
+ large: data.size === 'l',
43
+ medium: data.size === 'm',
44
+ small: data.size === 's',
45
+ })}
46
+ src={
47
+ isInternalURL(data.url)
48
+ ? // Backwards compat in the case that the block is storing the full server URL
49
+ (() => {
50
+ if (data.size === 'l')
51
+ return `${flattenToAppURL(
52
+ data.url,
53
+ )}/@@images/image`;
54
+ if (data.size === 'm')
55
+ return `${flattenToAppURL(
56
+ data.url,
57
+ )}/@@images/image/preview`;
58
+ if (data.size === 's')
59
+ return `${flattenToAppURL(
60
+ data.url,
61
+ )}/@@images/image/mini`;
62
+ return `${flattenToAppURL(data.url)}/@@images/image`;
63
+ })()
64
+ : data.url
65
+ }
66
+ alt={data.alt || ''}
67
+ loading="lazy"
68
+ />
69
+ <div className="copyright-image">
70
+ {copyright ? (
71
+ <Copyright copyrightPosition={copyrightPosition}>
72
+ <Copyright.Icon>
73
+ <Icon className={copyrightIcon} />
74
+ </Copyright.Icon>
75
+ <Copyright.Text>{copyright}</Copyright.Text>
76
+ </Copyright>
77
+ ) : (
78
+ ''
79
+ )}
80
+ </div>
81
+ </div>
82
+ );
83
+ if (href) {
84
+ return (
85
+ <UniversalLink
86
+ href={href}
87
+ openLinkInNewTab={data.openLinkInNewTab}
88
+ >
89
+ {image}
90
+ </UniversalLink>
91
+ );
92
+ } else {
93
+ return image;
94
+ }
95
+ })()}
96
+ </>
97
+ )}
98
+ </p>
99
+ );
100
+ };
101
+
102
+ /**
103
+ * Property types.
104
+ * @property {Object} propTypes Property types.
105
+ * @static
106
+ */
107
+ View.propTypes = {
108
+ data: PropTypes.objectOf(PropTypes.any).isRequired,
109
+ };
110
+
111
+ export default withBlockExtensions(View);