@eeacms/volto-accordion-block
Advanced tools
Comparing version 8.1.0 to 9.0.0
@@ -7,2 +7,24 @@ ### Changelog | ||
### [9.0.0](https://github.com/eea/volto-accordion-block/compare/8.1.0...9.0.0) - 28 June 2023 | ||
#### :rocket: New Features | ||
- feat: Add headline field to the block field. [Víctor Fernández de Alba - [`5e0ef4e`](https://github.com/eea/volto-accordion-block/commit/5e0ef4e45c7168314c7b287ece1152fa878a6f82)] | ||
- feat: Add support for custom `blocksConfig`. Fix add new block to accordion button. [Víctor Fernández de Alba - [`bdf3e97`](https://github.com/eea/volto-accordion-block/commit/bdf3e97fac92c130f43c03e610e530f41dd5bc17)] | ||
#### :bug: Bug Fixes | ||
- fix: Fix i18n make command and eslint - refs #254894 [Alin Voinea - [`38bc517`](https://github.com/eea/volto-accordion-block/commit/38bc517ae34914656345c397467891802ffeba7c)] | ||
#### :house: Internal changes | ||
- chore: Cleanup unused .i18n.babel.config.js [Alin Voinea - [`fc615e9`](https://github.com/eea/volto-accordion-block/commit/fc615e9802ae57e481159b738520f6d783953a0c)] | ||
- chore: Cleanup console warnings about styled and fluid [Alin Voinea - [`527165f`](https://github.com/eea/volto-accordion-block/commit/527165fa59e2e04041524f6c8631b619171f6ade)] | ||
#### :hammer_and_wrench: Others | ||
- Release 9.0.0 [Alin Voinea - [`1a3a11c`](https://github.com/eea/volto-accordion-block/commit/1a3a11c98b6aa8ad875f49a0da588ce2f0da2d25)] | ||
- i18n: Add Romanian [Alin Voinea - [`ecb7414`](https://github.com/eea/volto-accordion-block/commit/ecb74144f67b71a265e84628adb46aabc49c9416)] | ||
- test: Add cypress for accordion in DX Layout - refs #254894 [Alin Voinea - [`3c9b757`](https://github.com/eea/volto-accordion-block/commit/3c9b757f72a9f4ccc3f46458d8488e250acac437)] | ||
- test: add unit tests View and AccordionEdit - refs #253277 [ana-oprea - [`4b780ec`](https://github.com/eea/volto-accordion-block/commit/4b780ec32e6aedce6a61cb25876f7c96a6f471a7)] | ||
### [8.1.0](https://github.com/eea/volto-accordion-block/compare/8.0.0...8.1.0) - 12 June 2023 | ||
@@ -9,0 +31,0 @@ |
105
DEVELOP.md
@@ -5,2 +5,26 @@ # volto-accordion-block | ||
### With Docker | ||
1. Make sure you have `docker` and `docker compose` installed and running on your machine: | ||
```Bash | ||
git clone https://github.com/eea/volto-accordion-block.git | ||
cd volto-accordion-block | ||
git checkout -b bugfix-123456 develop | ||
make | ||
make start | ||
``` | ||
1. Wait for `Volto started at 0.0.0.0:3000` meesage | ||
1. Go to http://localhost:3000 | ||
1. Happy hacking! | ||
```Bash | ||
cd src/addons/volto-accordion-block/ | ||
``` | ||
### Or add volto-accordion-block to your Volto project | ||
Before starting make sure your development environment is properly set. See [Volto Developer Documentation](https://docs.voltocms.com/getting-started/install/) | ||
@@ -10,34 +34,41 @@ | ||
npm install -g yo @plone/generator-volto mrs-developer | ||
```Bash | ||
npm install -g yo @plone/generator-volto mrs-developer | ||
``` | ||
1. Create new volto app | ||
yo @plone/volto my-volto-project --addon @eeacms/volto-accordion-block --skip-install | ||
cd my-volto-project | ||
```Bash | ||
yo @plone/volto my-volto-project --addon @eeacms/volto-accordion-block --skip-install | ||
cd my-volto-project | ||
``` | ||
1. Add the following to `mrs.developer.json`: | ||
{ | ||
"volto-accordion-block": { | ||
"url": "https://github.com/eea/volto-accordion-block.git", | ||
"package": "@eeacms/volto-accordion-block", | ||
"branch": "develop", | ||
"path": "src" | ||
} | ||
```JSON | ||
{ | ||
"volto-accordion-block": { | ||
"url": "https://github.com/eea/volto-accordion-block.git", | ||
"package": "@eeacms/volto-accordion-block", | ||
"branch": "develop", | ||
"path": "src" | ||
} | ||
} | ||
``` | ||
1. Install | ||
yarn develop | ||
yarn | ||
```Bash | ||
make develop | ||
yarn | ||
``` | ||
1. Start backend | ||
docker pull plone | ||
docker run -d --name plone -p 8080:8080 -e SITE=Plone -e PROFILES="profile-plone.restapi:blocks" plone | ||
```Bash | ||
docker compose up backend | ||
``` | ||
...wait for backend to setup and start - `Ready to handle requests`: | ||
docker logs -f plone | ||
...you can also check http://localhost:8080/Plone | ||
@@ -47,3 +78,5 @@ | ||
yarn start | ||
```BASH | ||
yarn start | ||
``` | ||
@@ -54,2 +87,38 @@ 1. Go to http://localhost:3000 | ||
cd src/addons/volto-accordion-block/ | ||
```BASH | ||
cd src/addons/volto-accordion-block/ | ||
``` | ||
## Cypress | ||
To run cypress locally, first make sure you don't have any Volto/Plone running on ports `8080` and `3000`. | ||
You don't have to be in a `clean-volto-project`, you can be in any Volto Frontend | ||
project where you added `volto-accordion-block` to `mrs.developer.json` | ||
Go to: | ||
```BASH | ||
cd src/addons/volto-accordion-block/ | ||
``` | ||
Start: | ||
```Bash | ||
make | ||
make start | ||
``` | ||
This will build and start with Docker a clean `Plone backend` and `Volto Frontend` with `volto-accordion-block` block installed. | ||
Open Cypress Interface: | ||
```Bash | ||
make cypress-open | ||
``` | ||
Or run it: | ||
```Bash | ||
make cypress-run | ||
``` |
{ | ||
"name": "@eeacms/volto-accordion-block", | ||
"version": "8.1.0", | ||
"version": "9.0.0", | ||
"description": "volto-accordion-block: Volto accordion block", | ||
@@ -5,0 +5,0 @@ "main": "src/index.js", |
@@ -23,8 +23,2 @@ # volto-accordion-block | ||
## Upgrade | ||
### Upgrading to 6.x | ||
This version requires: `@plone/volto >= 16.0.0.alpha.46` (schemaEnhancer / addStyling). | ||
## Getting started | ||
@@ -34,23 +28,9 @@ | ||
1. Get the latest Docker images | ||
git clone https://github.com/eea/volto-accordion-block.git | ||
cd volto-accordion-block | ||
make | ||
make start | ||
``` | ||
docker pull plone | ||
docker pull plone/volto | ||
``` | ||
Go to http://localhost:3000 | ||
1. Start Plone backend | ||
``` | ||
docker run -d --name plone -p 8080:8080 -e SITE=Plone -e PROFILES="profile-plone.restapi:blocks" plone | ||
``` | ||
1. Start Volto frontend | ||
``` | ||
docker run -it --rm -p 3000:3000 --link plone -e ADDONS="@eeacms/volto-accordion-block" plone/volto | ||
``` | ||
1. Go to http://localhost:3000 | ||
### Add volto-accordion-block to your Volto project | ||
@@ -60,2 +40,6 @@ | ||
```Bash | ||
docker compose up backend | ||
``` | ||
1. Start Volto frontend | ||
@@ -71,3 +55,3 @@ | ||
"dependencies": { | ||
"@eeacms/volto-accordion-block": "^3.0.0" | ||
"@eeacms/volto-accordion-block": "*" | ||
} | ||
@@ -74,0 +58,0 @@ ``` |
@@ -1,5 +0,5 @@ | ||
export AccordionLayoutSchema from '@eeacms/volto-accordion-block/components/manage/Blocks/Accordion/LayoutSchema'; | ||
export { default as AccordionLayoutSchema } from '@eeacms/volto-accordion-block/components/manage/Blocks/Accordion/LayoutSchema'; | ||
export { AccordionStylingSchema } from '@eeacms/volto-accordion-block/components/manage/Blocks/Accordion/Schema'; | ||
export AccordionBlockEdit from '@eeacms/volto-accordion-block/components/manage/Blocks/Accordion/Edit'; | ||
export AccordionBlockView from '@eeacms/volto-accordion-block/components/manage/Blocks/Accordion/View'; | ||
export PanelsWidget from '@eeacms/volto-accordion-block/components/manage/Widgets/PanelsWidget'; | ||
export { default as AccordionBlockEdit } from '@eeacms/volto-accordion-block/components/manage/Blocks/Accordion/Edit'; | ||
export { default as AccordionBlockView } from '@eeacms/volto-accordion-block/components/manage/Blocks/Accordion/View'; | ||
export { default as PanelsWidget } from '@eeacms/volto-accordion-block/components/manage/Widgets/PanelsWidget'; |
@@ -5,4 +5,4 @@ import { render, fireEvent } from '@testing-library/react'; | ||
import renderer from 'react-test-renderer'; | ||
import config from '@plone/volto/registry'; | ||
import '@testing-library/jest-dom/extend-expect'; | ||
import config from '@plone/volto/registry'; | ||
@@ -122,2 +122,46 @@ config.blocks.blocksConfig.accordion = { | ||
}); | ||
it('should open accordion content when title is clicked', () => { | ||
config.blocks.blocksConfig.accordion = { | ||
...config.blocks.blocksConfig.accordion, | ||
semanticIcon: undefined, | ||
}; | ||
const { container, getByText } = render( | ||
<AccordionEdit | ||
handleTitleChange={handleTitleChange} | ||
handleTitleClick={handleTitleClick} | ||
uid={uid} | ||
panel={panel} | ||
data={data} | ||
index={index} | ||
> | ||
<p>Accordion Content</p> | ||
</AccordionEdit>, | ||
); | ||
const accordionTitle = container.querySelector('.accordion-title'); | ||
fireEvent.click(accordionTitle); | ||
const contentElement = getByText('Accordion Content'); | ||
expect(contentElement).toBeInTheDocument(); | ||
}); | ||
it('should open accordion content when title is clicked', () => { | ||
const { container, getByText } = render( | ||
<AccordionEdit | ||
handleTitleChange={handleTitleChange} | ||
handleTitleClick={handleTitleClick} | ||
uid={uid} | ||
panel={panel} | ||
data={{ ...data, non_exclusive: false }} | ||
index={index} | ||
> | ||
<p>Accordion Content</p> | ||
</AccordionEdit>, | ||
); | ||
const accordionTitle = container.querySelector('.accordion-title'); | ||
fireEvent.click(accordionTitle); | ||
const contentElement = getByText('Accordion Content'); | ||
expect(contentElement).toBeInTheDocument(); | ||
}); | ||
}); |
@@ -6,2 +6,3 @@ import { | ||
BlocksToolbar, | ||
BlockDataForm, | ||
} from '@plone/volto/components'; | ||
@@ -11,9 +12,8 @@ import { | ||
getBlocksLayoutFieldname, | ||
withBlockExtensions, | ||
} from '@plone/volto/helpers'; | ||
import helpSVG from '@plone/volto/icons/help.svg'; | ||
import { isEmpty, without } from 'lodash'; | ||
import { isEmpty, without, cloneDeep, pickBy } from 'lodash'; | ||
import React, { useState } from 'react'; | ||
import { Button, Segment } from 'semantic-ui-react'; | ||
import { withBlockExtensions } from '@plone/volto/helpers'; | ||
import { BlockDataForm } from '@plone/volto/components'; | ||
import { useIntl } from 'react-intl'; | ||
@@ -25,3 +25,2 @@ import AccordionEdit from './AccordionEdit'; | ||
import { emptyAccordion, getPanels } from './util'; | ||
import { cloneDeep } from 'lodash'; | ||
import config from '@plone/volto/registry'; | ||
@@ -42,2 +41,3 @@ | ||
} = props; | ||
const intl = useIntl(); | ||
@@ -95,11 +95,5 @@ const properties = isEmpty(data?.data?.blocks) | ||
const searchElementInMultiSelection = (uid, blockprops) => { | ||
if ( | ||
multiSelected.find((el) => { | ||
if (el === blockprops.block) return true; | ||
return false; | ||
}) | ||
) | ||
return true; | ||
return false; | ||
return !!multiSelected.find((el) => el === blockprops.block); | ||
}; | ||
const applySchemaEnhancer = (originalSchema) => { | ||
@@ -230,9 +224,5 @@ let schema, schemaEnhancer; | ||
if ( | ||
data?.data?.blocks[currentUid].blocks_layout.items.find( | ||
(x) => x === key, | ||
) | ||
) | ||
return false; | ||
return true; | ||
return !data?.data?.blocks[currentUid].blocks_layout.items.find( | ||
(x) => x === key, | ||
); | ||
}); | ||
@@ -269,53 +259,51 @@ | ||
const blockConfig = config.blocks.blocksConfig.accordion; | ||
const blocksConfig = blockConfig.blocksConfig || props.blocksConfig; | ||
// The accordion is able to get the allowedBlocks info from the custom DX layout | ||
// Fallback to the blockConfig one | ||
const allowedBlocks = data.allowedBlocks || blockConfig.allowedBlocks; | ||
const allowedBlocksConfig = allowedBlocks | ||
? pickBy(blocksConfig, (value, key) => allowedBlocks.includes(key)) | ||
: blocksConfig; | ||
return ( | ||
<fieldset className="accordion-block"> | ||
<legend | ||
onClick={() => { | ||
setSelectedBlock({}); | ||
props.setSidebarTab(1); | ||
}} | ||
aria-hidden="true" | ||
> | ||
{data.title || 'Accordion'} | ||
</legend> | ||
{panels.map(([uid, panel], index) => ( | ||
<AccordionEdit | ||
uid={uid} | ||
panel={panel} | ||
panelData={panelData} | ||
handleTitleChange={handleTitleChange} | ||
handleTitleClick={() => setSelectedBlock({})} | ||
data={data} | ||
index={index} | ||
<> | ||
{data.headline && <h2 className="headline">{data.headline}</h2>} | ||
<fieldset className="accordion-block"> | ||
<legend | ||
onClick={() => { | ||
setSelectedBlock({}); | ||
props.setSidebarTab(1); | ||
}} | ||
aria-hidden="true" | ||
> | ||
<BlocksForm | ||
key={uid} | ||
title={data.placeholder} | ||
description={instructions} | ||
manage={manage} | ||
allowedBlocks={data.allowedBlocks} | ||
metadata={metadata} | ||
properties={isEmpty(panel) ? emptyBlocksForm() : panel} | ||
selectedBlock={selected ? selectedBlock[uid] : null} | ||
onSelectBlock={(id, l, e) => { | ||
const isMultipleSelection = e | ||
? e.shiftKey || e.ctrlKey || e.metaKey | ||
: false; | ||
onSelectBlock(uid, id, isMultipleSelection, e, selectedBlock); | ||
}} | ||
onChangeFormData={(newFormData) => { | ||
onChangeBlock(block, { | ||
...data, | ||
data: { | ||
...panelData, | ||
blocks: { | ||
...panelData.blocks, | ||
[uid]: newFormData, | ||
}, | ||
}, | ||
}); | ||
}} | ||
onChangeField={(id, value) => { | ||
if (['blocks', 'blocks_layout'].indexOf(id) > -1) { | ||
blockState[id] = value; | ||
{data.title || 'Accordion'} | ||
</legend> | ||
{panels.map(([uid, panel], index) => ( | ||
<AccordionEdit | ||
uid={uid} | ||
panel={panel} | ||
panelData={panelData} | ||
handleTitleChange={handleTitleChange} | ||
handleTitleClick={() => setSelectedBlock({})} | ||
data={data} | ||
index={index} | ||
> | ||
<BlocksForm | ||
key={uid} | ||
title={data.placeholder} | ||
description={instructions} | ||
manage={manage} | ||
blocksConfig={allowedBlocksConfig} | ||
metadata={metadata} | ||
properties={isEmpty(panel) ? emptyBlocksForm() : panel} | ||
selectedBlock={selected ? selectedBlock[uid] : null} | ||
onSelectBlock={(id, l, e) => { | ||
const isMultipleSelection = e | ||
? e.shiftKey || e.ctrlKey || e.metaKey | ||
: false; | ||
onSelectBlock(uid, id, isMultipleSelection, e, selectedBlock); | ||
}} | ||
onChangeFormData={(newFormData) => { | ||
onChangeBlock(block, { | ||
@@ -327,95 +315,117 @@ ...data, | ||
...panelData.blocks, | ||
[uid]: { | ||
...panelData.blocks?.[uid], | ||
...blockState, | ||
}, | ||
[uid]: newFormData, | ||
}, | ||
}, | ||
}); | ||
} else { | ||
onChangeField(id, value); | ||
} | ||
}} | ||
onChangeField={(id, value) => { | ||
if (['blocks', 'blocks_layout'].indexOf(id) > -1) { | ||
blockState[id] = value; | ||
onChangeBlock(block, { | ||
...data, | ||
data: { | ||
...panelData, | ||
blocks: { | ||
...panelData.blocks, | ||
[uid]: { | ||
...panelData.blocks?.[uid], | ||
...blockState, | ||
}, | ||
}, | ||
}, | ||
}); | ||
} else { | ||
onChangeField(id, value); | ||
} | ||
}} | ||
pathname={pathname} | ||
> | ||
{({ draginfo }, editBlock, blockProps) => { | ||
return ( | ||
<EditBlockWrapper | ||
draginfo={draginfo} | ||
blockProps={blockProps} | ||
disabled={data.disableInnerButtons} | ||
multiSelected={searchElementInMultiSelection( | ||
uid, | ||
blockProps, | ||
)} | ||
extraControls={ | ||
<> | ||
{instructions && ( | ||
<> | ||
<Button | ||
icon | ||
basic | ||
title="Section help" | ||
onClick={() => { | ||
setSelectedBlock({}); | ||
const tab = manage ? 0 : 1; | ||
props.setSidebarTab(tab); | ||
}} | ||
> | ||
<Icon name={helpSVG} className="" size="19px" /> | ||
</Button> | ||
</> | ||
)} | ||
</> | ||
} | ||
> | ||
{editBlock} | ||
</EditBlockWrapper> | ||
); | ||
}} | ||
</BlocksForm> | ||
</AccordionEdit> | ||
))} | ||
{selected ? ( | ||
<BlocksToolbar | ||
selectedBlock={Object.keys(selectedBlock)[0]} | ||
formData={data?.data?.blocks?.[currentUid]} | ||
selectedBlocks={multiSelected} | ||
onSetSelectedBlocks={(blockIds) => { | ||
setMultiSelected(blockIds); | ||
}} | ||
pathname={pathname} | ||
> | ||
{({ draginfo }, editBlock, blockProps) => { | ||
return ( | ||
<EditBlockWrapper | ||
draginfo={draginfo} | ||
blockProps={blockProps} | ||
disabled={data.disableInnerButtons} | ||
multiSelected={searchElementInMultiSelection(uid, blockProps)} | ||
extraControls={ | ||
<> | ||
{instructions && ( | ||
<> | ||
<Button | ||
icon | ||
basic | ||
title="Section help" | ||
onClick={() => { | ||
setSelectedBlock({}); | ||
const tab = manage ? 0 : 1; | ||
props.setSidebarTab(tab); | ||
}} | ||
> | ||
<Icon name={helpSVG} className="" size="19px" /> | ||
</Button> | ||
</> | ||
)} | ||
</> | ||
} | ||
> | ||
{editBlock} | ||
</EditBlockWrapper> | ||
); | ||
}} | ||
</BlocksForm> | ||
</AccordionEdit> | ||
))} | ||
{selected ? ( | ||
<BlocksToolbar | ||
selectedBlock={Object.keys(selectedBlock)[0]} | ||
formData={data?.data?.blocks[currentUid]} | ||
selectedBlocks={multiSelected} | ||
onSetSelectedBlocks={(blockIds) => { | ||
setMultiSelected(blockIds); | ||
}} | ||
onSelectBlock={(id, l, e) => { | ||
const isMultipleSelection = e | ||
? e.shiftKey || e.ctrlKey || e.metaKey | ||
: false; | ||
onSelectBlock={(id, l, e) => { | ||
const isMultipleSelection = e | ||
? e.shiftKey || e.ctrlKey || e.metaKey | ||
: false; | ||
onSelectBlock(id, isMultipleSelection, e, selectedBlock); | ||
}} | ||
onChangeBlocks={(newBlockData) => { | ||
changeBlockData(newBlockData); | ||
}} | ||
/> | ||
) : ( | ||
'' | ||
)} | ||
<SidebarPortal selected={selected && !Object.keys(selectedBlock).length}> | ||
{instructions && ( | ||
<Segment attached> | ||
<div dangerouslySetInnerHTML={{ __html: instructions }} /> | ||
</Segment> | ||
)} | ||
{!data?.readOnlySettings && ( | ||
<BlockDataForm | ||
schema={AccordionBlockSchema({ intl })} | ||
title="Accordion block" | ||
onChangeField={(id, value) => { | ||
onChangeBlock(block, { | ||
...data, | ||
[id]: value, | ||
}); | ||
onSelectBlock(id, isMultipleSelection, e, selectedBlock); | ||
}} | ||
formData={data} | ||
block={block} | ||
onChangeBlocks={(newBlockData) => { | ||
changeBlockData(newBlockData); | ||
}} | ||
/> | ||
) : ( | ||
'' | ||
)} | ||
</SidebarPortal> | ||
</fieldset> | ||
<SidebarPortal | ||
selected={selected && !Object.keys(selectedBlock).length} | ||
> | ||
{instructions && ( | ||
<Segment attached> | ||
<div dangerouslySetInnerHTML={{ __html: instructions }} /> | ||
</Segment> | ||
)} | ||
{!data?.readOnlySettings && ( | ||
<BlockDataForm | ||
schema={AccordionBlockSchema({ intl })} | ||
title="Accordion block" | ||
onChangeField={(id, value) => { | ||
onChangeBlock(block, { | ||
...data, | ||
[id]: value, | ||
}); | ||
}} | ||
formData={data} | ||
block={block} | ||
blocksConfig={blocksConfig} | ||
onChangeBlock={onChangeBlock} | ||
/> | ||
)} | ||
</SidebarPortal> | ||
</fieldset> | ||
</> | ||
); | ||
@@ -422,0 +432,0 @@ }; |
import React from 'react'; | ||
import { Icon, BlockChooser } from '@plone/volto/components'; | ||
import { Icon } from '@plone/volto/components'; | ||
import { blockHasValue } from '@plone/volto/helpers'; | ||
@@ -9,7 +9,6 @@ import config from '@plone/volto/registry'; | ||
import { defineMessages, injectIntl } from 'react-intl'; | ||
import { doesNodeContainClick } from 'semantic-ui-react/dist/commonjs/lib'; | ||
import cx from 'classnames'; | ||
import NewBlockAddButton from './NewBlockAddButton'; | ||
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'; | ||
@@ -29,34 +28,2 @@ | ||
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() { | ||
@@ -73,3 +40,2 @@ const { | ||
const { | ||
allowedBlocks, | ||
block, | ||
@@ -79,5 +45,6 @@ data, | ||
onInsertBlock, | ||
onMutateBlock, | ||
onSelectBlock, | ||
selected, | ||
index, | ||
blocksConfig, | ||
} = blockProps; | ||
@@ -93,7 +60,4 @@ const type = data['@type']; | ||
const allowedBlocksFromConfig = | ||
blockProps.blocksConfig.accordion?.allowedBlocks; | ||
return ( | ||
<div ref={this.blockNode}> | ||
<div> | ||
<div | ||
@@ -132,16 +96,12 @@ ref={draginfo?.innerRef} | ||
{!disableNewBlocks && !blockHasValue(data) && ( | ||
<Button | ||
icon | ||
basic | ||
title="Add block" | ||
onClick={() => { | ||
this.setState({ | ||
addNewBlockOpened: !this.state.addNewBlockOpened, | ||
}); | ||
<NewBlockAddButton | ||
block={block} | ||
index={index} | ||
blocksConfig={blocksConfig} | ||
onInsertBlock={(id, value) => { | ||
onSelectBlock(onInsertBlock(id, value)); | ||
}} | ||
className="accordion-block-add-button" | ||
> | ||
<Icon name={addSVG} className="" size="19px" /> | ||
</Button> | ||
/> | ||
)} | ||
{!required && ( | ||
@@ -159,16 +119,2 @@ <Button | ||
)} | ||
{this.state.addNewBlockOpened && ( | ||
<BlockChooser | ||
onMutateBlock={(id, value) => { | ||
onMutateBlock(id, value); | ||
this.setState({ addNewBlockOpened: false }); | ||
}} | ||
onInsertBlock={(id, value) => { | ||
onSelectBlock(onInsertBlock(id, value)); | ||
this.setState({ addNewBlockOpened: false }); | ||
}} | ||
currentBlock={block} | ||
allowedBlocks={allowedBlocks || allowedBlocksFromConfig} | ||
/> | ||
)} | ||
</> | ||
@@ -175,0 +121,0 @@ )} |
@@ -66,2 +66,6 @@ import config from '@plone/volto/registry'; | ||
}, | ||
headline: { | ||
id: 'Headline', | ||
defaultMessage: 'Headline', | ||
}, | ||
}); | ||
@@ -98,2 +102,3 @@ | ||
fields: [ | ||
'headline', | ||
'title', | ||
@@ -108,2 +113,5 @@ 'title_size', | ||
properties: { | ||
headline: { | ||
title: intl.formatMessage(messages.headline), | ||
}, | ||
title: { | ||
@@ -149,3 +157,3 @@ title: intl.formatMessage(messages.Title), | ||
}, | ||
required: ['title'], | ||
required: [], | ||
}); | ||
@@ -152,0 +160,0 @@ |
import { v4 as uuid } from 'uuid'; | ||
import { emptyBlocksForm } from '@plone/volto/helpers'; | ||
import { map } from 'lodash'; | ||
@@ -9,2 +8,3 @@ | ||
blockHasValue, | ||
emptyBlocksForm, | ||
} from '@plone/volto/helpers'; | ||
@@ -11,0 +11,0 @@ |
import React from 'react'; | ||
import { RenderBlocks } from '@plone/volto/components'; | ||
import { getPanels, accordionBlockHasValue } from './util'; | ||
@@ -9,3 +8,3 @@ import { Accordion, Icon } from 'semantic-ui-react'; | ||
import cx from 'classnames'; | ||
import { Icon as VoltoIcon } from '@plone/volto/components'; | ||
import { Icon as VoltoIcon, RenderBlocks } from '@plone/volto/components'; | ||
import AnimateHeight from 'react-animate-height'; | ||
@@ -52,2 +51,3 @@ import config from '@plone/volto/registry'; | ||
<div className="accordion-block"> | ||
{data.headline && <h2 className="headline">{data.headline}</h2>} | ||
{panels.map(([id, panel], index) => { | ||
@@ -54,0 +54,0 @@ return accordionBlockHasValue(panel) ? ( |
import React from 'react'; | ||
import View from './View'; | ||
import renderer from 'react-test-renderer'; | ||
import { render } from '@testing-library/react'; | ||
import { render, fireEvent } from '@testing-library/react'; | ||
import configureStore from 'redux-mock-store'; | ||
@@ -9,2 +9,3 @@ import { Provider } from 'react-intl-redux'; | ||
import config from '@plone/volto/registry'; | ||
import * as utils from './util'; | ||
import '@testing-library/jest-dom/extend-expect'; | ||
@@ -45,7 +46,4 @@ | ||
jest.mock('./util', () => ({ | ||
getPanels: () => [ | ||
['id1', { title: 'Panel 1' }], | ||
['id2', { title: 'Panel 2' }], | ||
], | ||
accordionBlockHasValue: () => true, | ||
getPanels: () => [['id1', { title: 'Panel 1' }]], | ||
accordionBlockHasValue: jest.fn(), | ||
})); | ||
@@ -74,2 +72,3 @@ | ||
it('renders without crashing', () => { | ||
utils.accordionBlockHasValue.mockReturnValue(true); | ||
const component = renderer.create( | ||
@@ -86,3 +85,17 @@ <Provider store={store}> | ||
it('renders null', () => { | ||
utils.accordionBlockHasValue.mockReturnValue(false); | ||
const component = renderer.create( | ||
<Provider store={store}> | ||
<MemoryRouter> | ||
<View data={mockData} /> | ||
</MemoryRouter> | ||
</Provider>, | ||
); | ||
const json = component.toJSON(); | ||
expect(json).toMatchSnapshot(); | ||
}); | ||
it('renders with panels', () => { | ||
utils.accordionBlockHasValue.mockReturnValue(true); | ||
const { rerender, getByText } = render( | ||
@@ -96,3 +109,2 @@ <Provider store={store}> | ||
expect(getByText('Panel 1')).toBeInTheDocument(); | ||
expect(getByText('Panel 2')).toBeInTheDocument(); | ||
@@ -107,2 +119,61 @@ rerender( | ||
}); | ||
it('should open accordion content when title is clicked', () => { | ||
utils.accordionBlockHasValue.mockReturnValue(true); | ||
config.blocks.blocksConfig.accordion = { | ||
...config.blocks.blocksConfig.accordion, | ||
semanticIcon: 'someIcon', | ||
}; | ||
const { container, getByText } = render( | ||
<Provider store={store}> | ||
<MemoryRouter> | ||
<View data={mockData} /> | ||
</MemoryRouter> | ||
</Provider>, | ||
); | ||
const accordionTitle = container.querySelector('.accordion-title'); | ||
fireEvent.click(accordionTitle); | ||
const contentElement = getByText('RenderBlocks'); | ||
expect(contentElement).toBeInTheDocument(); | ||
}); | ||
it('should open accordion content when title is clicked', () => { | ||
utils.accordionBlockHasValue.mockReturnValue(true); | ||
const { container, getByText } = render( | ||
<Provider store={store}> | ||
<MemoryRouter> | ||
<View data={{ ...mockData, non_exclusive: false }}> | ||
<p>Accordion Content</p> | ||
</View> | ||
</MemoryRouter> | ||
</Provider>, | ||
); | ||
const accordionTitle = container.querySelector('.accordion-title'); | ||
fireEvent.click(accordionTitle); | ||
const contentElement = getByText('RenderBlocks'); | ||
expect(contentElement).toBeInTheDocument(); | ||
}); | ||
it('should open accordion content when Enter key is pressed', () => { | ||
config.blocks.blocksConfig.accordion = { | ||
...config.blocks.blocksConfig.accordion, | ||
semanticIcon: 'someIcon', | ||
}; | ||
const { container, getByText } = render( | ||
<Provider store={store}> | ||
<MemoryRouter> | ||
<View data={mockData} /> | ||
</MemoryRouter> | ||
</Provider>, | ||
); | ||
const accordionTitle = container.querySelector('.accordion-title'); | ||
fireEvent.keyDown(accordionTitle, { keyCode: 13 }); | ||
const contentElement = getByText('RenderBlocks'); | ||
expect(contentElement).toBeInTheDocument(); | ||
}); | ||
}); |
@@ -7,4 +7,3 @@ import React from 'react'; | ||
import { Button } from 'semantic-ui-react'; | ||
import { Icon, FormFieldWrapper } from '@plone/volto/components'; | ||
import { DragDropList } from '@plone/volto/components'; | ||
import { Icon, FormFieldWrapper, DragDropList } from '@plone/volto/components'; | ||
import { emptyBlocksForm } from '@plone/volto/helpers'; | ||
@@ -11,0 +10,0 @@ |
@@ -62,4 +62,4 @@ import accordionSVG from '@plone/volto/icons/list-arrows.svg'; | ||
options: { | ||
styled: 'styled', | ||
fluid: 'fluid', | ||
styled: true, | ||
fluid: true, | ||
}, | ||
@@ -66,0 +66,0 @@ defaults: {}, |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
125447
37
2091
93