Add relation dnd

Signed-off-by: HichamELBSI <elabbassih@gmail.com>
This commit is contained in:
HichamELBSI 2021-11-15 09:22:49 +01:00
parent 9bd2011f61
commit 6e77d7699e
5 changed files with 112 additions and 16 deletions

View File

@ -55,6 +55,7 @@ const CustomDragLayer = () => {
<div style={layerStyles}>
<div style={getItemStyles(initialOffset, currentOffset, mouseOffset)} className="col-md-2">
{itemType === ItemTypes.FIELD && <CardPreview labelField={item.labelField} />}
{itemType === ItemTypes.EDIT_RELATION && <CardPreview labelField={item.labelField} />}
{itemType === ItemTypes.COMPONENT && (
<RepeatableComponentPreview displayedValue={item.displayedValue} />
)}

View File

@ -11,14 +11,14 @@ import { Flex } from '@strapi/design-system/Flex';
import { VisuallyHidden } from '@strapi/design-system/VisuallyHidden';
import { SimpleMenu, MenuItem } from '@strapi/design-system/SimpleMenu';
import Plus from '@strapi/icons/Plus';
import { getTrad } from '../../../utils';
import { getTrad, ItemTypes } from '../../../utils';
import { useLayoutDnd } from '../../../hooks';
import FieldButton from './FieldButton';
import LinkToCTB from './LinkToCTB';
const DisplayedFields = ({ editLayout, editLayoutRemainingFields, onRemoveField, onAddField }) => {
const { formatMessage } = useIntl();
const { setEditFieldToSelect, attributes, modifiedData } = useLayoutDnd();
const { setEditFieldToSelect, attributes, modifiedData, onMoveField } = useLayoutDnd();
return (
<Stack size={4}>
@ -32,15 +32,14 @@ const DisplayedFields = ({ editLayout, editLayoutRemainingFields, onRemoveField,
})}
</Typography>
</Box>
{/* Since the drag n drop will not be available, this text will be hidden for the moment */}
{/* <Box>
<Box>
<Typography variant="pi" textColor="neutral600">
{formatMessage({
id: 'containers.SettingPage.editSettings.description',
defaultMessage: 'Drag & drop the fields to build the layout',
})}
</Typography>
</Box> */}
</Box>
</div>
<LinkToCTB />
</Flex>
@ -63,6 +62,10 @@ const DisplayedFields = ({ editLayout, editLayoutRemainingFields, onRemoveField,
onEditField={() => setEditFieldToSelect(rowItem.name)}
onDeleteField={() => onRemoveField(row.rowId, index)}
attribute={attribute}
itemType={ItemTypes.EDIT_RELATION}
index={index}
name={rowItem.name}
onMoveField={onMoveField}
>
{attributeLabel || rowItem.name}
</FieldButton>

View File

@ -1,6 +1,9 @@
import React from 'react';
import React, { useRef, useEffect } from 'react';
import styled from 'styled-components';
import PropTypes from 'prop-types';
import { useDrop, useDrag } from 'react-dnd';
import { getEmptyImage } from 'react-dnd-html5-backend';
import { useIntl } from 'react-intl';
import { Box } from '@strapi/design-system/Box';
import { Flex } from '@strapi/design-system/Flex';
import { IconButton } from '@strapi/design-system/IconButton';
@ -8,10 +11,9 @@ import { Typography } from '@strapi/design-system/Typography';
import Drag from '@strapi/icons/Drag';
import Pencil from '@strapi/icons/Pencil';
import Trash from '@strapi/icons/Trash';
import { useIntl } from 'react-intl';
import { getTrad } from '../../../utils';
import ComponentFieldList from './ComponentFieldList';
import DynamicZoneList from './DynamicZoneList';
import getTrad from '../../../utils/getTrad';
const CustomIconButton = styled(IconButton)`
background-color: transparent;
@ -27,10 +29,63 @@ const CustomDragIcon = styled(Drag)`
}
`;
const CustomFlex = styled(Flex)`
opacity: ${({ isDragging }) => (isDragging ? 0 : 1)};
`;
const DragButton = styled(Flex)`
cursor: all-scroll;
border-right: 1px solid ${({ theme }) => theme.colors.neutral200};
`;
const FieldButton = ({ attribute, onEditField, onDeleteField, children }) => {
const FieldButton = ({
attribute,
onEditField,
onDeleteField,
children,
index,
itemType,
name,
onMoveField,
}) => {
const dragButtonRef = useRef();
const [, drop] = useDrop({
accept: itemType,
hover(item) {
if (!dragButtonRef.current) {
return;
}
const dragIndex = item.index;
const hoverIndex = index;
// Don't replace items with themselves
if (dragIndex === hoverIndex) {
return;
}
console.log(hoverIndex);
onMoveField(dragIndex, hoverIndex);
item.index = hoverIndex;
},
});
const [{ isDragging }, drag, dragPreview] = useDrag({
type: itemType,
item: () => {
return { index, labelField: children, name };
},
collect: monitor => ({
isDragging: monitor.isDragging(),
}),
});
useEffect(() => {
dragPreview(getEmptyImage(), { captureDraggingState: true });
}, [dragPreview]);
drag(drop(dragButtonRef));
const { formatMessage } = useIntl();
const getHeight = () => {
const higherFields = ['json', 'text', 'file', 'media', 'component', 'richtext', 'dynamiczone'];
@ -43,17 +98,28 @@ const FieldButton = ({ attribute, onEditField, onDeleteField, children }) => {
};
return (
<Flex
<CustomFlex
width="100%"
borderColor="neutral150"
hasRadius
background="neutral100"
minHeight={getHeight()}
alignItems="stretch"
isDragging={isDragging}
>
<CustomFlex alignItems="center" paddingLeft={3} paddingRight={3}>
<DragButton
as="button"
type="button"
ref={dragButtonRef}
onClick={e => e.stopPropagation()}
alignItems="center"
paddingLeft={3}
paddingRight={3}
// Disable the keyboard navigation since the drag n drop isn't accessible with the keyboard for the moment
tabIndex={-1}
>
<CustomDragIcon />
</CustomFlex>
</DragButton>
<Box overflow="hidden" width="100%">
<Flex paddingLeft={3} alignItems="baseline" justifyContent="space-between">
<Box>
@ -96,7 +162,7 @@ const FieldButton = ({ attribute, onEditField, onDeleteField, children }) => {
)}
{attribute?.type === 'dynamiczone' && <DynamicZoneList components={attribute.components} />}
</Box>
</Flex>
</CustomFlex>
);
};
@ -113,6 +179,10 @@ FieldButton.propTypes = {
onEditField: PropTypes.func.isRequired,
onDeleteField: PropTypes.func.isRequired,
children: PropTypes.string.isRequired,
index: PropTypes.number.isRequired,
name: PropTypes.string.isRequired,
itemType: PropTypes.string.isRequired,
onMoveField: PropTypes.func.isRequired,
};
export default FieldButton;

View File

@ -8,9 +8,9 @@ import { Typography } from '@strapi/design-system/Typography';
import { Stack } from '@strapi/design-system/Stack';
import { SimpleMenu, MenuItem } from '@strapi/design-system/SimpleMenu';
import Plus from '@strapi/icons/Plus';
import { getTrad } from '../../../utils';
import FieldButton from './FieldButton';
import { getTrad, ItemTypes } from '../../../utils';
import { useLayoutDnd } from '../../../hooks';
import FieldButton from './FieldButton';
const RelationalFields = ({
relationsLayout,
@ -19,7 +19,7 @@ const RelationalFields = ({
onAddField,
}) => {
const { formatMessage } = useIntl();
const { setEditFieldToSelect, modifiedData } = useLayoutDnd();
const { setEditFieldToSelect, modifiedData, onMoveRelation } = useLayoutDnd();
return (
<Stack size={4}>
@ -56,6 +56,10 @@ const RelationalFields = ({
onEditField={() => setEditFieldToSelect(relationName)}
onDeleteField={() => onRemoveField(index)}
key={relationName}
index={index}
name={relationName}
onMoveField={onMoveRelation}
itemType={ItemTypes.EDIT_RELATION}
>
{relationLabel || relationName}
</FieldButton>

View File

@ -151,6 +151,22 @@ const EditSettingsView = ({ mainLayout, components, isContentTypeView, slug, upd
submitMutation.mutate(body);
};
const handleMoveRelation = (fromIndex, toIndex) => {
dispatch({
type: 'MOVE_RELATION',
fromIndex,
toIndex,
});
};
const handleMoveField = (fromIndex, toIndex) => {
dispatch({
type: 'MOVE_FIELD',
fromIndex,
toIndex,
});
};
return (
<LayoutDndProvider
isContentTypeView={isContentTypeView}
@ -160,6 +176,8 @@ const EditSettingsView = ({ mainLayout, components, isContentTypeView, slug, upd
componentLayouts={componentLayouts}
selectedField={metaToEdit}
fieldForm={metaForm}
onMoveRelation={handleMoveRelation}
onMoveField={handleMoveField}
setEditFieldToSelect={name => {
dispatch({
type: 'SET_FIELD_TO_EDIT',