@plone/volto 17.0.0-alpha.13 → 17.0.0-alpha.15

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 (84) hide show
  1. package/.yarn/install-state.gz +0 -0
  2. package/CHANGELOG.md +68 -0
  3. package/README.md +2 -2
  4. package/docker-compose.yml +1 -1
  5. package/locales/ca/LC_MESSAGES/volto.po +5 -0
  6. package/locales/ca.json +1 -1
  7. package/locales/de/LC_MESSAGES/volto.po +5 -0
  8. package/locales/de.json +1 -1
  9. package/locales/en/LC_MESSAGES/volto.po +5 -0
  10. package/locales/en.json +1 -1
  11. package/locales/es/LC_MESSAGES/volto.po +49 -44
  12. package/locales/es.json +1 -1
  13. package/locales/eu/LC_MESSAGES/volto.po +5 -0
  14. package/locales/eu.json +1 -1
  15. package/locales/fi/LC_MESSAGES/volto.po +5 -0
  16. package/locales/fi.json +1 -1
  17. package/locales/fr/LC_MESSAGES/volto.po +5 -0
  18. package/locales/fr.json +1 -1
  19. package/locales/it/LC_MESSAGES/volto.po +5 -0
  20. package/locales/it.json +1 -1
  21. package/locales/ja/LC_MESSAGES/volto.po +5 -0
  22. package/locales/ja.json +1 -1
  23. package/locales/nl/LC_MESSAGES/volto.po +5 -0
  24. package/locales/nl.json +1 -1
  25. package/locales/pt/LC_MESSAGES/volto.po +5 -0
  26. package/locales/pt.json +1 -1
  27. package/locales/pt_BR/LC_MESSAGES/volto.po +5 -0
  28. package/locales/pt_BR.json +1 -1
  29. package/locales/ro/LC_MESSAGES/volto.po +5 -0
  30. package/locales/ro.json +1 -1
  31. package/locales/volto.pot +5 -0
  32. package/locales/zh_CN/LC_MESSAGES/volto.po +5 -0
  33. package/locales/zh_CN.json +1 -1
  34. package/package.json +2 -1
  35. package/packages/volto-slate/package.json +1 -1
  36. package/packages/volto-slate/src/actions/index.js +1 -1
  37. package/packages/volto-slate/src/blocks/Text/TextBlockView.jsx +20 -16
  38. package/packages/volto-slate/src/blocks/Text/index.js +2 -2
  39. package/packages/volto-slate/src/editor/config.jsx +5 -4
  40. package/packages/volto-slate/src/editor/index.js +4 -4
  41. package/packages/volto-slate/src/editor/less/slate.less +28 -0
  42. package/packages/volto-slate/src/editor/render.jsx +68 -8
  43. package/packages/volto-slate/src/editor/ui/SlateContextToolbar.jsx +2 -2
  44. package/packages/volto-slate/src/editor/ui/index.js +15 -15
  45. package/packages/volto-slate/src/index.js +2 -2
  46. package/src/components/manage/AnchorPlugin/index.jsx +2 -2
  47. package/src/components/manage/AnchorPlugin/utils/EditorUtils.js +3 -1
  48. package/src/components/manage/Blocks/Block/Style.jsx +2 -2
  49. package/src/components/manage/Blocks/Listing/DefaultTemplate.jsx +18 -3
  50. package/src/components/manage/Blocks/Listing/ListingBody.jsx +30 -8
  51. package/src/components/manage/Blocks/Listing/getAsyncData.js +3 -5
  52. package/src/components/manage/Blocks/Search/components/index.js +13 -13
  53. package/src/components/manage/Blocks/Search/hocs/index.js +2 -2
  54. package/src/components/manage/Blocks/Search/hocs/withQueryString.jsx +2 -2
  55. package/src/components/manage/Blocks/Title/View.jsx +15 -5
  56. package/src/components/manage/Blocks/Title/View.test.jsx +16 -1
  57. package/src/components/manage/Blocks/ToC/View.jsx +8 -1
  58. package/src/components/manage/Blocks/ToC/variations/DefaultTocRenderer.jsx +17 -4
  59. package/src/components/manage/Blocks/ToC/variations/HorizontalMenu.jsx +6 -2
  60. package/src/components/manage/Blocks/ToC/variations/index.js +3 -1
  61. package/src/components/theme/Anontools/Anontools.jsx +45 -72
  62. package/src/components/theme/Anontools/Anontools.stories.jsx +16 -6
  63. package/src/components/theme/Anontools/Anontools.test.jsx +16 -2
  64. package/src/config/RichTextEditor/Blocks.jsx +2 -2
  65. package/src/config/RichTextEditor/FromHTML.jsx +2 -2
  66. package/src/config/RichTextEditor/Styles.jsx +1 -1
  67. package/src/constants/Indexes.js +3 -1
  68. package/src/express-middleware/devproxy.js +1 -1
  69. package/src/express-middleware/files.js +3 -3
  70. package/src/express-middleware/images.js +4 -4
  71. package/src/express-middleware/robotstxt.js +1 -1
  72. package/src/express-middleware/sitemap.js +1 -1
  73. package/src/express-middleware/static.js +3 -3
  74. package/src/helpers/Extensions/index.js +2 -1
  75. package/src/helpers/MessageLabels/MessageLabels.js +4 -0
  76. package/src/helpers/ScrollToTop/ScrollToTop.jsx +5 -3
  77. package/src/helpers/Utils/UseDetectClickOutside.stories.jsx +191 -0
  78. package/src/helpers/index.js +9 -10
  79. package/src/hooks/clipboard/useClipboard.js +26 -0
  80. package/src/hooks/content/useContent.js +31 -0
  81. package/src/hooks/index.js +2 -0
  82. package/src/middleware/index.js +2 -2
  83. package/src/start-server.js +2 -2
  84. package/theme/themes/pastanaga/extras/blocks.less +3 -1
