refactor: simplify component

This commit is contained in:
Josh 2022-11-10 17:47:26 +00:00
parent a8f807d27e
commit 9487d0c9a5
12 changed files with 159 additions and 1580 deletions

View File

@ -13,7 +13,8 @@ import { BaseButton } from '@strapi/design-system/BaseButton';
import { Box } from '@strapi/design-system/Box';
import { Flex } from '@strapi/design-system/Flex';
import { Typography } from '@strapi/design-system/Typography';
import { getTrad } from '../../../../utils';
import { getTrad } from '../../../utils';
const StyledAddIcon = styled(PlusCircle)`
transform: ${({ $isOpen }) => ($isOpen ? 'rotate(45deg)' : 'rotate(0deg)')};

View File

@ -1,763 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`<AddComponentButton /> displays the name of the dz when the label is empty 1`] = `
.c10 {
border: 0;
-webkit-clip: rect(0 0 0 0);
clip: rect(0 0 0 0);
height: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
width: 1px;
}
.c1 {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
cursor: pointer;
padding: 8px;
border-radius: 4px;
background: #ffffff;
border: 1px solid #dcdce4;
position: relative;
outline: none;
}
.c1 svg {
height: 12px;
width: 12px;
}
.c1 svg > g,
.c1 svg path {
fill: #ffffff;
}
.c1[aria-disabled='true'] {
pointer-events: none;
}
.c1:after {
-webkit-transition-property: all;
transition-property: all;
-webkit-transition-duration: 0.2s;
transition-duration: 0.2s;
border-radius: 8px;
content: '';
position: absolute;
top: -4px;
bottom: -4px;
left: -4px;
right: -4px;
border: 2px solid transparent;
}
.c1:focus-visible {
outline: none;
}
.c1:focus-visible:after {
border-radius: 8px;
content: '';
position: absolute;
top: -5px;
bottom: -5px;
left: -5px;
right: -5px;
border: 2px solid #4945ff;
}
.c4 {
padding-right: 8px;
}
.c0 {
-webkit-align-items: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-flex-direction: row;
-ms-flex-direction: row;
flex-direction: row;
-webkit-box-pack: center;
-webkit-justify-content: center;
-ms-flex-pack: center;
justify-content: center;
}
.c3 {
-webkit-align-items: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-flex-direction: row;
-ms-flex-direction: row;
flex-direction: row;
}
.c9 {
font-weight: 600;
color: #8e8ea9;
font-size: 0.75rem;
line-height: 1.33;
}
.c7 {
-webkit-transform: rotate(0deg);
-ms-transform: rotate(0deg);
transform: rotate(0deg);
}
.c7 > circle {
fill: #eaeaef;
}
.c7 > path {
fill: #666687;
}
.c2 {
border-radius: 26px;
border-color: #eaeaef;
background: #ffffff;
padding-top: 12px;
padding-right: 16px;
padding-bottom: 12px;
padding-left: 16px;
box-shadow: 0px 1px 4px rgba(33,33,52,0.1);
}
.c2 svg {
height: 24px;
width: 24px;
}
.c2 svg > path {
fill: #666687;
}
.c2:hover {
color: #4945ff !important;
}
.c2:hover .c8 {
color: #4945ff !important;
}
.c2:hover .c6 > circle {
fill: #4945ff;
}
.c2:hover .c6 > path {
fill: #f6f6f9;
}
.c2:active .c8 {
color: #4945ff;
}
.c2:active .c6 > circle {
fill: #4945ff;
}
.c2:active .c6 > path {
fill: #f6f6f9;
}
.c5 {
height: 100%;
}
<div>
<div
class="c0"
>
<div
class=""
style="cursor: pointer;"
>
<button
aria-disabled="false"
class="c1 c2"
type="button"
>
<div
class="c3"
>
<div
aria-hidden="true"
class="c4 c5"
>
<svg
class="c6 c7"
fill="none"
height="1em"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<circle
cx="12"
cy="12"
fill="#212134"
r="12"
/>
<path
d="M17 12.569c0 .124-.1.224-.225.224h-3.981v3.982c0 .124-.101.225-.226.225h-1.136a.225.225 0 01-.226-.225v-3.981H7.226A.225.225 0 017 12.567v-1.136c0-.125.1-.226.225-.226h3.982V7.226c0-.124.1-.225.224-.225h1.138c.124 0 .224.1.224.225v3.982h3.982c.124 0 .225.1.225.224v1.138z"
fill="#F6F6F9"
/>
</svg>
</div>
<span
class="c8 c9"
>
Add a component to name
</span>
</div>
</button>
</div>
</div>
<div
class="c10"
>
<p
aria-live="polite"
aria-relevant="all"
id="live-region-log"
role="log"
/>
<p
aria-live="polite"
aria-relevant="all"
id="live-region-status"
role="status"
/>
<p
aria-live="assertive"
aria-relevant="all"
id="live-region-alert"
role="alert"
/>
</div>
</div>
`;
exports[`<AddComponentButton /> renders and matches the snapshot 1`] = `
.c10 {
border: 0;
-webkit-clip: rect(0 0 0 0);
clip: rect(0 0 0 0);
height: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
width: 1px;
}
.c1 {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
cursor: pointer;
padding: 8px;
border-radius: 4px;
background: #ffffff;
border: 1px solid #dcdce4;
position: relative;
outline: none;
}
.c1 svg {
height: 12px;
width: 12px;
}
.c1 svg > g,
.c1 svg path {
fill: #ffffff;
}
.c1[aria-disabled='true'] {
pointer-events: none;
}
.c1:after {
-webkit-transition-property: all;
transition-property: all;
-webkit-transition-duration: 0.2s;
transition-duration: 0.2s;
border-radius: 8px;
content: '';
position: absolute;
top: -4px;
bottom: -4px;
left: -4px;
right: -4px;
border: 2px solid transparent;
}
.c1:focus-visible {
outline: none;
}
.c1:focus-visible:after {
border-radius: 8px;
content: '';
position: absolute;
top: -5px;
bottom: -5px;
left: -5px;
right: -5px;
border: 2px solid #4945ff;
}
.c4 {
padding-right: 8px;
}
.c0 {
-webkit-align-items: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-flex-direction: row;
-ms-flex-direction: row;
flex-direction: row;
-webkit-box-pack: center;
-webkit-justify-content: center;
-ms-flex-pack: center;
justify-content: center;
}
.c3 {
-webkit-align-items: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-flex-direction: row;
-ms-flex-direction: row;
flex-direction: row;
}
.c9 {
font-weight: 600;
color: #8e8ea9;
font-size: 0.75rem;
line-height: 1.33;
}
.c7 {
-webkit-transform: rotate(0deg);
-ms-transform: rotate(0deg);
transform: rotate(0deg);
}
.c7 > circle {
fill: #eaeaef;
}
.c7 > path {
fill: #666687;
}
.c2 {
border-radius: 26px;
border-color: #eaeaef;
background: #ffffff;
padding-top: 12px;
padding-right: 16px;
padding-bottom: 12px;
padding-left: 16px;
box-shadow: 0px 1px 4px rgba(33,33,52,0.1);
}
.c2 svg {
height: 24px;
width: 24px;
}
.c2 svg > path {
fill: #666687;
}
.c2:hover {
color: #4945ff !important;
}
.c2:hover .c8 {
color: #4945ff !important;
}
.c2:hover .c6 > circle {
fill: #4945ff;
}
.c2:hover .c6 > path {
fill: #f6f6f9;
}
.c2:active .c8 {
color: #4945ff;
}
.c2:active .c6 > circle {
fill: #4945ff;
}
.c2:active .c6 > path {
fill: #f6f6f9;
}
.c5 {
height: 100%;
}
<div>
<div
class="c0"
>
<div
class=""
style="cursor: pointer;"
>
<button
aria-disabled="false"
class="c1 c2"
type="button"
>
<div
class="c3"
>
<div
aria-hidden="true"
class="c4 c5"
>
<svg
class="c6 c7"
fill="none"
height="1em"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<circle
cx="12"
cy="12"
fill="#212134"
r="12"
/>
<path
d="M17 12.569c0 .124-.1.224-.225.224h-3.981v3.982c0 .124-.101.225-.226.225h-1.136a.225.225 0 01-.226-.225v-3.981H7.226A.225.225 0 017 12.567v-1.136c0-.125.1-.226.225-.226h3.982V7.226c0-.124.1-.225.224-.225h1.138c.124 0 .224.1.224.225v3.982h3.982c.124 0 .225.1.225.224v1.138z"
fill="#F6F6F9"
/>
</svg>
</div>
<span
class="c8 c9"
>
Add a component to test
</span>
</div>
</button>
</div>
</div>
<div
class="c10"
>
<p
aria-live="polite"
aria-relevant="all"
id="live-region-log"
role="log"
/>
<p
aria-live="polite"
aria-relevant="all"
id="live-region-status"
role="status"
/>
<p
aria-live="assertive"
aria-relevant="all"
id="live-region-alert"
role="alert"
/>
</div>
</div>
`;
exports[`<AddComponentButton /> renders and matches the snapshot when the isOpen prop is truthy 1`] = `
.c10 {
border: 0;
-webkit-clip: rect(0 0 0 0);
clip: rect(0 0 0 0);
height: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
width: 1px;
}
.c1 {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
cursor: pointer;
padding: 8px;
border-radius: 4px;
background: #ffffff;
border: 1px solid #dcdce4;
position: relative;
outline: none;
}
.c1 svg {
height: 12px;
width: 12px;
}
.c1 svg > g,
.c1 svg path {
fill: #ffffff;
}
.c1[aria-disabled='true'] {
pointer-events: none;
}
.c1:after {
-webkit-transition-property: all;
transition-property: all;
-webkit-transition-duration: 0.2s;
transition-duration: 0.2s;
border-radius: 8px;
content: '';
position: absolute;
top: -4px;
bottom: -4px;
left: -4px;
right: -4px;
border: 2px solid transparent;
}
.c1:focus-visible {
outline: none;
}
.c1:focus-visible:after {
border-radius: 8px;
content: '';
position: absolute;
top: -5px;
bottom: -5px;
left: -5px;
right: -5px;
border: 2px solid #4945ff;
}
.c4 {
padding-right: 8px;
}
.c0 {
-webkit-align-items: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-flex-direction: row;
-ms-flex-direction: row;
flex-direction: row;
-webkit-box-pack: center;
-webkit-justify-content: center;
-ms-flex-pack: center;
justify-content: center;
}
.c3 {
-webkit-align-items: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-flex-direction: row;
-ms-flex-direction: row;
flex-direction: row;
}
.c9 {
font-weight: 600;
color: #8e8ea9;
font-size: 0.75rem;
line-height: 1.33;
}
.c7 {
-webkit-transform: rotate(45deg);
-ms-transform: rotate(45deg);
transform: rotate(45deg);
}
.c7 > circle {
fill: #eaeaef;
}
.c7 > path {
fill: #666687;
}
.c2 {
border-radius: 26px;
border-color: #eaeaef;
background: #ffffff;
padding-top: 12px;
padding-right: 16px;
padding-bottom: 12px;
padding-left: 16px;
box-shadow: 0px 1px 4px rgba(33,33,52,0.1);
}
.c2 svg {
height: 24px;
width: 24px;
}
.c2 svg > path {
fill: #666687;
}
.c2:hover {
color: #4945ff !important;
}
.c2:hover .c8 {
color: #4945ff !important;
}
.c2:hover .c6 > circle {
fill: #4945ff;
}
.c2:hover .c6 > path {
fill: #f6f6f9;
}
.c2:active .c8 {
color: #4945ff;
}
.c2:active .c6 > circle {
fill: #4945ff;
}
.c2:active .c6 > path {
fill: #f6f6f9;
}
.c5 {
height: 100%;
}
<div>
<div
class="c0"
>
<div
class=""
style="cursor: pointer;"
>
<button
aria-disabled="false"
class="c1 c2"
type="button"
>
<div
class="c3"
>
<div
aria-hidden="true"
class="c4 c5"
>
<svg
class="c6 c7"
fill="none"
height="1em"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<circle
cx="12"
cy="12"
fill="#212134"
r="12"
/>
<path
d="M17 12.569c0 .124-.1.224-.225.224h-3.981v3.982c0 .124-.101.225-.226.225h-1.136a.225.225 0 01-.226-.225v-3.981H7.226A.225.225 0 017 12.567v-1.136c0-.125.1-.226.225-.226h3.982V7.226c0-.124.1-.225.224-.225h1.138c.124 0 .224.1.224.225v3.982h3.982c.124 0 .225.1.225.224v1.138z"
fill="#F6F6F9"
/>
</svg>
</div>
<span
class="c8 c9"
>
Close
</span>
</div>
</button>
</div>
</div>
<div
class="c10"
>
<p
aria-live="polite"
aria-relevant="all"
id="live-region-log"
role="log"
/>
<p
aria-live="polite"
aria-relevant="all"
id="live-region-status"
role="status"
/>
<p
aria-live="assertive"
aria-relevant="all"
id="live-region-alert"
role="alert"
/>
</div>
</div>
`;

View File

@ -1,23 +1,23 @@
import React, { memo, Suspense, useMemo } from 'react';
import React, { useMemo, useState } from 'react';
import PropTypes from 'prop-types';
import styled from 'styled-components';
import isEqual from 'react-fast-compare';
import { useIntl } from 'react-intl';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Accordion, AccordionToggle, AccordionContent } from '@strapi/design-system/Accordion';
import { IconButton } from '@strapi/design-system/IconButton';
import { FocusTrap } from '@strapi/design-system/FocusTrap';
import { Box } from '@strapi/design-system/Box';
import { Flex } from '@strapi/design-system/Flex';
import { Stack } from '@strapi/design-system/Stack';
import { Loader } from '@strapi/design-system/Loader';
import Trash from '@strapi/icons/Trash';
import ArrowDown from '@strapi/icons/ArrowDown';
import ArrowUp from '@strapi/icons/ArrowUp';
import { useContentTypeLayout } from '../../../../hooks';
import { getTrad } from '../../../../utils';
import FieldComponent from '../../../FieldComponent';
import Rectangle from './Rectangle';
import { useContentTypeLayout } from '../../../hooks';
import { getTrad } from '../../../utils';
import FieldComponent from '../../FieldComponent';
const ActionStack = styled(Stack)`
svg {
@ -42,20 +42,24 @@ const AccordionContentRadius = styled(Box)`
border-radius: 0 0 ${({ theme }) => theme.spaces[1]} ${({ theme }) => theme.spaces[1]};
`;
const Component = ({
const Rectangle = styled(Box)`
width: ${({ theme }) => theme.spaces[2]};
height: ${({ theme }) => theme.spaces[4]};
`;
const DynamicZoneComponent = ({
componentUid,
formErrors,
index,
isOpen,
isFieldAllowed,
moveComponentDown,
moveComponentUp,
onMoveComponentDownClick,
onMoveComponentUpClick,
name,
onToggle,
removeComponentFromDynamicZone,
onRemoveComponentClick,
showDownIcon,
showUpIcon,
}) => {
const [isOpen, setIsOpen] = useState(true);
const { formatMessage } = useIntl();
const { getComponentLayout } = useContentTypeLayout();
const { icon, friendlyName } = useMemo(() => {
@ -66,31 +70,7 @@ const Component = ({
return { friendlyName: displayName, icon };
}, [componentUid, getComponentLayout]);
const handleMoveComponentDown = () => moveComponentDown(name, index);
const handleMoveComponentUp = () => moveComponentUp(name, index);
const handleRemove = () => removeComponentFromDynamicZone(name, index);
const downLabel = formatMessage({
id: getTrad('components.DynamicZone.move-down-label'),
defaultMessage: 'Move component down',
});
const upLabel = formatMessage({
id: getTrad('components.DynamicZone.move-up-label'),
defaultMessage: 'Move component down',
});
const deleteLabel = formatMessage(
{
id: getTrad('components.DynamicZone.delete-label'),
defaultMessage: 'Delete {name}',
},
{ name: friendlyName }
);
const formErrorsKeys = Object.keys(formErrors);
const fieldsErrors = formErrorsKeys.filter((errorKey) => {
const fieldsErrors = Object.keys(formErrors).filter((errorKey) => {
const errorKeysArray = errorKey.split('.');
if (`${errorKeysArray[0]}.${errorKeysArray[1]}` === `${name}.${index}`) {
@ -109,11 +89,17 @@ const Component = ({
});
}
const handleToggle = () => {
setIsOpen((s) => !s);
};
return (
<Box>
<Rectangle />
<Flex justifyContent="center">
<Rectangle background="neutral200" />
</Flex>
<StyledBox hasRadius>
<Accordion expanded={isOpen} onToggle={() => onToggle(index)} size="S" error={errorMessage}>
<Accordion expanded={isOpen} onToggle={handleToggle} size="S" error={errorMessage}>
<AccordionToggle
startIcon={<FontAwesomeIcon icon={icon} />}
action={
@ -121,24 +107,36 @@ const Component = ({
{showDownIcon && (
<IconButtonCustom
noBorder
label={downLabel}
onClick={handleMoveComponentDown}
label={formatMessage({
id: getTrad('components.DynamicZone.move-up-label'),
defaultMessage: 'Move component down',
})}
onClick={onMoveComponentDownClick}
icon={<ArrowDown />}
/>
)}
{showUpIcon && (
<IconButtonCustom
noBorder
label={upLabel}
onClick={handleMoveComponentUp}
label={formatMessage({
id: getTrad('components.DynamicZone.move-down-label'),
defaultMessage: 'Move component down',
})}
onClick={onMoveComponentUpClick}
icon={<ArrowUp />}
/>
)}
{isFieldAllowed && (
<IconButtonCustom
noBorder
label={deleteLabel}
onClick={handleRemove}
label={formatMessage(
{
id: getTrad('components.DynamicZone.delete-label'),
defaultMessage: 'Delete {name}',
},
{ name: friendlyName }
)}
onClick={onRemoveComponentClick}
icon={<Trash />}
/>
)}
@ -149,22 +147,12 @@ const Component = ({
/>
<AccordionContent>
<AccordionContentRadius background="neutral0">
<Suspense
fallback={
<Flex justifyContent="center" paddingTop={4} paddingBottom={4}>
<Loader>Loading content.</Loader>
</Flex>
}
>
<FocusTrap onEscape={() => onToggle(index)}>
<FieldComponent
componentUid={componentUid}
icon={icon}
name={`${name}.${index}`}
isFromDynamicZone
/>
</FocusTrap>
</Suspense>
<FieldComponent
componentUid={componentUid}
icon={icon}
name={`${name}.${index}`}
isFromDynamicZone
/>
</AccordionContentRadius>
</AccordionContent>
</Accordion>
@ -173,19 +161,17 @@ const Component = ({
);
};
Component.propTypes = {
DynamicZoneComponent.propTypes = {
componentUid: PropTypes.string.isRequired,
formErrors: PropTypes.object.isRequired,
index: PropTypes.number.isRequired,
isFieldAllowed: PropTypes.bool.isRequired,
isOpen: PropTypes.bool.isRequired,
moveComponentDown: PropTypes.func.isRequired,
moveComponentUp: PropTypes.func.isRequired,
onMoveComponentDownClick: PropTypes.func.isRequired,
onMoveComponentUpClick: PropTypes.func.isRequired,
name: PropTypes.string.isRequired,
onToggle: PropTypes.func.isRequired,
removeComponentFromDynamicZone: PropTypes.func.isRequired,
onRemoveComponentClick: PropTypes.func.isRequired,
showDownIcon: PropTypes.bool.isRequired,
showUpIcon: PropTypes.bool.isRequired,
};
export default memo(Component, isEqual);
export default DynamicZoneComponent;

View File

@ -1,19 +0,0 @@
import React from 'react';
import styled from 'styled-components';
import { Box } from '@strapi/design-system/Box';
import { Flex } from '@strapi/design-system/Flex';
const StyledBox = styled(Box)`
width: ${({ theme }) => theme.spaces[2]};
height: ${({ theme }) => theme.spaces[4]};
`;
const Rectangle = () => {
return (
<Flex justifyContent="center">
<StyledBox background="neutral200" />
</Flex>
);
};
export default Rectangle;

View File

@ -6,13 +6,13 @@
import React from 'react';
import PropTypes from 'prop-types';
import styled from 'styled-components';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Box } from '@strapi/design-system/Box';
import { Typography } from '@strapi/design-system/Typography';
import { Stack } from '@strapi/design-system/Stack';
import { pxToRem } from '@strapi/helper-plugin';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import styled from 'styled-components';
import { useIntl } from 'react-intl';
const StyledFontAwesomeIcon = styled(FontAwesomeIcon)`
width: ${pxToRem(32)} !important;
@ -53,19 +53,14 @@ const ComponentBox = styled(Box)`
}
`;
function ComponentCard({ componentUid, intlLabel, icon, onClick }) {
const { formatMessage } = useIntl();
const handleClick = () => {
onClick(componentUid);
};
export default function ComponentCard({ children, icon, onClick }) {
return (
<button type="button" onClick={handleClick}>
<button type="button" onClick={onClick}>
<ComponentBox borderRadius="borderRadius">
<Stack spacing={1} style={{ justifyContent: 'center', alignItems: 'center' }}>
<StyledFontAwesomeIcon icon={icon} />
<Typography variant="pi" fontWeight="bold" textColor="neutral600">
{formatMessage(intlLabel)}
{children}
</Typography>
</Stack>
</ComponentBox>
@ -79,13 +74,7 @@ ComponentCard.defaultProps = {
};
ComponentCard.propTypes = {
componentUid: PropTypes.string.isRequired,
intlLabel: PropTypes.shape({
id: PropTypes.string.isRequired,
defaultMessage: PropTypes.string.isRequired,
}).isRequired,
children: PropTypes.node.isRequired,
icon: PropTypes.string,
onClick: PropTypes.func,
};
export default ComponentCard;

View File

@ -4,6 +4,7 @@ import { Accordion, AccordionToggle, AccordionContent } from '@strapi/design-sys
import { Box } from '@strapi/design-system/Box';
import styled from 'styled-components';
import { useIntl } from 'react-intl';
import ComponentCard from './ComponentCard';
const Grid = styled.div`
@ -12,7 +13,7 @@ const Grid = styled.div`
grid-gap: ${({ theme }) => theme.spaces[1]};
`;
const Category = ({ category, components, isOdd, isOpen, onAddComponent, onToggle }) => {
const ComponentCategory = ({ category, components, variant, isOpen, onAddComponent, onToggle }) => {
const { formatMessage } = useIntl();
const handleToggle = () => {
@ -22,24 +23,18 @@ const Category = ({ category, components, isOdd, isOpen, onAddComponent, onToggl
return (
<Accordion expanded={isOpen} onToggle={handleToggle} size="S">
<AccordionToggle
variant={isOdd ? 'primary' : 'secondary'}
variant={variant}
title={formatMessage({ id: category, defaultMessage: category })}
togglePosition="left"
/>
<AccordionContent>
<Box paddingTop={4} paddingBottom={4} paddingLeft={3} paddingRight={3}>
<Grid>
{components.map(({ componentUid, info: { displayName, icon } }) => {
return (
<ComponentCard
key={componentUid}
componentUid={componentUid}
intlLabel={{ id: displayName, defaultMessage: displayName }}
icon={icon}
onClick={onAddComponent}
/>
);
})}
{components.map(({ componentUid, info: { displayName, icon } }) => (
<ComponentCard key={componentUid} icon={icon} onClick={onAddComponent(componentUid)}>
{formatMessage({ id: displayName, defaultMessage: displayName })}
</ComponentCard>
))}
</Grid>
</Box>
</AccordionContent>
@ -47,13 +42,13 @@ const Category = ({ category, components, isOdd, isOpen, onAddComponent, onToggl
);
};
Category.propTypes = {
ComponentCategory.propTypes = {
category: PropTypes.string.isRequired,
components: PropTypes.array.isRequired,
isOdd: PropTypes.bool.isRequired,
isOpen: PropTypes.bool.isRequired,
onAddComponent: PropTypes.func.isRequired,
onToggle: PropTypes.func.isRequired,
variant: PropTypes.oneOf(['primary', 'secondary']).isRequired,
};
export default Category;
export default ComponentCategory;

View File

@ -1,4 +1,4 @@
import React, { memo, useCallback, useEffect, useMemo, useState } from 'react';
import React, { useEffect, useMemo, useState } from 'react';
import groupBy from 'lodash/groupBy';
import PropTypes from 'prop-types';
import { useIntl } from 'react-intl';
@ -6,9 +6,11 @@ import { KeyboardNavigable } from '@strapi/design-system/KeyboardNavigable';
import { Box } from '@strapi/design-system/Box';
import { Flex } from '@strapi/design-system/Flex';
import { Typography } from '@strapi/design-system/Typography';
import { getTrad } from '../../../../utils';
import { useContentTypeLayout } from '../../../../hooks';
import Category from './Category';
import { getTrad } from '../../../utils';
import { useContentTypeLayout } from '../../../hooks';
import ComponentCategory from './ComponentCategory';
const ComponentPicker = ({ components, isOpen, onClickAddComponent }) => {
const { formatMessage } = useIntl();
@ -37,22 +39,17 @@ const ComponentPicker = ({ components, isOpen, onClickAddComponent }) => {
}
}, [isOpen, dynamicComponentCategories]);
const handleAddComponentToDz = useCallback(
(componentUid) => {
onClickAddComponent(componentUid);
setCategoryToOpen('');
},
[onClickAddComponent]
);
const handleAddComponentToDz = (componentUid) => () => {
onClickAddComponent(componentUid);
setCategoryToOpen('');
};
const handleClickToggle = useCallback(
(categoryName) => {
const nextCategoryToOpen = categoryToOpen === categoryName ? '' : categoryName;
setCategoryToOpen(nextCategoryToOpen);
},
[categoryToOpen]
);
/**
* @type {(categoryName: string) => void}
*/
const handleClickToggle = (categoryName) => {
setCategoryToOpen((currentCat) => (currentCat === categoryName ? '' : categoryName));
};
if (!isOpen) {
return null;
@ -80,21 +77,17 @@ const ComponentPicker = ({ components, isOpen, onClickAddComponent }) => {
</Flex>
<Box paddingTop={2}>
<KeyboardNavigable attributeName="data-strapi-accordion-toggle">
{dynamicComponentCategories.map(({ category, components }, index) => {
return (
<Category
key={category}
category={category}
components={components}
isOdd={index % 2 === 1}
isOpen={category === categoryToOpen}
// TODO?
// isFirst={index === 0}
onAddComponent={handleAddComponentToDz}
onToggle={handleClickToggle}
/>
);
})}
{dynamicComponentCategories.map(({ category, components }, index) => (
<ComponentCategory
key={category}
category={category}
components={components}
onAddComponent={handleAddComponentToDz}
isOpen={category === categoryToOpen}
onToggle={handleClickToggle}
variant={index % 2 === 1 ? 'primary' : 'secondary'}
/>
))}
</KeyboardNavigable>
</Box>
</Box>
@ -108,4 +101,4 @@ ComponentPicker.propTypes = {
onClickAddComponent: PropTypes.func.isRequired,
};
export default memo(ComponentPicker);
export default ComponentPicker;

View File

@ -17,7 +17,14 @@ const StyledBox = styled(Box)`
border-radius: ${pxToRem(26)};
`;
const DzLabel = ({ label, labelAction, name, numberOfComponents, required, intlDescription }) => {
const DynamicZoneLabel = ({
label,
labelAction,
name,
numberOfComponents,
required,
intlDescription,
}) => {
const { formatMessage } = useIntl();
const intlLabel = formatMessage({ id: label || name, defaultMessage: label || name });
@ -58,14 +65,14 @@ const DzLabel = ({ label, labelAction, name, numberOfComponents, required, intlD
);
};
DzLabel.defaultProps = {
DynamicZoneLabel.defaultProps = {
intlDescription: undefined,
label: '',
labelAction: undefined,
required: false,
};
DzLabel.propTypes = {
DynamicZoneLabel.propTypes = {
intlDescription: PropTypes.shape({
id: PropTypes.string.isRequired,
defaultMessage: PropTypes.string.isRequired,
@ -77,4 +84,4 @@ DzLabel.propTypes = {
required: PropTypes.bool,
};
export default DzLabel;
export default DynamicZoneLabel;

View File

@ -1,530 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`<DzLabel /> displays the labelAction correctly 1`] = `
.c10 {
border: 0;
-webkit-clip: rect(0 0 0 0);
clip: rect(0 0 0 0);
height: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
width: 1px;
}
.c4 {
max-width: 22.25rem;
}
.c0 {
-webkit-align-items: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-flex-direction: row;
-ms-flex-direction: row;
flex-direction: row;
-webkit-box-pack: center;
-webkit-justify-content: center;
-ms-flex-pack: center;
justify-content: center;
}
.c3 {
-webkit-align-items: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-flex-direction: column;
-ms-flex-direction: column;
flex-direction: column;
-webkit-box-pack: center;
-webkit-justify-content: center;
-ms-flex-pack: center;
justify-content: center;
}
.c5 {
-webkit-align-items: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-flex-direction: row;
-ms-flex-direction: row;
flex-direction: row;
}
.c6 {
font-weight: 600;
color: #666687;
display: block;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
font-size: 0.75rem;
line-height: 1.33;
}
.c7 {
font-weight: 600;
color: #666687;
font-size: 0.75rem;
line-height: 1.33;
}
.c1 {
background: #ffffff;
color: #8e8ea9;
padding-top: 12px;
padding-right: 16px;
padding-bottom: 12px;
padding-left: 16px;
box-shadow: 0px 1px 4px rgba(33,33,52,0.1);
}
.c8 {
padding-left: 4px;
}
.c2 {
border-radius: 1.625rem;
}
.c9 {
border: none;
padding: 0;
background: transparent;
}
.c9 svg {
width: 12px;
height: 12px;
fill: #8e8ea9;
}
.c9 svg path {
fill: #8e8ea9;
}
<div>
<div
class="c0"
>
<div
class=""
>
<div
class="c1 c2"
>
<div
class="c3"
>
<div
class="c4 c5"
>
<span
class="c6"
>
dz
 
</span>
<span
class="c7"
>
(
1
)
</span>
<div
class="c8"
>
<span>
<button
aria-describedby="tooltip-1"
aria-label="i18n"
class="c9"
tabindex="0"
type="button"
>
<svg
aria-hidden="true"
fill="none"
height="1em"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M12.59 23.679l-.044-.007a.045.045 0 00.043.007zM22.334 8.345a.295.295 0 00-.572-.033.296.296 0 01-.28.206h-.828a.294.294 0 01-.153-.042l-1.199-.72a.293.293 0 00-.152-.042h-1.918a.294.294 0 00-.163.05l-2.366 1.577a.295.295 0 00-.131.248v2.236a.295.295 0 00.156.261l3.101 1.656a.298.298 0 01.157.257L18 15.257a.296.296 0 00.153.255l1.246.69a.297.297 0 01.152.258v2.604a.297.297 0 00.34.292.296.296 0 00.152-.07c.502-.443 1.223-1.09 1.319-1.237a11.186 11.186 0 001.175-2.415c.679-1.966.142-5.501-.203-7.289zM13.629 14.507l-3.286-2.464a.214.214 0 00-.129-.043H8.655a.203.203 0 01-.143-.06l-.735-.734a.216.216 0 00-.152-.063h-2.85a.202.202 0 01-.198-.243.203.203 0 01.055-.104l.451-.45a.202.202 0 01.144-.06H6.96a.428.428 0 00.413-.313l.369-1.312a.214.214 0 01.107-.132L9.32 7.77a.203.203 0 00.11-.18v-.67c0-.042.013-.082.037-.116l.782-1.126a.2.2 0 01.095-.074l1.095-.411a.203.203 0 00.131-.19v-.611a.203.203 0 00-.09-.17l-1.097-.729a.205.205 0 00-.206-.012l-1.493.747a.202.202 0 01-.214-.022l-.709-.56a.204.204 0 01.006-.321l.575-.424a.202.202 0 00-.005-.33l-.896-.625a.203.203 0 00-.214-.012c-.324.177-1.275.702-1.613.939a11.222 11.222 0 00-3.651 4.285c-.098.202-.218.407-.23.628-.012.221-.185.715-.258.915a.202.202 0 00.013.166l1.912 3.514a.2.2 0 00.074.077l2.012 1.207a.201.201 0 01.097.146l.403 2.922a.205.205 0 00.086.14l1.57 1.079a.214.214 0 01.088.133l.832 3.953a.193.193 0 00.027.066c.078.126.39.589.766.658-.035.01-.066.031-.101.041.09.016.18.037.268.063.107.028.214.053.321.076.168.033.184.06.265-.09.107-.2.23-.268.321-.292a.207.207 0 00.155-.156l.54-2.5a.215.215 0 01.085-.13l2.411-1.709a.214.214 0 00.09-.175v-3.212a.215.215 0 00-.082-.172z"
fill="#32324D"
/>
<path
d="M12.321.857s-.195.011-.235.012a11.113 11.113 0 00-3.932.845c.13.09-.094.173-.094.173l.35.684h1.876l1.285.643 1.125-.643-.375-1.714zM17.262 4.718l.863-.75a.214.214 0 00-.05-.357l-1.008-.467a.214.214 0 00-.284.101l-.415.869a.214.214 0 00.08.274l.56.35a.214.214 0 00.254-.02zM21.302 5.822l-.312-.483a.337.337 0 01-.014-.023c-.056-.115-.521-1.055-.91-1.42-.292-.276-.375-.196-.398-.135a.202.202 0 01-.064.085l-1.545 1.25a.214.214 0 01-.135.047h-.8a.214.214 0 00-.151.062l-.643.643a.215.215 0 000 .304l.643.642a.214.214 0 00.152.063h4.027a.215.215 0 00.214-.223l-.03-.705a.214.214 0 00-.034-.107z"
fill="#32324D"
/>
<path
d="M12 2.143A9.857 9.857 0 115.03 5.03 9.791 9.791 0 0112 2.143zM12 0C5.373 0 0 5.373 0 12s5.373 12 12 12 12-5.373 12-12S18.627 0 12 0z"
fill="#32324D"
/>
</svg>
</button>
</span>
</div>
</div>
</div>
</div>
</div>
</div>
<div
class="c10"
>
<p
aria-live="polite"
aria-relevant="all"
id="live-region-log"
role="log"
/>
<p
aria-live="polite"
aria-relevant="all"
id="live-region-status"
role="status"
/>
<p
aria-live="assertive"
aria-relevant="all"
id="live-region-alert"
role="alert"
/>
</div>
</div>
`;
exports[`<DzLabel /> displays the name of the dz when the label is empty 1`] = `
.c8 {
border: 0;
-webkit-clip: rect(0 0 0 0);
clip: rect(0 0 0 0);
height: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
width: 1px;
}
.c4 {
max-width: 22.25rem;
}
.c0 {
-webkit-align-items: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-flex-direction: row;
-ms-flex-direction: row;
flex-direction: row;
-webkit-box-pack: center;
-webkit-justify-content: center;
-ms-flex-pack: center;
justify-content: center;
}
.c3 {
-webkit-align-items: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-flex-direction: column;
-ms-flex-direction: column;
flex-direction: column;
-webkit-box-pack: center;
-webkit-justify-content: center;
-ms-flex-pack: center;
justify-content: center;
}
.c5 {
-webkit-align-items: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-flex-direction: row;
-ms-flex-direction: row;
flex-direction: row;
}
.c6 {
font-weight: 600;
color: #666687;
display: block;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
font-size: 0.75rem;
line-height: 1.33;
}
.c7 {
font-weight: 600;
color: #666687;
font-size: 0.75rem;
line-height: 1.33;
}
.c1 {
background: #ffffff;
color: #8e8ea9;
padding-top: 12px;
padding-right: 16px;
padding-bottom: 12px;
padding-left: 16px;
box-shadow: 0px 1px 4px rgba(33,33,52,0.1);
}
.c2 {
border-radius: 1.625rem;
}
<div>
<div
class="c0"
>
<div
class=""
>
<div
class="c1 c2"
>
<div
class="c3"
>
<div
class="c4 c5"
>
<span
class="c6"
>
test
 
</span>
<span
class="c7"
>
(
1
)
</span>
</div>
</div>
</div>
</div>
</div>
<div
class="c8"
>
<p
aria-live="polite"
aria-relevant="all"
id="live-region-log"
role="log"
/>
<p
aria-live="polite"
aria-relevant="all"
id="live-region-status"
role="status"
/>
<p
aria-live="assertive"
aria-relevant="all"
id="live-region-alert"
role="alert"
/>
</div>
</div>
`;
exports[`<DzLabel /> renders and matches the snapshot 1`] = `
.c8 {
border: 0;
-webkit-clip: rect(0 0 0 0);
clip: rect(0 0 0 0);
height: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
width: 1px;
}
.c4 {
max-width: 22.25rem;
}
.c0 {
-webkit-align-items: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-flex-direction: row;
-ms-flex-direction: row;
flex-direction: row;
-webkit-box-pack: center;
-webkit-justify-content: center;
-ms-flex-pack: center;
justify-content: center;
}
.c3 {
-webkit-align-items: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-flex-direction: column;
-ms-flex-direction: column;
flex-direction: column;
-webkit-box-pack: center;
-webkit-justify-content: center;
-ms-flex-pack: center;
justify-content: center;
}
.c5 {
-webkit-align-items: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-flex-direction: row;
-ms-flex-direction: row;
flex-direction: row;
}
.c6 {
font-weight: 600;
color: #666687;
display: block;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
font-size: 0.75rem;
line-height: 1.33;
}
.c7 {
font-weight: 600;
color: #666687;
font-size: 0.75rem;
line-height: 1.33;
}
.c1 {
background: #ffffff;
color: #8e8ea9;
padding-top: 12px;
padding-right: 16px;
padding-bottom: 12px;
padding-left: 16px;
box-shadow: 0px 1px 4px rgba(33,33,52,0.1);
}
.c2 {
border-radius: 1.625rem;
}
<div>
<div
class="c0"
>
<div
class=""
>
<div
class="c1 c2"
>
<div
class="c3"
>
<div
class="c4 c5"
>
<span
class="c6"
>
dz
 
</span>
<span
class="c7"
>
(
1
)
</span>
</div>
</div>
</div>
</div>
</div>
<div
class="c8"
>
<p
aria-live="polite"
aria-relevant="all"
id="live-region-log"
role="log"
/>
<p
aria-live="polite"
aria-relevant="all"
id="live-region-status"
role="status"
/>
<p
aria-live="assertive"
aria-relevant="all"
id="live-region-alert"
role="alert"
/>
</div>
</div>
`;

View File

@ -8,7 +8,7 @@ import React from 'react';
import { render } from '@testing-library/react';
import { ThemeProvider, lightTheme } from '@strapi/design-system';
import { IntlProvider } from 'react-intl';
import AddComponentButton from '../index';
import AddComponentButton from '../AddComponentButton';
describe('<AddComponentButton />', () => {
it('renders and matches the snapshot', () => {

View File

@ -10,7 +10,7 @@ import { ThemeProvider, lightTheme, Tooltip } from '@strapi/design-system';
import Earth from '@strapi/icons/Earth';
import { IntlProvider } from 'react-intl';
import styled from 'styled-components';
import DzLabel from '../index';
import DynamicZoneLabel from '../DynamicZoneLabel';
const Button = styled.button`
border: none;
@ -36,12 +36,12 @@ const LabelAction = () => {
);
};
describe('<DzLabel />', () => {
describe('DynamicZoneLabel', () => {
it('renders and matches the snapshot', () => {
const { container } = render(
<ThemeProvider theme={lightTheme}>
<IntlProvider locale="en" messages={{}} defaultLocale="en">
<DzLabel label="dz" name="test" numberOfComponents={1} />
<DynamicZoneLabel label="dz" name="test" numberOfComponents={1} />
</IntlProvider>
</ThemeProvider>
);
@ -53,7 +53,7 @@ describe('<DzLabel />', () => {
const { container } = render(
<ThemeProvider theme={lightTheme}>
<IntlProvider locale="en" messages={{}} defaultLocale="en">
<DzLabel name="test" numberOfComponents={1} />
<DynamicZoneLabel name="test" numberOfComponents={1} />
</IntlProvider>
</ThemeProvider>
);
@ -65,7 +65,12 @@ describe('<DzLabel />', () => {
const { container } = render(
<ThemeProvider theme={lightTheme}>
<IntlProvider locale="en" messages={{}} defaultLocale="en">
<DzLabel label="dz" name="test" numberOfComponents={1} labelAction={<LabelAction />} />
<DynamicZoneLabel
label="dz"
name="test"
numberOfComponents={1}
labelAction={<LabelAction />}
/>
</IntlProvider>
</ThemeProvider>
);

View File

@ -1,25 +1,23 @@
import React, { memo, useCallback, useMemo, useState, useEffect } from 'react';
import React, { memo, useMemo, useState } from 'react';
import get from 'lodash/get';
import isEqual from 'react-fast-compare';
import PropTypes from 'prop-types';
import { Stack } from '@strapi/design-system/Stack';
import { Box } from '@strapi/design-system/Box';
import { NotAllowedInput, useNotification } from '@strapi/helper-plugin';
import { getTrad } from '../../utils';
import connect from './utils/connect';
import select from './utils/select';
import DynamicZoneComponent from './components/Component';
import AddComponentButton from './components/AddComponentButton';
import DzLabel from './components/DzLabel';
import Component from './components/Component';
import DynamicZoneLabel from './components/DynamicZoneLabel';
import ComponentPicker from './components/ComponentPicker';
import { useContentTypeLayout } from '../../hooks';
/* eslint-disable react/no-array-index-key */
const createCollapses = (arrayLength) =>
Array.from({ length: arrayLength }).map(() => ({ isOpen: false }));
const DynamicZone = ({
name,
// Passed with the select function
@ -36,39 +34,16 @@ const DynamicZone = ({
fieldSchema,
metadatas,
}) => {
const [addComponentIsOpen, setAddComponentIsOpen] = useState(false);
const toggleNotification = useNotification();
const [isOpen, setIsOpen] = useState(false);
const [shouldOpenAddedComponent, setShouldOpenAddedComponent] = useState(false);
const { getComponentLayout, components } = useContentTypeLayout();
const dynamicDisplayedComponentsLength = dynamicDisplayedComponents.length;
const intlDescription = metadatas.description
? { id: metadatas.description, defaultMessage: metadatas.description }
: null;
const [componentCollapses, setComponentsCollapses] = useState(
createCollapses(dynamicDisplayedComponentsLength)
);
useEffect(() => {
setComponentsCollapses(createCollapses(dynamicDisplayedComponentsLength));
}, [dynamicDisplayedComponentsLength]);
useEffect(() => {
if (shouldOpenAddedComponent) {
setComponentsCollapses((prev) =>
prev.map((collapse, index) => {
if (index === prev.length - 1) {
return { ...collapse, isOpen: true };
}
return collapse;
})
);
setShouldOpenAddedComponent(false);
}
}, [shouldOpenAddedComponent]);
// We cannot use the default props here
const { max = Infinity, min = -Infinity } = fieldSchema;
const dynamicZoneErrors = useMemo(() => {
@ -79,8 +54,6 @@ const DynamicZone = ({
.map((key) => formErrors[key]);
}, [formErrors, name]);
const dynamicZoneAvailableComponents = useMemo(() => fieldSchema.components || [], [fieldSchema]);
const missingComponentNumber = min - dynamicDisplayedComponentsLength;
const hasError = dynamicZoneErrors.length > 0;
@ -90,21 +63,17 @@ const DynamicZone = ({
const hasMaxError =
hasError && get(dynamicZoneErrors, [0, 'id'], '') === 'components.Input.error.validation.max';
const handleAddComponent = useCallback(
(componentUid) => {
setIsOpen(false);
const handleAddComponent = (componentUid) => {
setAddComponentIsOpen(false);
const componentLayoutData = getComponentLayout(componentUid);
const componentLayoutData = getComponentLayout(componentUid);
addComponentToDynamicZone(name, componentLayoutData, components, hasError);
setShouldOpenAddedComponent(true);
},
[addComponentToDynamicZone, hasError, name, components, getComponentLayout]
);
addComponentToDynamicZone(name, componentLayoutData, components, hasError);
};
const handleClickOpenPicker = () => {
if (dynamicDisplayedComponentsLength < max) {
setIsOpen((prev) => !prev);
setAddComponentIsOpen((prev) => !prev);
} else {
toggleNotification({
type: 'info',
@ -113,68 +82,19 @@ const DynamicZone = ({
}
};
const handleToggleComponent = (indexToToggle) => {
setComponentsCollapses((prev) =>
prev.map(({ isOpen }, index) => {
if (index === indexToToggle) {
return { isOpen: !isOpen };
}
return { isOpen };
})
);
const handleMoveComponentDown = (name, componentIndex) => () => {
moveComponentDown(name, componentIndex);
};
const handleMoveComponentDown = (name, currentIndex) => {
moveComponentDown(name, currentIndex);
setComponentsCollapses((prev) => {
return prev.map(({ isOpen }, index, refArray) => {
if (index === currentIndex + 1) {
return { isOpen: refArray[currentIndex].isOpen };
}
if (index === currentIndex) {
return { isOpen: refArray[index + 1].isOpen };
}
return { isOpen };
});
});
const handleMoveComponentUp = (name, componentIndex) => () => {
moveComponentUp(name, componentIndex);
};
const handleMoveComponentUp = (name, currentIndex) => {
moveComponentUp(name, currentIndex);
setComponentsCollapses((prev) => {
return prev.map(({ isOpen }, index, refArray) => {
if (index === currentIndex - 1) {
return { isOpen: refArray[currentIndex].isOpen };
}
if (index === currentIndex) {
return { isOpen: refArray[index - 1].isOpen };
}
return { isOpen };
});
});
};
const handleRemoveComponent = (name, currentIndex) => {
const handleRemoveComponent = (name, currentIndex) => () => {
removeComponentFromDynamicZone(name, currentIndex);
};
if (!isFieldAllowed && isCreatingEntry) {
return (
<NotAllowedInput
description={intlDescription}
intlLabel={{ id: metadatas.label, defaultMessage: metadatas.label }}
labelAction={labelAction}
name={name}
/>
);
}
if (!isFieldAllowed && !isFieldReadable && !isCreatingEntry) {
if (!isFieldAllowed && (isCreatingEntry || (!isFieldReadable && !isCreatingEntry))) {
return (
<NotAllowedInput
description={intlDescription}
@ -189,7 +109,7 @@ const DynamicZone = ({
<Stack spacing={6}>
{dynamicDisplayedComponentsLength > 0 && (
<Box>
<DzLabel
<DynamicZoneLabel
intlDescription={intlDescription}
label={metadatas.label}
labelAction={labelAction}
@ -198,26 +118,21 @@ const DynamicZone = ({
required={fieldSchema.required || false}
/>
{dynamicDisplayedComponents.map((componentUid, index) => {
const showDownIcon =
isFieldAllowed &&
dynamicDisplayedComponentsLength > 0 &&
index < dynamicDisplayedComponentsLength - 1;
const showUpIcon = isFieldAllowed && dynamicDisplayedComponentsLength > 0 && index > 0;
const isOpen = componentCollapses[index]?.isOpen || false;
const showDownIcon = isFieldAllowed && index < dynamicDisplayedComponentsLength - 1;
const showUpIcon = isFieldAllowed && index > 0;
return (
<Component
<DynamicZoneComponent
componentUid={componentUid}
formErrors={formErrors}
// eslint-disable-next-line react/no-array-index-key
key={index}
index={index}
isOpen={isOpen}
isFieldAllowed={isFieldAllowed}
moveComponentDown={handleMoveComponentDown}
moveComponentUp={handleMoveComponentUp}
onToggle={handleToggleComponent}
onMoveComponentDownClick={handleMoveComponentDown(name, index)}
onMoveComponentUpClick={handleMoveComponentUp(name, index)}
name={name}
removeComponentFromDynamicZone={handleRemoveComponent}
onRemoveComponentClick={handleRemoveComponent(name, index)}
showDownIcon={showDownIcon}
showUpIcon={showUpIcon}
/>
@ -233,13 +148,13 @@ const DynamicZone = ({
isDisabled={!isFieldAllowed}
label={metadatas.label}
missingComponentNumber={missingComponentNumber}
isOpen={isOpen}
isOpen={addComponentIsOpen}
name={name}
onClick={handleClickOpenPicker}
/>
<ComponentPicker
isOpen={isOpen}
components={dynamicZoneAvailableComponents}
isOpen={addComponentIsOpen}
components={fieldSchema.components ?? []}
onClickAddComponent={handleAddComponent}
/>
</Stack>