@plone/volto 17.0.0-alpha.14 → 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.
Files changed (99) hide show
  1. package/.yarn/install-state.gz +0 -0
  2. package/CHANGELOG.md +25 -0
  3. package/cypress/support/commands.js +18 -0
  4. package/locales/ca/LC_MESSAGES/volto.po +41 -0
  5. package/locales/ca.json +1 -1
  6. package/locales/de/LC_MESSAGES/volto.po +41 -0
  7. package/locales/de.json +1 -1
  8. package/locales/en/LC_MESSAGES/volto.po +41 -0
  9. package/locales/en.json +1 -1
  10. package/locales/es/LC_MESSAGES/volto.po +41 -0
  11. package/locales/es.json +1 -1
  12. package/locales/eu/LC_MESSAGES/volto.po +41 -0
  13. package/locales/eu.json +1 -1
  14. package/locales/fi/LC_MESSAGES/volto.po +41 -0
  15. package/locales/fi.json +1 -1
  16. package/locales/fr/LC_MESSAGES/volto.po +41 -0
  17. package/locales/fr.json +1 -1
  18. package/locales/it/LC_MESSAGES/volto.po +41 -0
  19. package/locales/it.json +1 -1
  20. package/locales/ja/LC_MESSAGES/volto.po +41 -0
  21. package/locales/ja.json +1 -1
  22. package/locales/nl/LC_MESSAGES/volto.po +41 -0
  23. package/locales/nl.json +1 -1
  24. package/locales/pt/LC_MESSAGES/volto.po +41 -0
  25. package/locales/pt.json +1 -1
  26. package/locales/pt_BR/LC_MESSAGES/volto.po +41 -0
  27. package/locales/pt_BR.json +1 -1
  28. package/locales/ro/LC_MESSAGES/volto.po +41 -0
  29. package/locales/ro.json +1 -1
  30. package/locales/volto.pot +42 -1
  31. package/locales/zh_CN/LC_MESSAGES/volto.po +41 -0
  32. package/locales/zh_CN.json +1 -1
  33. package/package.json +1 -1
  34. package/packages/volto-slate/package.json +1 -1
  35. package/packages/volto-slate/src/actions/index.js +1 -1
  36. package/packages/volto-slate/src/blocks/Text/index.js +10 -2
  37. package/packages/volto-slate/src/editor/index.js +4 -4
  38. package/packages/volto-slate/src/editor/ui/SlateContextToolbar.jsx +2 -2
  39. package/packages/volto-slate/src/editor/ui/index.js +15 -15
  40. package/packages/volto-slate/src/index.js +2 -2
  41. package/src/components/manage/AnchorPlugin/index.jsx +2 -2
  42. package/src/components/manage/AnchorPlugin/utils/EditorUtils.js +3 -1
  43. package/src/components/manage/Blocks/Block/BlocksForm.jsx +19 -2
  44. package/src/components/manage/Blocks/Block/Edit.jsx +1 -1
  45. package/src/components/manage/Blocks/Block/Style.jsx +2 -2
  46. package/src/components/manage/Blocks/Container/Data.jsx +32 -0
  47. package/src/components/manage/Blocks/Container/Edit.jsx +174 -0
  48. package/src/components/manage/Blocks/Container/EditBlockWrapper.jsx +120 -0
  49. package/src/components/manage/Blocks/Container/NewBlockAddButton.jsx +84 -0
  50. package/src/components/manage/Blocks/Container/SimpleContainerToolbar.jsx +54 -0
  51. package/src/components/manage/Blocks/Grid/Edit.jsx +33 -0
  52. package/src/components/manage/Blocks/Grid/View.jsx +42 -0
  53. package/src/components/manage/Blocks/Grid/adapter.js +14 -0
  54. package/src/components/manage/Blocks/Grid/grid-1.svg +6 -0
  55. package/src/components/manage/Blocks/Grid/grid-2.svg +9 -0
  56. package/src/components/manage/Blocks/Grid/grid-3.svg +10 -0
  57. package/src/components/manage/Blocks/Grid/grid-4.svg +11 -0
  58. package/src/components/manage/Blocks/Grid/schema.js +35 -0
  59. package/src/components/manage/Blocks/Grid/templates.js +47 -0
  60. package/src/components/manage/Blocks/Image/ImageSidebar.jsx +2 -1
  61. package/src/components/manage/Blocks/Image/schema.js +11 -0
  62. package/src/components/manage/Blocks/Listing/DefaultTemplate.jsx +18 -3
  63. package/src/components/manage/Blocks/Listing/getAsyncData.js +3 -5
  64. package/src/components/manage/Blocks/Search/components/index.js +13 -13
  65. package/src/components/manage/Blocks/Search/hocs/index.js +2 -2
  66. package/src/components/manage/Blocks/Search/hocs/withQueryString.jsx +2 -2
  67. package/src/components/manage/Blocks/Teaser/schema.js +5 -0
  68. package/src/components/manage/Blocks/ToC/variations/index.js +3 -1
  69. package/src/components/manage/DragDropList/DragDropList.jsx +18 -13
  70. package/src/components/manage/TemplateChooser/TemplateChooser.jsx +38 -0
  71. package/src/components/manage/TemplateChooser/TemplateChooser.test.jsx +34 -0
  72. package/src/components/manage/TemplateChooser/template.svg +10 -0
  73. package/src/components/theme/Anontools/Anontools.stories.jsx +16 -6
  74. package/src/components/theme/Component/Component.jsx +1 -1
  75. package/src/components/theme/View/RenderBlocks.jsx +56 -27
  76. package/src/components/theme/View/RenderEmptyBlock.jsx +5 -0
  77. package/src/config/Blocks.jsx +44 -0
  78. package/src/config/RichTextEditor/Blocks.jsx +2 -2
  79. package/src/config/RichTextEditor/FromHTML.jsx +2 -2
  80. package/src/config/RichTextEditor/Styles.jsx +1 -1
  81. package/src/constants/Indexes.js +3 -1
  82. package/src/express-middleware/devproxy.js +1 -1
  83. package/src/express-middleware/files.js +3 -3
  84. package/src/express-middleware/images.js +4 -4
  85. package/src/express-middleware/robotstxt.js +1 -1
  86. package/src/express-middleware/sitemap.js +1 -1
  87. package/src/express-middleware/static.js +3 -3
  88. package/src/helpers/Blocks/Blocks.js +26 -0
  89. package/src/helpers/Blocks/Blocks.test.js +21 -0
  90. package/src/helpers/Extensions/index.js +2 -1
  91. package/src/helpers/Utils/UseDetectClickOutside.stories.jsx +191 -0
  92. package/src/helpers/Utils/Utils.js +25 -0
  93. package/src/helpers/index.js +11 -10
  94. package/src/icons/grid-block.svg +11 -0
  95. package/src/middleware/index.js +2 -2
  96. package/src/start-server.js +2 -2
  97. package/theme/themes/pastanaga/extras/blocks.less +3 -1
  98. package/theme/themes/pastanaga/extras/grid.less +426 -0
  99. package/theme/themes/pastanaga/extras/main.less +1 -0
