@plone/volto 17.0.0-alpha.15 → 17.0.0-alpha.16
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 +8 -0
- package/cypress/support/commands.js +18 -0
- package/locales/ca/LC_MESSAGES/volto.po +41 -0
- package/locales/ca.json +1 -1
- package/locales/de/LC_MESSAGES/volto.po +41 -0
- package/locales/de.json +1 -1
- package/locales/en/LC_MESSAGES/volto.po +41 -0
- package/locales/en.json +1 -1
- package/locales/es/LC_MESSAGES/volto.po +41 -0
- package/locales/es.json +1 -1
- package/locales/eu/LC_MESSAGES/volto.po +41 -0
- package/locales/eu.json +1 -1
- package/locales/fi/LC_MESSAGES/volto.po +41 -0
- package/locales/fi.json +1 -1
- package/locales/fr/LC_MESSAGES/volto.po +41 -0
- package/locales/fr.json +1 -1
- package/locales/it/LC_MESSAGES/volto.po +41 -0
- package/locales/it.json +1 -1
- package/locales/ja/LC_MESSAGES/volto.po +41 -0
- package/locales/ja.json +1 -1
- package/locales/nl/LC_MESSAGES/volto.po +41 -0
- package/locales/nl.json +1 -1
- package/locales/pt/LC_MESSAGES/volto.po +41 -0
- package/locales/pt.json +1 -1
- package/locales/pt_BR/LC_MESSAGES/volto.po +41 -0
- package/locales/pt_BR.json +1 -1
- package/locales/ro/LC_MESSAGES/volto.po +41 -0
- package/locales/ro.json +1 -1
- package/locales/volto.pot +42 -1
- package/locales/zh_CN/LC_MESSAGES/volto.po +41 -0
- package/locales/zh_CN.json +1 -1
- package/package.json +1 -1
- package/packages/volto-slate/package.json +1 -1
- package/packages/volto-slate/src/blocks/Text/index.js +8 -0
- package/src/components/manage/Blocks/Block/BlocksForm.jsx +19 -2
- package/src/components/manage/Blocks/Block/Edit.jsx +1 -1
- package/src/components/manage/Blocks/Container/Data.jsx +32 -0
- package/src/components/manage/Blocks/Container/Edit.jsx +174 -0
- package/src/components/manage/Blocks/Container/EditBlockWrapper.jsx +120 -0
- package/src/components/manage/Blocks/Container/NewBlockAddButton.jsx +84 -0
- package/src/components/manage/Blocks/Container/SimpleContainerToolbar.jsx +54 -0
- package/src/components/manage/Blocks/Grid/Edit.jsx +33 -0
- package/src/components/manage/Blocks/Grid/View.jsx +42 -0
- package/src/components/manage/Blocks/Grid/adapter.js +14 -0
- package/src/components/manage/Blocks/Grid/grid-1.svg +6 -0
- package/src/components/manage/Blocks/Grid/grid-2.svg +9 -0
- package/src/components/manage/Blocks/Grid/grid-3.svg +10 -0
- package/src/components/manage/Blocks/Grid/grid-4.svg +11 -0
- package/src/components/manage/Blocks/Grid/schema.js +35 -0
- package/src/components/manage/Blocks/Grid/templates.js +47 -0
- package/src/components/manage/Blocks/Image/ImageSidebar.jsx +2 -1
- package/src/components/manage/Blocks/Image/schema.js +11 -0
- package/src/components/manage/Blocks/Teaser/schema.js +5 -0
- package/src/components/manage/DragDropList/DragDropList.jsx +18 -13
- package/src/components/manage/TemplateChooser/TemplateChooser.jsx +38 -0
- package/src/components/manage/TemplateChooser/TemplateChooser.test.jsx +34 -0
- package/src/components/manage/TemplateChooser/template.svg +10 -0
- package/src/components/theme/Component/Component.jsx +1 -1
- package/src/components/theme/View/RenderBlocks.jsx +56 -27
- package/src/components/theme/View/RenderEmptyBlock.jsx +5 -0
- package/src/config/Blocks.jsx +44 -0
- package/src/helpers/Blocks/Blocks.js +26 -0
- package/src/helpers/Blocks/Blocks.test.js +21 -0
- package/src/helpers/Utils/Utils.js +25 -0
- package/src/helpers/index.js +2 -0
- package/src/icons/grid-block.svg +11 -0
- package/theme/themes/pastanaga/extras/grid.less +426 -0
- package/theme/themes/pastanaga/extras/main.less +1 -0
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { getBaseUrl, applyBlockDefaults } from '@plone/volto/helpers';
|
|
3
|
-
import { defineMessages,
|
|
3
|
+
import { defineMessages, useIntl } from 'react-intl';
|
|
4
4
|
import { map } from 'lodash';
|
|
5
|
+
import { MaybeWrap } from '@plone/volto/components';
|
|
5
6
|
import {
|
|
6
7
|
getBlocksFieldname,
|
|
7
8
|
getBlocksLayoutFieldname,
|
|
@@ -10,6 +11,7 @@ import {
|
|
|
10
11
|
import StyleWrapper from '@plone/volto/components/manage/Blocks/Block/StyleWrapper';
|
|
11
12
|
import config from '@plone/volto/registry';
|
|
12
13
|
import { ViewDefaultBlock } from '@plone/volto/components';
|
|
14
|
+
import RenderEmptyBlock from './RenderEmptyBlock';
|
|
13
15
|
|
|
14
16
|
const messages = defineMessages({
|
|
15
17
|
unknownBlock: {
|
|
@@ -23,7 +25,8 @@ const messages = defineMessages({
|
|
|
23
25
|
});
|
|
24
26
|
|
|
25
27
|
const RenderBlocks = (props) => {
|
|
26
|
-
const { content,
|
|
28
|
+
const { content, location, metadata, blockWrapperTag } = props;
|
|
29
|
+
const intl = useIntl();
|
|
27
30
|
const blocksFieldname = getBlocksFieldname(content);
|
|
28
31
|
const blocksLayoutFieldname = getBlocksLayoutFieldname(content);
|
|
29
32
|
const blocksConfig = props.blocksConfig || config.blocks.blocksConfig;
|
|
@@ -43,30 +46,56 @@ const RenderBlocks = (props) => {
|
|
|
43
46
|
properties: content,
|
|
44
47
|
});
|
|
45
48
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
49
|
+
if (content[blocksFieldname]?.[block]?.['@type'] === 'empty') {
|
|
50
|
+
return (
|
|
51
|
+
<MaybeWrap
|
|
52
|
+
key={block}
|
|
53
|
+
condition={blockWrapperTag}
|
|
54
|
+
as={blockWrapperTag}
|
|
55
|
+
>
|
|
56
|
+
<RenderEmptyBlock />
|
|
57
|
+
</MaybeWrap>
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (Block) {
|
|
62
|
+
return (
|
|
63
|
+
<MaybeWrap
|
|
64
|
+
key={block}
|
|
65
|
+
condition={blockWrapperTag}
|
|
66
|
+
as={blockWrapperTag}
|
|
67
|
+
>
|
|
68
|
+
<StyleWrapper
|
|
69
|
+
key={block}
|
|
70
|
+
{...props}
|
|
71
|
+
id={block}
|
|
72
|
+
block={block}
|
|
73
|
+
data={blockData}
|
|
74
|
+
>
|
|
75
|
+
<Block
|
|
76
|
+
id={block}
|
|
77
|
+
metadata={metadata}
|
|
78
|
+
properties={content}
|
|
79
|
+
data={blockData}
|
|
80
|
+
path={getBaseUrl(location?.pathname || '')}
|
|
81
|
+
blocksConfig={blocksConfig}
|
|
82
|
+
/>
|
|
83
|
+
</StyleWrapper>
|
|
84
|
+
</MaybeWrap>
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (blockData) {
|
|
89
|
+
return (
|
|
90
|
+
<div key={block}>
|
|
91
|
+
{intl.formatMessage(messages.unknownBlock, {
|
|
92
|
+
block: content[blocksFieldname]?.[block]?.['@type'],
|
|
93
|
+
})}
|
|
94
|
+
</div>
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return (
|
|
70
99
|
<div key={block}>{intl.formatMessage(messages.invalidBlock)}</div>
|
|
71
100
|
);
|
|
72
101
|
})}
|
|
@@ -76,4 +105,4 @@ const RenderBlocks = (props) => {
|
|
|
76
105
|
);
|
|
77
106
|
};
|
|
78
107
|
|
|
79
|
-
export default
|
|
108
|
+
export default RenderBlocks;
|
package/src/config/Blocks.jsx
CHANGED
|
@@ -42,6 +42,7 @@ import tableSVG from '@plone/volto/icons/table.svg';
|
|
|
42
42
|
import listingBlockSVG from '@plone/volto/icons/content-listing.svg';
|
|
43
43
|
import tocSVG from '@plone/volto/icons/list-bullet.svg';
|
|
44
44
|
import searchSVG from '@plone/volto/icons/zoom.svg';
|
|
45
|
+
import gridSVG from '@plone/volto/icons/grid-block.svg';
|
|
45
46
|
import imagesSVG from '@plone/volto/icons/images.svg';
|
|
46
47
|
|
|
47
48
|
import ImageGalleryListingBlockTemplate from '@plone/volto/components/manage/Blocks/Listing/ImageGallery';
|
|
@@ -50,6 +51,14 @@ import TextSettingsSchema from '@plone/volto/components/manage/Blocks/Text/Schem
|
|
|
50
51
|
import ImageSettingsSchema from '@plone/volto/components/manage/Blocks/Image/LayoutSchema';
|
|
51
52
|
import ToCSettingsSchema from '@plone/volto/components/manage/Blocks/ToC/Schema';
|
|
52
53
|
|
|
54
|
+
import GridBlockView from '@plone/volto/components/manage/Blocks/Grid/View';
|
|
55
|
+
import GridBlockEdit from '@plone/volto/components/manage/Blocks/Grid/Edit';
|
|
56
|
+
import { GridBlockDataAdapter } from '@plone/volto/components/manage/Blocks/Grid/adapter';
|
|
57
|
+
import { GridBlockSchema } from '@plone/volto/components/manage/Blocks/Grid/schema';
|
|
58
|
+
import GridTemplates from '@plone/volto/components/manage/Blocks/Grid/templates';
|
|
59
|
+
import { gridTeaserDisableStylingSchema } from '@plone/volto/components/manage/Blocks/Teaser/schema';
|
|
60
|
+
import { gridImageDisableSizeAndPositionHandlersSchema } from '@plone/volto/components/manage/Blocks/Image/schema';
|
|
61
|
+
|
|
53
62
|
import SearchBlockView from '@plone/volto/components/manage/Blocks/Search/SearchBlockView';
|
|
54
63
|
import SearchBlockEdit from '@plone/volto/components/manage/Blocks/Search/SearchBlockEdit';
|
|
55
64
|
|
|
@@ -458,6 +467,27 @@ const blocksConfig = {
|
|
|
458
467
|
},
|
|
459
468
|
},
|
|
460
469
|
},
|
|
470
|
+
// This next block is not named just grid for some reasons:
|
|
471
|
+
// 1.- Naming it grid will collide with the SemanticUI CSS of the Grid component
|
|
472
|
+
// 2.- It would prevent the transition from the old grid
|
|
473
|
+
// (based on @kitconcept/volto-blocks-grid) without having to perform any migration.
|
|
474
|
+
// This way, both can co-exist at the same time.
|
|
475
|
+
gridBlock: {
|
|
476
|
+
id: 'gridBlock',
|
|
477
|
+
title: 'Grid',
|
|
478
|
+
icon: gridSVG,
|
|
479
|
+
group: 'common',
|
|
480
|
+
view: GridBlockView,
|
|
481
|
+
edit: GridBlockEdit,
|
|
482
|
+
blockSchema: GridBlockSchema,
|
|
483
|
+
dataAdapter: GridBlockDataAdapter,
|
|
484
|
+
restricted: false,
|
|
485
|
+
mostUsed: true,
|
|
486
|
+
sidebarTab: 1,
|
|
487
|
+
templates: GridTemplates,
|
|
488
|
+
maxLength: 4,
|
|
489
|
+
allowedBlocks: ['image', 'listing', 'slate', 'teaser'],
|
|
490
|
+
},
|
|
461
491
|
teaser: {
|
|
462
492
|
id: 'teaser',
|
|
463
493
|
title: 'Teaser',
|
|
@@ -481,6 +511,20 @@ const blocksConfig = {
|
|
|
481
511
|
},
|
|
482
512
|
};
|
|
483
513
|
|
|
514
|
+
// This is required in order to initialize the inner blocksConfig
|
|
515
|
+
// for the grid block, since we need to modify how the inner teaser
|
|
516
|
+
// block behave in it (= no schemaEnhancer fields for teasers inside a grid)
|
|
517
|
+
// Afterwards, it can be further customized in add-ons using the same technique.
|
|
518
|
+
blocksConfig.gridBlock.blocksConfig = { ...blocksConfig };
|
|
519
|
+
blocksConfig.gridBlock.blocksConfig.teaser = {
|
|
520
|
+
...blocksConfig.teaser,
|
|
521
|
+
schemaEnhancer: gridTeaserDisableStylingSchema,
|
|
522
|
+
};
|
|
523
|
+
blocksConfig.gridBlock.blocksConfig.image = {
|
|
524
|
+
...blocksConfig.image,
|
|
525
|
+
schemaEnhancer: gridImageDisableSizeAndPositionHandlersSchema,
|
|
526
|
+
};
|
|
527
|
+
|
|
484
528
|
const requiredBlocks = ['title'];
|
|
485
529
|
|
|
486
530
|
const initialBlocks = {};
|
|
@@ -343,6 +343,32 @@ export function emptyBlocksForm() {
|
|
|
343
343
|
};
|
|
344
344
|
}
|
|
345
345
|
|
|
346
|
+
/**
|
|
347
|
+
* Generate empty blocks blocks/blocks_layout pair given the type
|
|
348
|
+
* (could be empty, if not type given) and the number of blocks
|
|
349
|
+
* @function blocksFormGenerator
|
|
350
|
+
* @param {number} number How many blocks to generate of the type (could be "empty", if no type provided)
|
|
351
|
+
* @param {number} type The type of the blocks
|
|
352
|
+
* @return {Object} blocks/blocks_layout pair filled with the generated blocks
|
|
353
|
+
*/
|
|
354
|
+
export function blocksFormGenerator(number, type) {
|
|
355
|
+
const idMap = [...Array(number).keys()].map(() => uuid());
|
|
356
|
+
const start = {
|
|
357
|
+
blocks: {},
|
|
358
|
+
blocks_layout: { items: idMap },
|
|
359
|
+
};
|
|
360
|
+
|
|
361
|
+
return {
|
|
362
|
+
...start,
|
|
363
|
+
blocks: Object.fromEntries(
|
|
364
|
+
start.blocks_layout.items.map((item) => [
|
|
365
|
+
item,
|
|
366
|
+
{ '@type': type || 'empty' },
|
|
367
|
+
]),
|
|
368
|
+
),
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
|
|
346
372
|
/**
|
|
347
373
|
* Recursively discover blocks in data and call the provided callback
|
|
348
374
|
* @function visitBlocks
|
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
buildStyleClassNamesFromData,
|
|
20
20
|
buildStyleClassNamesExtenders,
|
|
21
21
|
getPreviousNextBlock,
|
|
22
|
+
blocksFormGenerator,
|
|
22
23
|
} from './Blocks';
|
|
23
24
|
|
|
24
25
|
import config from '@plone/volto/registry';
|
|
@@ -1275,4 +1276,24 @@ describe('Blocks', () => {
|
|
|
1275
1276
|
]);
|
|
1276
1277
|
});
|
|
1277
1278
|
});
|
|
1279
|
+
|
|
1280
|
+
describe('blocksFormGenerator', () => {
|
|
1281
|
+
it('Returns an empty blocks/blocks_layout pair', () => {
|
|
1282
|
+
expect(blocksFormGenerator(0, '')).toEqual({
|
|
1283
|
+
blocks: {},
|
|
1284
|
+
blocks_layout: { items: [] },
|
|
1285
|
+
});
|
|
1286
|
+
});
|
|
1287
|
+
it.only('Returns a filled blocks/blocks_layout pair with type block', () => {
|
|
1288
|
+
const result = blocksFormGenerator(2, 'teaser');
|
|
1289
|
+
expect(Object.keys(result.blocks).length).toEqual(2);
|
|
1290
|
+
expect(result.blocks_layout.items.length).toEqual(2);
|
|
1291
|
+
expect(result.blocks[result.blocks_layout.items[0]]['@type']).toEqual(
|
|
1292
|
+
'teaser',
|
|
1293
|
+
);
|
|
1294
|
+
expect(result.blocks[result.blocks_layout.items[1]]['@type']).toEqual(
|
|
1295
|
+
'teaser',
|
|
1296
|
+
);
|
|
1297
|
+
});
|
|
1298
|
+
});
|
|
1278
1299
|
});
|
|
@@ -324,3 +324,28 @@ export const arrayRange = (start, stop, step) =>
|
|
|
324
324
|
{ length: (stop - start) / step + 1 },
|
|
325
325
|
(value, index) => start + index * step,
|
|
326
326
|
);
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* Given an event target element returns if it's an interactive element
|
|
330
|
+
* of the one in the list.
|
|
331
|
+
* @param {node} element event.target element type
|
|
332
|
+
* @returns {boolean} If it's an interactive element of the list
|
|
333
|
+
*/
|
|
334
|
+
export function isInteractiveElement(
|
|
335
|
+
element,
|
|
336
|
+
interactiveElements = [
|
|
337
|
+
'button',
|
|
338
|
+
'input',
|
|
339
|
+
'textarea',
|
|
340
|
+
'select',
|
|
341
|
+
'option',
|
|
342
|
+
'svg',
|
|
343
|
+
'path',
|
|
344
|
+
],
|
|
345
|
+
) {
|
|
346
|
+
if (interactiveElements.includes(element.tagName.toLowerCase())) {
|
|
347
|
+
return true;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
return false;
|
|
351
|
+
}
|
package/src/helpers/index.js
CHANGED
|
@@ -54,6 +54,7 @@ export {
|
|
|
54
54
|
previousBlockId,
|
|
55
55
|
applyBlockDefaults,
|
|
56
56
|
applySchemaDefaults,
|
|
57
|
+
blocksFormGenerator,
|
|
57
58
|
buildStyleClassNamesFromData,
|
|
58
59
|
buildStyleClassNamesExtenders,
|
|
59
60
|
getPreviousNextBlock,
|
|
@@ -91,6 +92,7 @@ export {
|
|
|
91
92
|
cloneDeepSchema,
|
|
92
93
|
arrayRange,
|
|
93
94
|
reorderArray,
|
|
95
|
+
isInteractiveElement,
|
|
94
96
|
} from '@plone/volto/helpers/Utils/Utils';
|
|
95
97
|
export { messages } from './MessageLabels/MessageLabels';
|
|
96
98
|
export {
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="96" height="96" viewBox="0 0 96 96">
|
|
2
|
+
<g fill="none" fill-rule="evenodd">
|
|
3
|
+
<rect width="96" height="96" fill="currentcolor" rx="3"/>
|
|
4
|
+
<g fill="#FFF" opacity=".9" transform="translate(8 22)">
|
|
5
|
+
<rect width="18" height="53" x="42"/>
|
|
6
|
+
<rect width="18" height="53" x="63"/>
|
|
7
|
+
<rect width="18" height="53"/>
|
|
8
|
+
<rect width="18" height="53" x="21"/>
|
|
9
|
+
</g>
|
|
10
|
+
</g>
|
|
11
|
+
</svg>
|