@plone/volto 17.0.0-alpha.14 → 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 (36) hide show
  1. package/.yarn/install-state.gz +0 -0
  2. package/CHANGELOG.md +17 -0
  3. package/package.json +1 -1
  4. package/packages/volto-slate/package.json +1 -1
  5. package/packages/volto-slate/src/actions/index.js +1 -1
  6. package/packages/volto-slate/src/blocks/Text/index.js +2 -2
  7. package/packages/volto-slate/src/editor/index.js +4 -4
  8. package/packages/volto-slate/src/editor/ui/SlateContextToolbar.jsx +2 -2
  9. package/packages/volto-slate/src/editor/ui/index.js +15 -15
  10. package/packages/volto-slate/src/index.js +2 -2
  11. package/src/components/manage/AnchorPlugin/index.jsx +2 -2
  12. package/src/components/manage/AnchorPlugin/utils/EditorUtils.js +3 -1
  13. package/src/components/manage/Blocks/Block/Style.jsx +2 -2
  14. package/src/components/manage/Blocks/Listing/DefaultTemplate.jsx +18 -3
  15. package/src/components/manage/Blocks/Listing/getAsyncData.js +3 -5
  16. package/src/components/manage/Blocks/Search/components/index.js +13 -13
  17. package/src/components/manage/Blocks/Search/hocs/index.js +2 -2
  18. package/src/components/manage/Blocks/Search/hocs/withQueryString.jsx +2 -2
  19. package/src/components/manage/Blocks/ToC/variations/index.js +3 -1
  20. package/src/components/theme/Anontools/Anontools.stories.jsx +16 -6
  21. package/src/config/RichTextEditor/Blocks.jsx +2 -2
  22. package/src/config/RichTextEditor/FromHTML.jsx +2 -2
  23. package/src/config/RichTextEditor/Styles.jsx +1 -1
  24. package/src/constants/Indexes.js +3 -1
  25. package/src/express-middleware/devproxy.js +1 -1
  26. package/src/express-middleware/files.js +3 -3
  27. package/src/express-middleware/images.js +4 -4
  28. package/src/express-middleware/robotstxt.js +1 -1
  29. package/src/express-middleware/sitemap.js +1 -1
  30. package/src/express-middleware/static.js +3 -3
  31. package/src/helpers/Extensions/index.js +2 -1
  32. package/src/helpers/Utils/UseDetectClickOutside.stories.jsx +191 -0
  33. package/src/helpers/index.js +9 -10
  34. package/src/middleware/index.js +2 -2
  35. package/src/start-server.js +2 -2
  36. package/theme/themes/pastanaga/extras/blocks.less +3 -1
Binary file
package/CHANGELOG.md CHANGED
@@ -8,6 +8,23 @@
8
8
 
9
9
  <!-- towncrier release notes start -->
10
10
 