@@ -2,7 +2,7 @@ import express from 'express';
2
2
  import path from 'path';
3
3
  import config from '@plone/volto/registry';
4
4
 
5
- const staticMiddleware = express.static(
5
+ const staticMiddlewareFn = express.static(
6
6
  process.env.BUILD_DIR
7
7
  ? path.join(process.env.BUILD_DIR, 'public')
8
8
  : process.env.RAZZLE_PUBLIC_DIR,
@@ -24,9 +24,9 @@ const staticMiddleware = express.static(
24
24
  },
25
25
  );
26
26
 
27
- export default function () {
27
+ export default function staticsMiddleware() {
28
28
  const middleware = express.Router();
29
- middleware.all('*', staticMiddleware);
29
+ middleware.all('*', staticMiddlewareFn);
30
30
  middleware.id = 'staticResourcesProcessor';
31
31
  return middleware;
32
32
  }
@@ -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
  });
@@ -1,5 +1,6 @@
1
1
  export * from './withBlockSchemaEnhancer';
2
- export withBlockExtensions, {
2
+ export {
3
+ default as withBlockExtensions,
3
4
  resolveExtension,
4
5
  resolveBlockExtensions,
5
6
  } from './withBlockExtensions';
@@ -0,0 +1,191 @@
1
+ import React from 'react';
2
+ import { useDetectClickOutside } from './useDetectClickOutside';
3
+ import { Portal } from 'react-portal';
4
+ import { usePopper } from 'react-popper';
5
+ import { BlockChooser } from '@plone/volto/components';
6
+
7
+ function OpenedChooser(props) {
8
+ const blockChooserRef = useDetectClickOutside({
9
+ onTriggered: () => props.setOpenMenu(false),
10
+ triggerKeys: ['Escape'],
11
+ });
12
+
13
+ return (
14
+ <div ref={blockChooserRef} style={{ marginLeft: '20px' }}>
15
+ Hello
16
+ </div>
17
+ );
18
+ }
19
+
20
+ function TestComponent(props) {
21
+ const [isOpenMenu, setOpenMenu] = React.useState(false);
22
+
23
+ return (
24
+ <div style={{ display: 'flex', marginBottom: '20px' }}>
25
+ <button onClick={() => setOpenMenu(true)}>Click me</button>
26
+ {isOpenMenu && <OpenedChooser setOpenMenu={setOpenMenu} />}
27
+ </div>
28
+ );
29
+ }
30
+
31
+ function StoryComponent(args) {
32
+ return (
33
+ <>
34
+ <TestComponent />
35
+ <TestComponent />
36
+ <TestComponent />
37
+ </>
38
+ );
39
+ }
40
+
41
+ function OpenedChooserWithPortal(props) {
42
+ const blockChooserRef = useDetectClickOutside({
43
+ onTriggered: () => props.setOpenMenu(false),
44
+ triggerKeys: ['Escape'],
45
+ });
46
+
47
+ return (
48
+ <Portal node={document.getElementById('body')}>
49
+ <div ref={blockChooserRef}>{`Hello ${props.id}`}</div>
50
+ </Portal>
51
+ );
52
+ }
53
+
54
+ function TestComponentWithPortal(props) {
55
+ const [isOpenMenu, setOpenMenu] = React.useState(false);
56
+
57
+ return (
58
+ <div style={{ display: 'flex', marginBottom: '20px' }}>
59
+ <button
60
+ onClick={() => setOpenMenu(true)}
61
+ >{`Click me ${props.id}`}</button>
62
+ {isOpenMenu && (
63
+ <OpenedChooserWithPortal {...props} setOpenMenu={setOpenMenu} />
64
+ )}
65
+ </div>
66
+ );
67
+ }
68
+
69
+ function StoryComponentWithPortal(args) {
70
+ return (
71
+ <>
72
+ <TestComponentWithPortal id={1} />
73
+ <TestComponentWithPortal id={2} />
74
+ <TestComponentWithPortal id={3} />
75
+ </>
76
+ );
77
+ }
78
+
79
+ function OpenedChooserWithPortalAndPopper(props) {
80
+ const { showBlockChooser } = props;
81
+
82
+ const blockChooserRef = useDetectClickOutside({
83
+ onTriggered: () => props.setOpenMenu(false),
84
+ triggerKeys: ['Escape'],
85
+ });
86
+
87
+ return showBlockChooser ? (
88
+ <BlockChooser
89
+ // onMutateBlock={onMutateBlock}
90
+ // currentBlock={block}
91
+ showRestricted
92
+ // blocksConfig={blocksConfig}
93
+ ref={blockChooserRef}
94
+ />
95
+ ) : (
96
+ <div ref={blockChooserRef}>{`Hello ${props.id}`}</div>
97
+ );
98
+ }
99
+
100
+ function TestComponentWithPortalAndPopper(props) {
101
+ const [isOpenMenu, setOpenMenu] = React.useState(false);
102
+ const [referenceElement, setReferenceElement] = React.useState(null);
103
+ const [popperElement, setPopperElement] = React.useState(null);
104
+ const { styles, attributes } = usePopper(referenceElement, popperElement, {
105
+ placement: 'right',
106
+ modifiers: [
107
+ {
108
+ name: 'offset',
109
+ options: {
110
+ offset: [-10, 10],
111
+ },
112
+ },
113
+ {
114
+ name: 'flip',
115
+ options: {
116
+ fallbackPlacements: ['top-start'],
117
+ },
118
+ },
119
+ ],
120
+ });
121
+ return (
122
+ <div style={{ display: 'flex', marginBottom: '20px' }}>
123
+ <button
124
+ ref={setReferenceElement}
125
+ onClick={() => setOpenMenu(true)}
126
+ >{`Click me ${props.id}`}</button>
127
+ <Portal node={document.getElementById('body')}>
128
+ <div
129
+ ref={setPopperElement}
130
+ style={styles.popper}
131
+ {...attributes.popper}
132
+ >
133
+ {isOpenMenu && (
134
+ <OpenedChooserWithPortalAndPopper
135
+ {...props}
136
+ setOpenMenu={setOpenMenu}
137
+ />
138
+ )}
139
+ </div>
140
+ </Portal>
141
+ </div>
142
+ );
143
+ }
144
+
145
+ function StoryComponentWithPortalAndPopper(args) {
146
+ const { showBlockChooser } = args;
147
+ return (
148
+ <>
149
+ <TestComponentWithPortalAndPopper
150
+ id={1}
151
+ showBlockChooser={showBlockChooser}
152
+ />
153
+ <TestComponentWithPortalAndPopper
154
+ id={2}
155
+ showBlockChooser={showBlockChooser}
156
+ />
157
+ <TestComponentWithPortalAndPopper
158
+ id={3}
159
+ showBlockChooser={showBlockChooser}
160
+ />
161
+ </>
162
+ );
163
+ }
164
+
165
+ export const Default = StoryComponent.bind({});
166
+ Default.args = {};
167
+
168
+ export const WithPortal = StoryComponentWithPortal.bind({});
169
+ WithPortal.args = {};
170
+
171
+ export const WithPortalAndPopper = StoryComponentWithPortalAndPopper.bind({});
172
+ WithPortalAndPopper.args = {};
173
+
174
+ export const WithPortalAndPopperUsingBlockChooser = StoryComponentWithPortalAndPopper.bind(
175
+ {},
176
+ );
177
+ WithPortalAndPopperUsingBlockChooser.args = {
178
+ showBlockChooser: true,
179
+ };
180
+
181
+ export default {
182
+ title: 'Internal Components/useDetectClickOutside',
183
+ component: TestComponent,
184
+ decorators: [
185
+ (Story) => (
186
+ <div style={{ width: '600px' }}>
187
+ <Story />
188
+ </div>
189
+ ),
190
+ ],
191
+ };
@@ -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
+ }
@@ -5,9 +5,9 @@
5
5
  */