@@ -9,15 +9,19 @@ import { map } from 'lodash';
9
9
  import { Menu } from 'semantic-ui-react';
10
10
  import { FormattedMessage, injectIntl } from 'react-intl';
11
11
  import AnchorLink from 'react-anchor-link-smooth-scroll';
12
+ import Slugger from 'github-slugger';
12
13
 
13
14
  const RenderMenuItems = ({ items }) => {
14
15
  return map(items, (item) => {
15
- const { id, level, title } = item;
16
+ const { id, level, title, override_toc, plaintext } = item;
17
+ const slug = override_toc
18
+ ? Slugger.slug(plaintext)
19
+ : Slugger.slug(title) || id;
16
20
  return (
17
21
  item && (
18
22
  <React.Fragment key={id}>
19
23
  <Menu.Item className={`headline-${level}`}>
20
- <AnchorLink href={`#${id}`}>{title}</AnchorLink>
24
+ <AnchorLink href={`#${slug}`}>{title}</AnchorLink>
21
25
  </Menu.Item>
22
26
  {item.items?.length > 0 && <RenderMenuItems items={item.items} />}
23
27
  </React.Fragment>
@@ -1,7 +1,7 @@
1
1
  import DefaultTocRenderer from './DefaultTocRenderer';
2
2
  import HorizontalMenu from './HorizontalMenu';
3
3
 
4
- export default [
4
+ const ToCVariations = [
5
5
  {
6
6
  id: 'default',
7
7
  title: 'Listing (default)',
@@ -14,3 +14,5 @@ export default [
14
14
  view: HorizontalMenu,
15
15
  },
16
16
  ];
17
+
18
+ export default ToCVariations;
@@ -1,83 +1,56 @@
1
- /**
2
- * Anontools component.
3
- * @module components/theme/Anontools/Anontools
4
- */
5
-
6
- import React, { Component } from 'react';
7
1
  import PropTypes from 'prop-types';
8
- import { connect } from 'react-redux';
9
2
  import { Link } from 'react-router-dom';
10
3
  import { Menu } from 'semantic-ui-react';
11
4
  import { FormattedMessage } from 'react-intl';
5
+ import { flattenToAppURL } from '@plone/volto/helpers';
6
+ import { useToken } from '@plone/volto/hooks/userSession/useToken';
7
+ import { useContent } from '@plone/volto/hooks/content/useContent';
12
8
  import config from '@plone/volto/registry';
13
9
 
14
- /**
15
- * Anontools container class.
16
- */
17
- export class Anontools extends Component {
18
- /**
19
- * Property types.
20
- * @property {Object} propTypes Property types.
21
- * @static
22
- */
23
- static propTypes = {
24
- token: PropTypes.string,
25
- content: PropTypes.shape({
26
- '@id': PropTypes.string,
27
- }),
28
- };
29
-
30
- /**
31
- * Default properties.
32
- * @property {Object} defaultProps Default properties.
33
- * @static
34
- */
35
- static defaultProps = {
36
- token: null,
37
- content: {
38
- '@id': null,
39
- },
40
- };
10
+ const Anontools = () => {
11
+ const token = useToken();
12
+ const { data: content } = useContent();
41
13
 
42
- /**
43
- * Render method.
44
- * @method render
45
- * @returns {string} Markup for the component.
46
- */
47
- render() {
48
- const { settings } = config;
49
- return (
50
- !this.props.token && (
51
- <Menu pointing secondary floated="right">
14
+ const { settings } = config;
15
+ return (
16
+ !token && (
17
+ <Menu pointing secondary floated="right">
18
+ <Menu.Item>
19
+ <Link
20
+ aria-label="login"
21
+ to={`/login${
22
+ content?.['@id']
23
+ ? `?return_url=${flattenToAppURL(content['@id'])}`
24
+ : ''
25
+ }`}
26
+ >
27
+ <FormattedMessage id="Log in" defaultMessage="Log in" />
28
+ </Link>
29
+ </Menu.Item>
30
+ {settings.showSelfRegistration && (
52
31
  <Menu.Item>
53
- <Link
54
- aria-label="login"
55
- to={`/login${
56
- this.props.content?.['@id']
57
- ? `?return_url=${this.props.content['@id'].replace(
58
- settings.apiPath,
59
- '',
60
- )}`
61
- : ''
62
- }`}
63
- >
64
- <FormattedMessage id="Log in" defaultMessage="Log in" />
32
+ <Link aria-label="register" to="/register">
33
+ <FormattedMessage id="Register" defaultMessage="Register" />
65
34
  </Link>
66
35
  </Menu.Item>
67
- {settings.showSelfRegistration && (
68
- <Menu.Item>
69
- <Link aria-label="register" to="/register">
70
- <FormattedMessage id="Register" defaultMessage="Register" />
71
- </Link>
72
- </Menu.Item>
73
- )}
74
- </Menu>
75
- )
76
- );
77
- }
78
- }
36
+ )}
37
+ </Menu>
38
+ )
39
+ );
40
+ };
41
+
42
+ export default Anontools;
43
+
44
+ Anontools.propTypes = {
45
+ token: PropTypes.string,
46
+ content: PropTypes.shape({
47
+ '@id': PropTypes.string,
48
+ }),
49
+ };
79
50
 
80
- export default connect((state) => ({
81
- token: state.userSession.token,
82
- content: state.content.data,
83
- }))(Anontools);
51
+ Anontools.defaultProps = {
52
+ token: null,
53
+ content: {
54
+ '@id': null,
55
+ },
56
+ };
@@ -1,15 +1,25 @@
1
1
  import React from 'react';
2
- import { Anontools as AnontoolsDefault } from './Anontools';
2
+ import AnontoolsDefault from './Anontools';
3
3
  import Wrapper from '@plone/volto/storybook';
4
4
 
5
5
  const AnontoolsComponent = ({ children, ...args }) => {
6
6
  return (
7
- <Wrapper location={{ pathname: '/folder2/folder21/doc212' }}>
7
+ <Wrapper
8
+ anonymous
9
+ location={{ pathname: '/folder2/folder21/doc212' }}
10
+ customStore={{
11
+ content: {
12
+ data: { '@id': 'http://myreturnURL' },
13
+ get: {
14
+ loaded: false,
15
+ loading: false,
16
+ error: null,
17
+ },
18
+ },
19
+ }}
20
+ >
8
21
  <div className="ui segment form attached" style={{ width: '400px' }}>
9
- <AnontoolsDefault
10
- userSession={{ token: null }}
11
- content={{ '@id': 'myid' }}
12
- />
22
+ <AnontoolsDefault />
13
23
  </div>
14
24
  </Wrapper>
15
25
  );
@@ -12,7 +12,14 @@ describe('Anontools', () => {
12
12
  it('renders an anontools component when no token is specified', () => {
13
13
  const store = mockStore({
14
14
  userSession: { token: null },
15
- content: { data: { '@id': 'myid' } },
15
+ content: {
16
+ data: { '@id': 'myid' },
17
+ get: {
18
+ loading: false,
19
+ loaded: true,
20
+ error: null,
21
+ },
22
+ },
16
23
  intl: {
17
24
  locale: 'en',
18
25
  messages: {},
@@ -32,7 +39,14 @@ describe('Anontools', () => {
32
39
  it('should not render an anontools component when a token is specified', () => {
33
40
  const store = mockStore({
34
41
  userSession: { token: '1234' },
35
- content: { data: {} },
42
+ content: {
43
+ data: {},
44
+ get: {
45
+ loading: false,
46
+ loaded: true,
47
+ error: null,
48
+ },
49
+ },
36
50
  intl: {
37
51
  locale: 'en',
38
52
  messages: {},
@@ -1,4 +1,4 @@
1
- export default (props) => {
1
+ export default function Blocks(props) {
2
2
  const { draftJs, immutableLib } = props;
3
3
  const { DefaultDraftBlockRenderMap } = draftJs;
4
4
  const { Map } = immutableLib;
@@ -27,4 +27,4 @@ export default (props) => {
27
27
  const listBlockTypes = ['unordered-list-item', 'ordered-list-item'];
28
28
 
29
29
  return { extendedBlockRenderMap, blockStyleFn, listBlockTypes };
30
- };
30
+ }
@@ -1,8 +1,8 @@
1
- export default (element) => {
1
+ export default function FromHTMLCustomBlockFn(element) {
2
2
  if (element.className === 'callout') {
3
3
  return {
4
4
  type: 'callout',
5
5
  };
6
6
  }
7
7
  return null;
8
- };
8
+ }
@@ -13,7 +13,7 @@ import orderedListSVG from '@plone/volto/icons/list-numbered.svg';
13
13
  import blockquoteSVG from '@plone/volto/icons/quote.svg';
14
14
  import calloutSVG from '@plone/volto/icons/megaphone.svg';
15
15
 
16
- export default function (props) {
16
+ export default function Styles(props) {
17
17
  const createInlineStyleButton = props.draftJsCreateInlineStyleButton.default;
18
18
  const createBlockStyleButton = props.draftJsCreateBlockStyleButton.default;
19
19
 
@@ -3,7 +3,7 @@
3
3
  * @module constants/indexes
4
4
  */
5
5
 
6
- export default {
6
+ const Indexes = {
7
7
  sortable_title: { label: 'Title', type: 'string', sort_on: 'sortable_title' },
8
8
  review_state: { label: 'Review state', type: 'string' },
9
9
  ModificationDate: {
@@ -35,6 +35,8 @@ export default {
35
35
  Type: { label: 'Type', type: 'string' },
36
36
  };
37
37
 
38
+ export default Indexes;
39
+
38
40
  export const defaultIndexes = [
39
41
  'review_state',
40
42
  'ModificationDate',
@@ -37,7 +37,7 @@ function getEnv() {
37
37
  return _env;
38
38
  }
39
39
 
40
- export default function () {
40
+ export default function devProxyMiddleware() {
41
41
  const middleware = express.Router();
42
42
  const devProxy = createProxyMiddleware(filter, {
43
43
  selfHandleResponse: true,
@@ -9,7 +9,7 @@ const HEADERS = [
9
9
  'Content-Type',
10
10
  ];
11
11
 
12
- function fileMiddleware(req, res, next) {
12
+ function filesMiddlewareFn(req, res, next) {
13
13
  getAPIResourceWithAuth(req)
14
14
  .then((resource) => {
15
15
  // Just forward the headers that we need
@@ -24,10 +24,10 @@ function fileMiddleware(req, res, next) {
24
24
  .catch(next);
25
25
  }
26
26
 
27
- export default function () {
27
+ export default function filesMiddleware() {
28
28
  const middleware = express.Router();
29
29
 
30
- middleware.all(['**/@@download/*', '**/@@display-file/*'], fileMiddleware);
30
+ middleware.all(['**/@@download/*', '**/@@display-file/*'], filesMiddlewareFn);
31
31
  middleware.id = 'filesResourcesProcessor';
32
32
  return middleware;
33
33
  }
@@ -3,7 +3,7 @@ import { getAPIResourceWithAuth } from '@plone/volto/helpers';
3
3
 
4
4
  const HEADERS = ['content-type', 'content-disposition', 'cache-control'];
5
5
 
6
- function imageMiddleware(req, res, next) {
6
+ function imageMiddlewareFn(req, res, next) {
7
7
  getAPIResourceWithAuth(req)
8
8
  .then((resource) => {
9
9
  // Just forward the headers that we need
@@ -17,11 +17,11 @@ function imageMiddleware(req, res, next) {
17
17
  .catch(next);
18
18
  }
19
19
 
20
- export default function () {
20
+ export default function imagesMiddleware() {
21
21
  const middleware = express.Router();
22
22
 
23
- middleware.all(['**/@@images/*'], imageMiddleware);
24
- middleware.all(['/@portrait/*'], imageMiddleware);
23
+ middleware.all(['**/@@images/*'], imageMiddlewareFn);
24
+ middleware.all(['/@portrait/*'], imageMiddlewareFn);
25
25
  middleware.id = 'imageResourcesProcessor';
26
26
  return middleware;
27
27
  }
@@ -22,7 +22,7 @@ const envRobots = function (req, res, next) {
22
22
  res.send(process.env.VOLTO_ROBOTSTXT);
23
23
  };
24
24
 
25
- export default function () {
25
+ export default function robotstxtMiddleware() {
26
26
  const middleware = express.Router();
27
27
  if (process.env.VOLTO_ROBOTSTXT) {
28
28
  middleware.all('**/robots.txt', envRobots);
@@ -47,7 +47,7 @@ export const sitemapIndex = function (req, res, next) {
47
47
  });
48
48
  };
49
49
 
50
- export default function () {
50
+ export default function sitemapMiddleware() {
51
51
  const middleware = express.Router();
52
52
 
53
53
  middleware.all('**/sitemap.xml.gz', sitemap);
@@ -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
  }
@@ -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';
@@ -260,6 +260,10 @@ export const messages = defineMessages({
260
260
  id: 'Show groups of users below',
261
261
  defaultMessage: 'Show groups of users below',
262
262
  },
263
+ urlClipboardCopy: {
264
+ id: 'Link copied to clipboard',
265
+ defaultMessage: 'Link copied to clipboard',
266
+ },
263
267
  inspectRelations: {
264
268
  id: 'Inspect relations',
265
269
  defaultMessage: 'Inspect relations',
@@ -28,15 +28,17 @@ class ScrollToTop extends React.Component {
28
28
  * @memberof ScrollToTop
29
29
  */
30
30
  componentDidUpdate(prevProps) {
31
+ const { location } = this.props;
31
32
  const noInitialBlocksFocus = // Do not scroll on /edit
32
33
  config.blocks?.initialBlocksFocus === null
33
34
  ? this.props.location?.pathname.slice(-5) !== '/edit'
34
35
  : true;
36
+
37
+ const isHash = location?.hash || location?.pathname.hash;
35
38
  if (
36
- !this.props.location?.hash &&
37
- !this.props.location?.pathname.hash &&
39
+ !isHash &&
38
40
  noInitialBlocksFocus &&
39
- this.props.location?.pathname !== prevProps.location?.pathname
41
+ location?.pathname !== prevProps.location?.pathname
40
42
  ) {
41
43
  window.scrollTo(0, 0);
42
44
  }
@@ -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
+ };
@@ -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,
@@ -58,8 +58,8 @@ export {
58
58
  buildStyleClassNamesExtenders,
59
59
  getPreviousNextBlock,
60
60
  } from '@plone/volto/helpers/Blocks/Blocks';
61
- export BodyClass from '@plone/volto/helpers/BodyClass/BodyClass';
62
- export ScrollToTop from '@plone/volto/helpers/ScrollToTop/ScrollToTop';
61
+ export { default as BodyClass } from '@plone/volto/helpers/BodyClass/BodyClass';
62
+ export { default as ScrollToTop } from '@plone/volto/helpers/ScrollToTop/ScrollToTop';
63
63
  export {
64
64
  getBoolean,
65
65
  getVocabName,
@@ -69,11 +69,10 @@ export {
69
69
  getFieldsVocabulary,
70
70
  } from '@plone/volto/helpers/Vocabularies/Vocabularies';
71
71
 
72
- export langmap from './LanguageMap/LanguageMap';
73
- export Helmet from './Helmet/Helmet';
74
- export FormValidation, {
75
- validateFileUploadSize,
76
- } from './FormValidation/FormValidation';
72
+ export { default as langmap } from './LanguageMap/LanguageMap';
73
+ export { default as Helmet } from './Helmet/Helmet';
74
+ export { default as FormValidation } from './FormValidation/FormValidation';
75
+ export { validateFileUploadSize } from './FormValidation/FormValidation';
77
76
  export {
78
77
  difference,
79
78
  getColor,
@@ -111,7 +110,7 @@ export { useDetectClickOutside } from './Utils/useDetectClickOutside';
111
110
  export { useEvent } from './Utils/useEvent';
112
111
  export { usePrevious } from './Utils/usePrevious';
113
112
  export { usePagination } from './Utils/usePagination';
114
- export useUndoManager from './UndoManager/useUndoManager';
113
+ export { default as useUndoManager } from './UndoManager/useUndoManager';
115
114
  export { getCookieOptions } from './Cookies/cookies';
116
115
  export { getWidgetView } from './Widget/widget';
117
116
  export {