11
+ ## 17.0.0-alpha.15 (2023-06-28)
12
+
13
+ ### Breaking
14
+
15
+ - Use proper heading tag (depending on the headline) in default listing template @sneridagh [#4848](https://github.com/plone/volto/issues/4848)
16
+
17
+ ### Bugfix
18
+
19
+ - Remove anonymous function calls. Remove default exports from. @sneridagh [#4917](https://github.com/plone/volto/issues/4917)
20
+ - Fix Annontools StoryBook @sneridagh [#4921](https://github.com/plone/volto/issues/4921)
21
+ - Fix the experimental add new block button position, compensate the icon width to center it correctly @sneridagh [#4924](https://github.com/plone/volto/issues/4924)
22
+
23
+ ### Internal
24
+
25
+ - Add Storybook story for useDetectClickOutside hook with several demos @sneridagh [#4923](https://github.com/plone/volto/issues/4923)
26
+
27
+
11
28
  ## 17.0.0-alpha.14 (2023-06-23)
12
29
 
13
30
  ### Feature
package/package.json CHANGED
@@ -9,7 +9,7 @@
9
9
  }
10
10
  ],
11
11
  "license": "MIT",
12
- "version": "17.0.0-alpha.14",
12
+ "version": "17.0.0-alpha.15",
13
13
  "repository": {
14
14
  "type": "git",
15
15
  "url": "git@github.com:plone/volto.git"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plone/volto-slate",
3
- "version": "17.0.0-alpha.14",
3
+ "version": "17.0.0-alpha.15",
4
4
  "description": "Slate.js integration with Volto",
5
5
  "main": "src/index.js",
6
6
  "author": "European Environment Agency: IDM2 A-Team",
@@ -1,3 +1,3 @@
1
- export saveSlateBlockSelection from './selection';
1
+ export { default as saveSlateBlockSelection } from './selection';
2
2
  export * from './content';
3
3
  export * from './plugins';
@@ -35,7 +35,7 @@ import textSVG from '@plone/volto/icons/subtext.svg';
35
35
 
36
36
  export { TextBlockView, TextBlockEdit, TextBlockSchema };
37
37
 
38
- export default (config) => {
38
+ export default function applyConfig(config) {
39
39
  config.settings.slate = {
40
40
  // TODO: should we inverse order? First here gets executed last
41
41
  textblockExtensions: [
@@ -165,4 +165,4 @@ export default (config) => {
165
165
  restricted: true,
166
166
  };
167
167
  return config;
168
- };
168
+ }
@@ -1,9 +1,9 @@
1
1
  import * as slateConfig from './config';
2
2
  import installDefaultPlugins from './plugins';
3
- export SlateEditor from './SlateEditor';
4
- export EditorReference from './EditorReference';
3
+ export { default as SlateEditor } from './SlateEditor';
4
+ export { default as EditorReference } from './EditorReference';
5
5
 
6
- export default (config) => {
6
+ export default function applyConfig(config) {
7
7
  config.settings.slate = {
8
8
  ...slateConfig,
9
9
  // showExpandedToolbar: false,
@@ -11,4 +11,4 @@ export default (config) => {
11
11
  };
12
12
  config = installDefaultPlugins(config);
13
13
  return config;
14
- };
14
+ }
@@ -3,11 +3,11 @@ import Toolbar from './Toolbar';
3
3
 
4
4
  // A toolbar that conditionally renders itself based on the presense of
5
5
  // children
6
- export default ({ editor, plugins, show }) => {
6
+ export default function SlateContextToolbar({ editor, plugins, show }) {
7
7
  if (!show) {
8
8
  return null;
9
9
  }
10
10
 
11
11
  const components = plugins.map((plug) => plug(editor)).filter((c) => !!c);
12
12
  return components.length ? <Toolbar>{components}</Toolbar> : '';
13
- };
13
+ }
@@ -1,15 +1,15 @@
1
- export BasicToolbar from './BasicToolbar';
2
- export BlockButton from './BlockButton';
3
- export ClearFormattingButton from './ClearFormattingButton';
4
- export ExpandedToolbar from './ExpandedToolbar';
5
- export Expando from './Expando';
6
- export MarkButton from './MarkButton';
7
- export Menu from './Menu';
8
- export Separator from './Separator';
9
- export SlateContextToolbar from './SlateContextToolbar';
10
- export SlateToolbar from './SlateToolbar';
11
- export Toolbar from './Toolbar';
12
- export ToolbarButton from './ToolbarButton';
13
- export MarkElementButton from './MarkElementButton';
14
- export PositionedToolbar from './PositionedToolbar';
15
- export InlineToolbar from './InlineToolbar';
1
+ export { default as BasicToolbar } from './BasicToolbar';
2
+ export { default as BlockButton } from './BlockButton';
3
+ export { default as ClearFormattingButton } from './ClearFormattingButton';
4
+ export { default as ExpandedToolbar } from './ExpandedToolbar';
5
+ export { default as Expando } from './Expando';
6
+ export { default as MarkButton } from './MarkButton';
7
+ export { default as Menu } from './Menu';
8
+ export { default as Separator } from './Separator';
9
+ export { default as SlateContextToolbar } from './SlateContextToolbar';
10
+ export { default as SlateToolbar } from './SlateToolbar';
11
+ export { default as Toolbar } from './Toolbar';
12
+ export { default as ToolbarButton } from './ToolbarButton';
13
+ export { default as MarkElementButton } from './MarkElementButton';
14
+ export { default as PositionedToolbar } from './PositionedToolbar';
15
+ export { default as InlineToolbar } from './InlineToolbar';
@@ -8,7 +8,7 @@ import RichTextWidgetView from './widgets/RichTextWidgetView';
8
8
  import HtmlSlateWidget from './widgets/HtmlSlateWidget';
9
9
  import ObjectByTypeWidget from './widgets/ObjectByTypeWidget';
10
10
 
11
- export default (config) => {
11
+ export default function applyConfig(config) {
12
12
  config = [installSlate, installTextBlock, installTableBlock].reduce(
13
13
  (acc, apply) => apply(acc),
14
14
  config,
@@ -58,4 +58,4 @@ export default (config) => {
58
58
  }
59
59
 
60
60
  return config;
61
- };
61
+ }
@@ -44,7 +44,7 @@ function unboundRemoveEntity(editorState) {
44
44
  return newEditorState;
45
45
  }
46
46
 
47
- export default (config = {}) => {
47
+ export default function AnchorPlugin(config = {}) {
48
48
  // ToDo: Get rif of the remainings of having the original CSS modules
49
49
  const defaultTheme = {};
50
50
 
@@ -79,4 +79,4 @@ export default (config = {}) => {
79
79
  setEditorState(removeEntity(getEditorState())),
80
80
  }),
81
81
  };
82
- };
82
+ }
@@ -1,4 +1,4 @@
1
- export default ({ draftJs }) => ({
1
+ const EditorUtils = ({ draftJs }) => ({
2
2
  createLinkAtSelection(editorState, url) {
3
3
  const contentState = editorState
4
4
  .getCurrentContent()
@@ -43,3 +43,5 @@ export default ({ draftJs }) => ({
43
43
  return entity && entity.getType() === entityType;
44
44
  },
45
45
  });
46
+
47
+ export default EditorUtils;
@@ -1,7 +1,7 @@
1
1
  import React from 'react';
2
2
  import cx from 'classnames';
3
3
 
4
- export default ({ data, detached, children }) => {
4
+ export default function Style({ data, detached, children }) {
5
5
  return (
6
6
  <div
7
7
  className={cx(
@@ -25,4 +25,4 @@ export default ({ data, detached, children }) => {
25
25
  </div>
26
26
  </div>
27
27
  );
28
- };
28
+ }
@@ -2,10 +2,15 @@ import React from 'react';
2
2
  import PropTypes from 'prop-types';
3
3
  import { ConditionalLink, UniversalLink } from '@plone/volto/components';
4
4
  import { flattenToAppURL } from '@plone/volto/helpers';
5
-
6
5
  import { isInternalURL } from '@plone/volto/helpers/Url/Url';
7
6
 
8
- const DefaultTemplate = ({ items, linkTitle, linkHref, isEditMode }) => {
7
+ const DefaultTemplate = ({
8
+ headlineTag,
9
+ items,
10
+ linkTitle,
11
+ linkHref,
12
+ isEditMode,
13
+ }) => {
9
14
  let link = null;
10
15
  let href = linkHref?.[0]?.['@id'] || '';
11
16
 
@@ -19,6 +24,16 @@ const DefaultTemplate = ({ items, linkTitle, linkHref, isEditMode }) => {
19
24
  link = <UniversalLink href={href}>{linkTitle || href}</UniversalLink>;
20
25
  }
21
26
 
27
+ const getTitleTag = (tag) => {
28
+ const level = tag.slice(-1);
29
+ if (/\d/.test(level)) {
30
+ return `h${Number(level) + 1}`;
31
+ } else {
32
+ return 'h3';
33
+ }
34
+ };
35
+ const TitleTag = headlineTag ? getTitleTag(headlineTag) : 'h3';
36
+
22
37
  return (
23
38
  <>
24
39
  <div className="items">
@@ -26,7 +41,7 @@ const DefaultTemplate = ({ items, linkTitle, linkHref, isEditMode }) => {
26
41
  <div className="listing-item" key={item['@id']}>
27
42
  <ConditionalLink item={item} condition={!isEditMode}>
28
43
  <div className="listing-body">
29
- <h4>{item.title ? item.title : item.id}</h4>
44
+ <TitleTag>{item.title ? item.title : item.id}</TitleTag>
30
45
  <p>{item.description}</p>
31
46
  </div>
32
47
  </ConditionalLink>
@@ -1,13 +1,13 @@
1
1
  import { getQueryStringResults } from '@plone/volto/actions';
2
2
  import { resolveBlockExtensions } from '@plone/volto/helpers';
3
3
 
4
- const getListingBlockAsyncData = ({
4
+ export default function getListingBlockAsyncData({
5
5
  dispatch,
6
6
  id,
7
7
  data,
8
8
  path,
9
9
  blocksConfig,
10
- }) => {
10
+ }) {
11
11
  const { resolvedExtensions } = resolveBlockExtensions(data, blocksConfig);
12
12
 
13
13
  return [
@@ -24,6 +24,4 @@ const getListingBlockAsyncData = ({
24
24
  ),
25
25
  ),
26
26
  ];
27
- };
28
-
29
- export default getListingBlockAsyncData;
27
+ }
@@ -1,13 +1,13 @@
1
- export SearchDetails from './SearchDetails';
2
- export Facets from './Facets';
3
- export SelectFacet from './SelectFacet';
4
- export CheckboxFacet from './CheckboxFacet';
5
- export DateRangeFacet from './DateRangeFacet';
6
- export SearchInput from './SearchInput';
7
- export FilterList from './FilterList';
8
- export SortOn from './SortOn';
9
- export ToggleFacet from './ToggleFacet';
10
- export SelectFacetFilterListEntry from './SelectFacetFilterListEntry';
11
- export ToggleFacetFilterListEntry from './ToggleFacetFilterListEntry';
12
- export DateRangeFacetFilterListEntry from './DateRangeFacetFilterListEntry';
13
- export ViewSwitcher from './ViewSwitcher';
1
+ export { default as SearchDetails } from './SearchDetails';
2
+ export { default as Facets } from './Facets';
3
+ export { default as SelectFacet } from './SelectFacet';
4
+ export { default as CheckboxFacet } from './CheckboxFacet';
5
+ export { default as DateRangeFacet } from './DateRangeFacet';
6
+ export { default as SearchInput } from './SearchInput';
7
+ export { default as FilterList } from './FilterList';
8
+ export { default as SortOn } from './SortOn';
9
+ export { default as ToggleFacet } from './ToggleFacet';
10
+ export { default as SelectFacetFilterListEntry } from './SelectFacetFilterListEntry';
11
+ export { default as ToggleFacetFilterListEntry } from './ToggleFacetFilterListEntry';
12
+ export { default as DateRangeFacetFilterListEntry } from './DateRangeFacetFilterListEntry';
13
+ export { default as ViewSwitcher } from './ViewSwitcher';
@@ -1,2 +1,2 @@
1
- export withQueryString from './withQueryString';
2
- export withSearch from './withSearch';
1
+ export { default as withQueryString } from './withQueryString';
2
+ export { default as withSearch } from './withSearch';
@@ -10,7 +10,7 @@ function getDisplayName(WrappedComponent) {
10
10
  * A HOC that injects querystring metadata information from the backend.
11
11
  *
12
12
  */
13
- export default (WrappedComponent) => {
13
+ export default function withQueryString(WrappedComponent) {
14
14
  function WithQueryString(props) {
15
15
  const dispatch = useDispatch();
16
16
 
@@ -29,4 +29,4 @@ export default (WrappedComponent) => {
29
29
  WrappedComponent,
30
30
  )})`;
31
31
  return WithQueryString;
32
- };
32
+ }
@@ -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,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
  );
@@ -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';
@@ -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 {
@@ -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;