6
6
 
7
7
  // export { injectLazyLibs } from './Loadable/Loadable';
8
- export Api from '@plone/volto/helpers/Api/Api';
8
+ export { default as Api } from '@plone/volto/helpers/Api/Api';
9
9
  export { getAPIResourceWithAuth } from '@plone/volto/helpers/Api/APIResourceWithAuth';
10
- export Html from '@plone/volto/helpers/Html/Html';
10
+ export { default as Html } from '@plone/volto/helpers/Html/Html';
11
11
  export {
12
12
  getAuthToken,
13
13
  persistAuthToken,
@@ -54,12 +54,13 @@ export {
54
54
  previousBlockId,
55
55
  applyBlockDefaults,
56
56
  applySchemaDefaults,
57
+ blocksFormGenerator,
57
58
  buildStyleClassNamesFromData,
58
59
  buildStyleClassNamesExtenders,
59
60
  getPreviousNextBlock,
60
61
  } from '@plone/volto/helpers/Blocks/Blocks';
61
- export BodyClass from '@plone/volto/helpers/BodyClass/BodyClass';
62
- export ScrollToTop from '@plone/volto/helpers/ScrollToTop/ScrollToTop';
62
+ export { default as BodyClass } from '@plone/volto/helpers/BodyClass/BodyClass';
63
+ export { default as ScrollToTop } from '@plone/volto/helpers/ScrollToTop/ScrollToTop';
63
64
  export {
64
65
  getBoolean,
65
66
  getVocabName,
@@ -69,11 +70,10 @@ export {
69
70
  getFieldsVocabulary,
70
71
  } from '@plone/volto/helpers/Vocabularies/Vocabularies';
71
72
 
72
- export langmap from './LanguageMap/LanguageMap';
73
- export Helmet from './Helmet/Helmet';
74
- export FormValidation, {
75
- validateFileUploadSize,
76
- } from './FormValidation/FormValidation';
73
+ export { default as langmap } from './LanguageMap/LanguageMap';
74
+ export { default as Helmet } from './Helmet/Helmet';
75
+ export { default as FormValidation } from './FormValidation/FormValidation';
76
+ export { validateFileUploadSize } from './FormValidation/FormValidation';
77
77
  export {
78
78
  difference,
79
79
  getColor,
@@ -92,6 +92,7 @@ export {
92
92
  cloneDeepSchema,
93
93
  arrayRange,
94
94
  reorderArray,
95
+ isInteractiveElement,
95
96
  } from '@plone/volto/helpers/Utils/Utils';
96
97
  export { messages } from './MessageLabels/MessageLabels';
97
98
  export {
@@ -111,7 +112,7 @@ export { useDetectClickOutside } from './Utils/useDetectClickOutside';
111
112
  export { useEvent } from './Utils/useEvent';
112
113
  export { usePrevious } from './Utils/usePrevious';
113
114
  export { usePagination } from './Utils/usePagination';
114
- export useUndoManager from './UndoManager/useUndoManager';
115
+ export { default as useUndoManager } from './UndoManager/useUndoManager';
115
116
  export { getCookieOptions } from './Cookies/cookies';
116
117
  export { getWidgetView } from './Widget/widget';
117
118
  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>
@@ -4,8 +4,8 @@
4
4
  * @example import { api } from 'middleware';
5
5
  */
6
6
 
7
- export api from '@plone/volto/middleware/api';
8
- export blacklistRoutes from './blacklistRoutes';
7
+ export { default as api } from '@plone/volto/middleware/api';
8
+ export { default as blacklistRoutes } from './blacklistRoutes';
9
9
  export {
10
10
  protectLoadStart,
11
11
  protectLoadEnd,
@@ -4,7 +4,7 @@ import http from 'http';
4
4
  import app from './server';
5
5
  import debug from 'debug';
6
6
 
7
- export default () => {
7
+ export default function server() {
8
8
  const server = http.createServer(app);
9
9
  // const host = process.env.HOST || 'localhost';
10
10
  const port = process.env.PORT || 3000;
@@ -46,4 +46,4 @@ export default () => {
46
46
  currentApp = newApp;
47
47
  });
48
48
  };
49
- };
49
+ }
@@ -477,7 +477,9 @@ body.has-toolbar.has-sidebar-collapsed .ui.wrapper > .ui.inner.block.full {
477
477
 
478
478
  &.new-add-block {
479
479
  bottom: -26px;
480
- left: 50%;
480
+ left: calc(
481
+ 50% - 12px
482
+ ); // This is to compensate the width of the icon and center it correctly
481
483
  padding: 0 !important;
482
484
  border: none !important;
483
485
  background: white !important;