New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@eeacms/volto-accordion-block

Package Overview
Dependencies
Maintainers
9
Versions
62
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@eeacms/volto-accordion-block - npm Package Compare versions

Comparing version 9.3.0 to 10.0.0

src/components/manage/Blocks/Accordion/AccordionFilter.jsx

37

CHANGELOG.md

@@ -7,2 +7,39 @@ ### Changelog

### [10.0.0](https://github.com/eea/volto-accordion-block/compare/9.3.0...10.0.0) - 17 August 2023
#### :boom: Breaking Change
- breaking(accordion): use a single icon component with titleIcons config and added panel filtering option #82 from eea/accordion-filter [dana-cfc4 - [`902005a`](https://github.com/eea/volto-accordion-block/commit/902005a7c7e8ed65ec6cb7f32d45a394a474acfa)]
#### :rocket: New Features
- feat(filter): added unit testing for filtering [David Ichim - [`8517248`](https://github.com/eea/volto-accordion-block/commit/851724853f4af8f070f44a22d38b878b773c0e2f)]
#### :bug: Bug Fixes
- fix: i18n - Fix untranslated text persent in addon [Alok Kumar - [`e624d9b`](https://github.com/eea/volto-accordion-block/commit/e624d9b108dc170835adf9be15feaaed347c556c)]
- fix(filter): pass options to Icon component instead of reading always from config [David Ichim - [`f111235`](https://github.com/eea/volto-accordion-block/commit/f1112354d83b0518edf2165b2d19715899810e0c)]
- fix(filter): use config from param after latest change to pass only accordion config [David Ichim - [`aae122e`](https://github.com/eea/volto-accordion-block/commit/aae122ec87947f5dee8c5974d2bfc6848274f3a4)]
#### :nail_care: Enhancements
- change(filter): use volto icons as fallback is iconComponent option isn't set [David Ichim - [`bd504d3`](https://github.com/eea/volto-accordion-block/commit/bd504d34762e2d6e4ea7996fee962fdbaeac268c)]
- change(filter): test now uses dummy accordionConfig without tie to real accordion config [David Ichim - [`90ce56e`](https://github.com/eea/volto-accordion-block/commit/90ce56e47715a0066727b05f4b5facc555a9d450)]
#### :house: Internal changes
- chore(accordion): fixed missing key warning and cleaned commented code from tests [David Ichim - [`290f391`](https://github.com/eea/volto-accordion-block/commit/290f391d95b46a0ae162f4d3f0164772b22e18b1)]
#### :house: Documentation changes
- docs: Cleanup Makefile, update DEVELOP documentation, i18n - refs #254894 [valentinab25 - [`f7e97d4`](https://github.com/eea/volto-accordion-block/commit/f7e97d4db19b1c177b18bedca299c53520089145)]
#### :hammer_and_wrench: Others
- test: Fix AccordionFilter jest tests to include i18n [Alin Voinea - [`eb1e849`](https://github.com/eea/volto-accordion-block/commit/eb1e849010aa4da9855d42fd55f7fb231e77e394)]
- i18n: Filter input placeholder [Alin Voinea - [`6acbd1f`](https://github.com/eea/volto-accordion-block/commit/6acbd1f33d2a4f3a5f3467a4b92eb1e33a6c4bde)]
- i18n [Alin Voinea - [`68a8817`](https://github.com/eea/volto-accordion-block/commit/68a881788576941eecbc6dc874c42720d70fc7ea)]
- better key set to accordion on edit avoiding warning about key being index [David Ichim - [`21bb15f`](https://github.com/eea/volto-accordion-block/commit/21bb15fc77ead710fcb70d5632ccdb9499066f9b)]
- use the index of key instead of uid as the uid ended up performing a click every time you clicked on the accordion title [David Ichim - [`0477d22`](https://github.com/eea/volto-accordion-block/commit/0477d22eef10fd586001dacf1d0a5171b465768f)]
- add missing commit where accordion filter only receives the accordion config [David Ichim - [`db64f21`](https://github.com/eea/volto-accordion-block/commit/db64f21bcc0978d837ac35469eeafe927a62c792)]
### [9.3.0](https://github.com/eea/volto-accordion-block/compare/9.2.0...9.3.0) - 26 July 2023

@@ -9,0 +46,0 @@

2

package.json
{
"name": "@eeacms/volto-accordion-block",
"version": "9.3.0",
"version": "10.0.0",
"description": "volto-accordion-block: Volto accordion block",

@@ -5,0 +5,0 @@ "main": "src/index.js",

@@ -1,6 +0,6 @@

import { Icon as VoltoIcon } from '@plone/volto/components';
import cx from 'classnames';
import React from 'react';
import AnimateHeight from 'react-animate-height';
import { Accordion, Input, Icon } from 'semantic-ui-react';
import { Accordion, Input } from 'semantic-ui-react';
import { Icon } from './util';
import config from '@plone/volto/registry';

@@ -21,2 +21,5 @@

const { titleIcons } = accordionConfig;
const isActive = activeIndex.includes(index);
const iconOnRight = data.right_arrows;
const iconPosition = iconOnRight ? 'rightPosition' : 'leftPosition';

@@ -42,6 +45,2 @@ const handleClick = (e, itemProps) => {

const isExclusive = (index) => {
return activeIndex.includes(index);
};
React.useEffect(() => {

@@ -61,31 +60,18 @@ return data.collapsed ? setActiveIndex([]) : setActiveIndex([0]);

as={data.title_size}
active={isExclusive(index)}
active={isActive}
index={index}
onClick={handleClick}
className={cx('accordion-title', {
'align-arrow-left': !props?.data?.right_arrows,
'align-arrow-right': props?.data?.right_arrows,
'align-arrow-left': !iconOnRight,
'align-arrow-right': iconOnRight,
})}
>
{accordionConfig.semanticIcon ? (
<Icon className={accordionConfig.semanticIcon} />
) : isExclusive(index) ? (
<VoltoIcon
name={
props?.data?.right_arrows
? titleIcons.opened.rightPosition
: titleIcons.opened.leftPosition
}
size={titleIcons.size}
/>
) : (
<VoltoIcon
name={
props?.data?.right_arrows
? titleIcons.closed.rightPosition
: titleIcons.closed.leftPosition
}
size={titleIcons.size}
/>
)}
<Icon
options={titleIcons}
name={
isActive
? titleIcons.opened[iconPosition]
: titleIcons.closed[iconPosition]
}
/>
{!data.readOnlyTitles ? (

@@ -111,7 +97,5 @@ <Input

duration={500}
height={isExclusive(index) ? 'auto' : 0}
height={isActive ? 'auto' : 0}
>
<Accordion.Content active={isExclusive(index)}>
{children}
</Accordion.Content>
<Accordion.Content active={isActive}>{children}</Accordion.Content>
</AnimateHeight>

@@ -118,0 +102,0 @@ </React.Fragment>

@@ -10,3 +10,2 @@ import { render, fireEvent } from '@testing-library/react';

...config.blocks.blocksConfig.accordion,
semanticIcon: 'someIcon',
defaults: {

@@ -17,10 +16,11 @@ theme: 'defaultTheme',

opened: {
rightPosition: 'openedRightIcon',
leftPosition: 'openedLeftIcon',
rightPosition: 'chevron left',
leftPosition: 'chevron right',
},
closed: {
rightPosition: 'closedRightIcon',
leftPosition: 'closedLeftIcon',
rightPosition: 'chevron down',
leftPosition: 'chevron down',
},
size: '10px',
size: 'tiny',
iconComponent: 'SemanticIcon',
},

@@ -127,3 +127,2 @@ };

...config.blocks.blocksConfig.accordion,
semanticIcon: undefined,
};

@@ -130,0 +129,0 @@ const { container, getByText } = render(

@@ -19,2 +19,3 @@ import {

import AccordionEdit from './AccordionEdit';
import AccordionFilter from './AccordionFilter';
import EditBlockWrapper from './EditBlockWrapper';

@@ -29,2 +30,3 @@ import './editor.less';

const [multiSelected, setMultiSelected] = useState([]);
const [filterValue, setFilterValue] = useState('');
const {

@@ -207,2 +209,6 @@ block,

const handleFilteredValueChange = (value) => {
setFilterValue(value);
};
// Get editing instructions from block settings or props

@@ -266,2 +272,4 @@ let instructions = data?.instructions?.data || data?.instructions;

const schema = AccordionBlockSchema({ intl });
return (

@@ -280,42 +288,47 @@ <>

</legend>
{panels.map(([uid, panel], index) => (
<AccordionEdit
uid={uid}
panel={panel}
panelData={panelData}
handleTitleChange={handleTitleChange}
handleTitleClick={() => setSelectedBlock({})}
{data.filtering && (
<AccordionFilter
config={blockConfig}
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, {
...data,
data: {
...panelData,
blocks: {
...panelData.blocks,
[uid]: newFormData,
},
},
});
}}
onChangeField={(id, value) => {
if (['blocks', 'blocks_layout'].indexOf(id) > -1) {
blockState[id] = value;
filterValue={filterValue}
handleFilteredValueChange={handleFilteredValueChange}
/>
)}
{panels
.filter(
(panel) =>
!data.filtering ||
filterValue === '' ||
(filterValue !== '' &&
panel[1].title
?.toLowerCase()
.includes(filterValue.toLowerCase())),
)
.map(([uid, panel], index) => (
<AccordionEdit
uid={uid}
panel={panel}
panelData={panelData}
handleTitleChange={handleTitleChange}
handleTitleClick={() => setSelectedBlock({})}
data={data}
index={index}
key={`accordion-${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,53 +340,67 @@ ...data,

...panelData.blocks,
[uid]: {
...panelData.blocks?.[uid],
...blockState,
},
[uid]: newFormData,
},
},
});
} 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>
))}
}}
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 ? (

@@ -412,4 +439,4 @@ <BlocksToolbar

<BlockDataForm
schema={AccordionBlockSchema({ intl })}
title="Accordion block"
schema={schema}
title={schema.title}
onChangeField={(id, value) => {

@@ -416,0 +443,0 @@ onChangeBlock(block, {

@@ -27,9 +27,11 @@ import React from 'react';

opened: {
rightPosition: '',
leftPosition: '',
rightPosition: 'chevron left',
leftPosition: 'chevron right',
},
closed: {
rightPosition: '',
leftPosition: '',
rightPosition: 'chevron down',
leftPosition: 'chevron down',
},
size: 'tiny',
iconComponent: 'SemanticIcon',
},

@@ -36,0 +38,0 @@ };

@@ -10,2 +10,6 @@ import config from '@plone/volto/registry';

},
AccordionBlock: {
id: 'Accordion block',
defaultMessage: 'Accordion block',
},
Options: {

@@ -47,2 +51,6 @@ id: 'Options',

},
filtering: {
id: 'Enable filtering',
defaultMessage: 'Enable filtering',
},
Theme: {

@@ -74,21 +82,23 @@ id: 'Theme',

export const AccordionSchema = {
title: 'Accordion',
fieldsets: [
{
id: 'default',
title: 'Default',
fields: ['panel_title'],
export const AccordionSchema = (intl) => {
return {
title: intl.formatMessage(messages.Accordion),
fieldsets: [
{
id: 'default',
title: 'Default',
fields: ['panel_title'],
},
],
properties: {
panel_title: {
title: 'Accordion title',
},
},
],
properties: {
panel_title: {
title: 'Accordion title',
},
},
required: [],
required: [],
};
};
export const AccordionBlockSchema = ({ intl }) => ({
title: 'Accordion block',
title: intl.formatMessage(messages.AccordionBlock),
fieldsets: [

@@ -110,2 +120,3 @@ {

'non_exclusive',
'filtering',
],

@@ -126,3 +137,3 @@ },

type: 'panels',
schema: AccordionSchema,
schema: AccordionSchema(intl),
},

@@ -158,2 +169,7 @@ title_size: {

},
filtering: {
title: intl.formatMessage(messages.filtering),
type: 'boolean',
default: false,
},
},

@@ -160,0 +176,0 @@ required: [],

import { v4 as uuid } from 'uuid';
import { map } from 'lodash';
import { Icon as VoltoIcon } from '@plone/volto/components';
import { Icon as SemanticIcon } from 'semantic-ui-react';
import {

@@ -45,1 +48,16 @@ getBlocksFieldname,

};
export const Icon = (props) => {
const { name, options, ...rest } = props;
const componentToRender = options.iconComponent;
// Map component names to their actual components
const componentMap = {
SemanticIcon,
VoltoIcon,
};
// Get the component from the map based on the configuration
const IconComponent = componentMap[componentToRender] || VoltoIcon;
return <IconComponent size={options.size} name={name} {...rest} />;
};
import React from 'react';
import { getPanels, accordionBlockHasValue } from './util';
import { Accordion, Icon } from 'semantic-ui-react';
import { getPanels, accordionBlockHasValue, Icon } from './util';
import { Accordion } from 'semantic-ui-react';
import { withBlockExtensions } from '@plone/volto/helpers';

@@ -8,6 +8,7 @@ import { useLocation, useHistory } from 'react-router-dom';

import cx from 'classnames';
import { Icon as VoltoIcon, RenderBlocks } from '@plone/volto/components';
import { RenderBlocks } from '@plone/volto/components';
import AnimateHeight from 'react-animate-height';
import config from '@plone/volto/registry';
import './editor.less';
import AccordionFilter from './AccordionFilter';

@@ -27,5 +28,8 @@ const useQuery = (location) => {

const [activePanel, setActivePanel] = React.useState([]);
const [filterValue, setFilterValue] = React.useState('');
const [itemToScroll, setItemToScroll] = React.useState('');
const accordionConfig = config.blocks.blocksConfig.accordion;
const { titleIcons } = accordionConfig;
const iconOnRight = data.right_arrows;
const iconPosition = iconOnRight ? 'rightPosition' : 'leftPosition';

@@ -83,2 +87,6 @@ const query = useQuery(location);

const handleFilteredValueChange = (value) => {
setFilterValue(value);
};
const scrollToElement = () => {

@@ -122,77 +130,85 @@ if (!!activePanels && !!activePanels[0].length) {

{data.headline && <h2 className="headline">{data.headline}</h2>}
{panels.map(([id, panel], index) => {
return accordionBlockHasValue(panel) ? (
<Accordion
key={id}
id={id}
exclusive={!data.exclusive}
className={
data.styles ? data.styles.theme : accordionConfig?.defaults?.theme
}
{...accordionConfig.options}
>
<React.Fragment>
<Accordion.Title
as={data.title_size}
active={isExclusive(id)}
index={index}
tabIndex={0}
onClick={(e) => handleClick(e, { index, id })}
onKeyDown={(e) => {
if (e.nativeEvent.keyCode === 13) {
handleClick(e, { index });
}
}}
className={cx('accordion-title', {
'align-arrow-left': !props?.data?.right_arrows,
'align-arrow-right': props?.data?.right_arrows,
})}
>
{accordionConfig.semanticIcon ? (
<Icon className={accordionConfig.semanticIcon} />
) : isExclusive(id) ? (
<VoltoIcon
{data.filtering && (
<AccordionFilter
config={accordionConfig}
data={data}
filterValue={filterValue}
handleFilteredValueChange={handleFilteredValueChange}
/>
)}
{panels
.filter(
(panel) =>
!data.filtering ||
filterValue === '' ||
(filterValue !== '' &&
panel[1].title
?.toLowerCase()
.includes(filterValue.toLowerCase())),
)
.map(([id, panel], index) => {
const active = isExclusive(id);
return accordionBlockHasValue(panel) ? (
<Accordion
key={id}
id={id}
exclusive={!data.exclusive}
className={
data.styles
? data.styles.theme
: accordionConfig?.defaults?.theme
}
{...accordionConfig.options}
>
<React.Fragment>
<Accordion.Title
as={data.title_size}
active={active}
index={index}
tabIndex={0}
onClick={(e) => handleClick(e, { index, id })}
onKeyDown={(e) => {
if (e.nativeEvent.keyCode === 13) {
handleClick(e, { index });
}
}}
className={cx('accordion-title', {
'align-arrow-left': !iconOnRight,
'align-arrow-right': iconOnRight,
})}
>
<Icon
options={titleIcons}
name={
props?.data?.right_arrows
? titleIcons.opened.rightPosition
: titleIcons.opened.leftPosition
active
? titleIcons.opened[iconPosition]
: titleIcons.closed[iconPosition]
}
size={titleIcons.size}
/>
) : (
<VoltoIcon
name={
props?.data?.right_arrows
? titleIcons.closed.rightPosition
: titleIcons.closed.leftPosition
<span>{panel?.title}</span>
</Accordion.Title>
<AnimateHeight
animateOpacity
duration={500}
height={active ? 'auto' : 0}
onTransitionEnd={() => {
if (!!activePanels && id === itemToScroll) {
scrollToElement();
setItemToScroll('');
}
size={titleIcons.size}
/>
)}
<span>{panel?.title}</span>
</Accordion.Title>
<AnimateHeight
animateOpacity
duration={500}
height={isExclusive(id) ? 'auto' : 0}
onTransitionEnd={() => {
if (!!activePanels && id === itemToScroll) {
scrollToElement();
setItemToScroll('');
}
}}
>
<Accordion.Content active={isExclusive(id)}>
<RenderBlocks
{...props}
location={location}
metadata={metadata}
content={panel}
/>
</Accordion.Content>
</AnimateHeight>
</React.Fragment>
</Accordion>
) : null;
})}
}}
>
<Accordion.Content active={active}>
<RenderBlocks
{...props}
location={location}
metadata={metadata}
content={panel}
/>
</Accordion.Content>
</AnimateHeight>
</React.Fragment>
</Accordion>
) : null;
})}
</div>

@@ -199,0 +215,0 @@ );

@@ -16,10 +16,11 @@ import React from 'react';

opened: {
rightPosition: '',
leftPosition: '',
rightPosition: 'chevron left',
leftPosition: 'chevron right',
},
closed: {
rightPosition: '',
leftPosition: '',
rightPosition: 'chevron down',
leftPosition: 'chevron down',
},
size: '10px',
size: 'tiny',
iconComponent: 'SemanticIcon',
},

@@ -48,2 +49,3 @@ };

accordionBlockHasValue: jest.fn(),
Icon: () => <div>Icon</div>,
}));

@@ -119,6 +121,2 @@

utils.accordionBlockHasValue.mockReturnValue(true);
config.blocks.blocksConfig.accordion = {
...config.blocks.blocksConfig.accordion,
semanticIcon: 'someIcon',
};
const { container, getByText } = render(

@@ -157,7 +155,2 @@ <Provider store={store}>

it('should open accordion content when Enter key is pressed', () => {
config.blocks.blocksConfig.accordion = {
...config.blocks.blocksConfig.accordion,
semanticIcon: 'someIcon',
};
const { container, getByText } = render(

@@ -164,0 +157,0 @@ <Provider store={store}>

@@ -73,3 +73,4 @@ import React from 'react';

{/* Custom addMessage in schema, else default to english */}
{objectSchema.addMessage || `Add ${objectSchema.title}`}
{objectSchema.addMessage ||
`${intl.formatMessage(messages.add)} ${objectSchema.title}`}
</Button>

@@ -76,0 +77,0 @@ </div>

@@ -12,2 +12,4 @@ import accordionSVG from '@plone/volto/icons/list-arrows.svg';

import downSVG from '@plone/volto/icons/down-key.svg';
import filterSVG from '@plone/volto/icons/filter.svg';
import clearSVG from '@plone/volto/icons/clear.svg';

@@ -51,3 +53,6 @@ const extendedSchema = (config) => {

opened: { leftPosition: downSVG, rightPosition: downSVG },
filtered: { leftPosition: clearSVG, rightPosition: clearSVG },
unfiltered: { leftPosition: filterSVG, rightPosition: filterSVG },
size: '24px',
iconComponent: 'VoltoIcon', // other option is SemanticIcon
},

@@ -54,0 +59,0 @@ view: AccordionBlockView,

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc