Skip to content

Commit

Permalink
use blockform and renderblocks
Browse files Browse the repository at this point in the history
  • Loading branch information
dobri1408 committed Mar 26, 2024
1 parent 25b26d5 commit 61994d0
Show file tree
Hide file tree
Showing 3 changed files with 250 additions and 60 deletions.
131 changes: 73 additions & 58 deletions src/components/Blocks/Hero/Edit.jsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,18 @@
import React from 'react';
import React, { useState } from 'react';
import cx from 'classnames';
import isFunction from 'lodash/isFunction';
import { Icon } from 'semantic-ui-react';
import config from '@plone/volto/registry';
import { BlocksForm } from '@plone/volto/components';
import EditBlockWrapper from './EditBlockWrapper';
import { v4 as uuid } from 'uuid';

import {
emptyBlocksForm,
withBlockExtensions,
getBlocksLayoutFieldname,
} from '@plone/volto/helpers';
import { isEmpty, without } from 'lodash';
import {
BlockDataForm,
SidebarPortal,
Expand Down Expand Up @@ -39,23 +49,20 @@ const Metadata = ({ buttonLabel, inverted, styles, ...props }) => {
};

export default function Edit(props) {
const { slate } = config.settings;
const [selectedBlock, setSelectedBlock] = useState(null);
const {
data = {},
block = null,
selected = false,
index,
selected,

properties,
onChangeBlock,
onSelectBlock,

onChangeField,
pathname,
metadata = null,
} = props;
const {
text,
copyright,
copyrightIcon,
copyrightPosition,
isMultiline,
} = data;
const { copyright, copyrightIcon, copyrightPosition } = data;
const copyrightPrefix = config.blocks.blocksConfig.hero.copyrightPrefix || '';
const schema = React.useMemo(() => {
if (isFunction(HeroBlockSchema)) {
Expand All @@ -64,64 +71,72 @@ export default function Edit(props) {
return HeroBlockSchema;
}, [props]);

const withBlockProperties = React.useCallback(
(editor) => {
editor.getBlockProps = () => props;
return editor;
},
[props],
);

const handleFocus = React.useCallback(() => {
if (!selected) {
onSelectBlock(block);
}
}, [onSelectBlock, selected, block]);

const extensions = React.useMemo(() => {
if (isMultiline) {
return slate.textblockExtensions.filter(
(f) => f.name !== 'withSplitBlocksOnBreak',
);
} else {
return slate.textblockExtensions;
}
}, [slate.textblockExtensions, isMultiline]);

const value = createSlateHeader(text);
const blockState = {};
const data_blocks = data?.data?.blocks;
const id = uuid();
const childBlocksForm = isEmpty(data_blocks)
? data.text
? {
blocks: {
[id]: {
'@type': 'slate',
value: data.text,
},
},
blocks_layout: { items: [id] },
}
: emptyBlocksForm()
: data.data;

return (
<>
<BodyClass className="with-hero-block" />

<Hero {...data}>
<Hero.Text {...data}>
<SlateEditor
key={isMultiline}
detached={!isMultiline}
index={index}
properties={properties}
extensions={extensions}
renderExtensions={[withBlockProperties]}
value={value}
onChange={(text) => {
<BlocksForm
metadata={properties || metadata}
properties={childBlocksForm}
manage={false}
allowedBlocks={'slate'}
selectedBlock={selected ? selectedBlock : null}
title={data.placeholder}
onSelectBlock={(id) => {
setSelectedBlock(id);
}}
onChangeFormData={(newFormData) => {
onChangeBlock(block, {
...data,
text,
data: newFormData,
});
}}
block={block}
onFocus={handleFocus}
onKeyDown={(e) => {
if (!isMultiline && e.event.code === 'Enter') {
e.event.preventDefault();
return;
onChangeField={(id, value) => {
if (['blocks', 'blocks_layout'].indexOf(id) > -1) {
blockState[id] = value;
if (data.text) delete data.text;
onChangeBlock(block, {
...data,
data: {
...data.data,
...blockState,
},
});
} else {
onChangeField(id, value);
}
if (isMultiline) handleKeyDetached(e);
}}
selected={selected}
placeholder="Add text..."
slateSettings={slate}
/>
pathname={pathname}
>
{({ draginfo }, editBlock, blockProps) => (
<EditBlockWrapper
draginfo={draginfo}
blockProps={blockProps}
disabled={data.disableInnerButtons}
>
{editBlock}
</EditBlockWrapper>
)}
</BlocksForm>
</Hero.Text>
<Hero.Meta {...data}>
<Metadata {...data} />
Expand Down
161 changes: 161 additions & 0 deletions src/components/Blocks/Hero/EditBlockWrapper.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
import React from 'react';
import { Icon, BlockChooser } from '@plone/volto/components';
import { blockHasValue } from '@plone/volto/helpers';
import config from '@plone/volto/registry';
import { Button } from 'semantic-ui-react';
import includes from 'lodash/includes';
import isBoolean from 'lodash/isBoolean';
import { defineMessages, injectIntl } from 'react-intl';
import { doesNodeContainClick } from 'semantic-ui-react/dist/commonjs/lib';
import cx from 'classnames';

import dragSVG from '@plone/volto/icons/drag.svg';
import addSVG from '@plone/volto/icons/circle-plus.svg';
import trashSVG from '@plone/volto/icons/delete.svg';

const messages = defineMessages({
unknownBlock: {
id: 'Unknown Block',
defaultMessage: 'Unknown Block {block}',
},
delete: {
id: 'delete',
defaultMessage: 'delete',
},
});

class EditBlockWrapper extends React.Component {
constructor(props) {
super(props);
this.state = {
addNewBlockOpened: false,
};
}

componentDidMount() {
document.addEventListener('mousedown', this.handleClickOutside, false);
}

componentWillUnmount() {
document.removeEventListener('mousedown', this.handleClickOutside);
}

handleClickOutside = (e) => {
if (
this.blockNode.current &&
doesNodeContainClick(this.blockNode.current, e)
) {
return;
}

if (this.state.addNewBlockOpened) {
this.setState({
addNewBlockOpened: false,
});
return true;
}
};

blockNode = React.createRef();

render() {
const { intl, blockProps, draginfo, extraControls, children } = this.props;

const {
allowedBlocks,
block,
data,
onDeleteBlock,
onMutateBlock,
selected,
} = blockProps;
const type = data['@type'];
const { disableNewBlocks } = data;
const visible = !data.fixed;

const required = isBoolean(data.required)
? data.required
: includes(config.blocks.requiredBlocks, type);

return (
<div ref={this.blockNode} className="block-wrapper">
<div
ref={draginfo?.innerRef}
{...(selected ? draginfo?.draggableProps : null)}
className={`block-editor-${data['@type']}`}
>
{!selected && (
<div
style={{
display: 'none',
// keep react-beautiful-dnd happy
}}
{...draginfo.dragHandleProps}
></div>
)}
{selected && (
<div className="block-toolbar">
<div
style={{
display: visible ? 'inline-block' : 'none',
}}
{...draginfo.dragHandleProps}
className="drag handle wrapper-column-block"
>
<Button icon basic title="Drag and drop">
<Icon name={dragSVG} size="19px" />
</Button>
</div>

{extraControls}

{!disableNewBlocks && !blockHasValue(data) && (
<Button
icon
basic
title="Add block"
onClick={() => {
this.setState({
addNewBlockOpened: !this.state.addNewBlockOpened,
});
}}
className="column-block-add-button"
>
<Icon name={addSVG} className="" size="19px" />
</Button>
)}
{!required && (
<Button
icon
basic
title="Remove block"
onClick={() => onDeleteBlock(block)}
className="delete-button-column-block"
aria-label={intl.formatMessage(messages.delete)}
>
<Icon name={trashSVG} size="19px" />
</Button>
)}
{this.state.addNewBlockOpened && (
<BlockChooser
onMutateBlock={(id, value) => {
this.setState({ addNewBlockOpened: false });
onMutateBlock(id, value);
}}
currentBlock={block}
allowedBlocks={allowedBlocks}
/>
)}
</div>
)}

<div className={cx('ui drag block wrapper inner', type)}>
{children}
</div>
</div>
</div>
);
}
}

export default injectIntl(EditBlockWrapper);
18 changes: 16 additions & 2 deletions src/components/Blocks/Hero/View.jsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import React from 'react';
import cx from 'classnames';
import { Icon } from 'semantic-ui-react';
import { UniversalLink } from '@plone/volto/components';
import { UniversalLink, RenderBlocks } from '@plone/volto/components';
import { BodyClass } from '@plone/volto/helpers';
import { useLocation } from 'react-router-dom';
import Hero from './Hero';
import Copyright from './Copyright';
import { serializeText, getFieldURL } from '@eeacms/volto-hero-block/helpers';
Expand All @@ -25,14 +26,27 @@ const Metadata = ({ buttonLabel, inverted, styles, ...props }) => {
};

const View = (props) => {
const location = useLocation();
const { data = {} } = props;
const { text, copyright, copyrightIcon, copyrightPosition } = data;

const metadata = props.metadata || props.properties;
const copyrightPrefix = config.blocks.blocksConfig.hero.copyrightPrefix || '';
return (
<React.Fragment>
<BodyClass className="with-hero-block" />
<Hero {...data}>
<Hero.Text {...data}>{serializeText(text)}</Hero.Text>
<Hero.Text {...data}>
{data?.data ? (
<RenderBlocks
location={location}
metadata={metadata}
content={data?.data || {}}
/>
) : (
serializeText(text)
)}
</Hero.Text>
<Hero.Meta {...data}>
<Metadata {...data} />
</Hero.Meta>
Expand Down

0 comments on commit 61994d0

Please sign in to comment.