dnd draggable card

This commit is contained in:
ronronscelestes 2021-10-15 14:22:08 +02:00
parent ba9eb03f70
commit 8eb0fcc8fb
4 changed files with 82 additions and 201 deletions

View File

@ -1,6 +1,7 @@
import React, { useRef } from 'react';
import styled from 'styled-components';
import PropTypes from 'prop-types';
import { useDrag, useDrop } from 'react-dnd';
import { useIntl } from 'react-intl';
import { Row } from '@strapi/parts/Row';
import { Box } from '@strapi/parts/Box';
@ -9,7 +10,7 @@ import { Stack } from '@strapi/parts/Stack';
import EditIcon from '@strapi/icons/EditIcon';
import CloseAlertIcon from '@strapi/icons/CloseAlertIcon';
import Drag from '@strapi/icons/Drag';
import { getTrad } from '../../../utils';
import { getTrad, ItemTypes } from '../../../utils';
const ActionButton = styled.button`
display: flex;
@ -36,6 +37,10 @@ const FieldContainer = styled(Row)`
max-height: ${32 / 16}rem;
cursor: pointer;
// Solution to remove borders on drag preview
transform: translate(0, 0);
opacity: ${({ isDragging }) => (isDragging ? 0 : 1)};
svg {
width: ${10 / 16}rem;
height: ${10 / 16}rem;
@ -71,8 +76,16 @@ const FieldWrapper = styled(Box)`
}
`;
const DraggableCard = ({ name, labelField, onRemoveField, onClickEditField }) => {
const DraggableCard = ({
index,
labelField,
onClickEditField,
onMoveField,
onRemoveField,
name,
}) => {
const { formatMessage } = useIntl();
const ref = useRef(null);
const editButtonRef = useRef();
const cardTitle = labelField || name;
const cardEllipsisTitle = cardTitle.length > 20 ? `${cardTitle.substring(0, 20)}...` : cardTitle;
@ -83,6 +96,39 @@ const DraggableCard = ({ name, labelField, onRemoveField, onClickEditField }) =>
}
};
const [, drop] = useDrop({
accept: ItemTypes.FIELD,
hover(item) {
if (!ref.current) {
return;
}
const dragIndex = item.index;
const hoverIndex = index;
// Don't replace items with themselves
if (dragIndex === hoverIndex) {
return;
}
console.log('dragged', dragIndex, 'hovered', hoverIndex);
onMoveField(dragIndex, hoverIndex);
item.index = hoverIndex;
},
});
const [{ isDragging }, drag, preview] = useDrag(() => ({
type: ItemTypes.FIELD,
item: () => {
return { name, index };
},
collect: monitor => ({
isDragging: monitor.isDragging(),
}),
}));
drag(drop(ref));
return (
<FieldWrapper>
<FieldContainer
@ -91,6 +137,8 @@ const DraggableCard = ({ name, labelField, onRemoveField, onClickEditField }) =>
hasRadius
justifyContent="space-between"
onClick={handleClickEditRow}
isDragging={isDragging}
ref={preview}
>
<Stack horizontal size={3}>
<DragButton
@ -101,6 +149,8 @@ const DraggableCard = ({ name, labelField, onRemoveField, onClickEditField }) =>
},
{ item: name }
)}
onClick={e => e.stopPropagation()}
ref={ref}
type="button"
>
<Drag />
@ -150,8 +200,10 @@ DraggableCard.defaultProps = {
};
DraggableCard.propTypes = {
index: PropTypes.number.isRequired,
labelField: PropTypes.string,
onClickEditField: PropTypes.func.isRequired,
onMoveField: PropTypes.func.isRequired,
onRemoveField: PropTypes.func.isRequired,
name: PropTypes.string.isRequired,
};

View File

@ -29,8 +29,9 @@ const View = ({
listRemainingFields,
displayedFields,
onAddField,
onRemoveField,
onClickEditField,
onMoveField,
onRemoveField,
metadatas,
}) => {
const { formatMessage } = useIntl();
@ -58,11 +59,13 @@ const View = ({
<Stack horizontal size={3}>
{displayedFields.map((field, index) => (
<DraggableCard
onRemoveField={e => onRemoveField(e, index)}
onClickEditField={onClickEditField}
key={field}
name={field}
index={index}
labelField={metadatas[field].list.label || ''}
name={field}
onMoveField={onMoveField}
onClickEditField={onClickEditField}
onRemoveField={e => onRemoveField(e, index)}
/>
))}
</Stack>
@ -94,6 +97,7 @@ View.propTypes = {
displayedFields: PropTypes.array.isRequired,
onAddField: PropTypes.func.isRequired,
onClickEditField: PropTypes.func.isRequired,
onMoveField: PropTypes.func.isRequired,
onRemoveField: PropTypes.func.isRequired,
listRemainingFields: PropTypes.array.isRequired,
metadatas: PropTypes.objectOf(

View File

@ -177,68 +177,13 @@ const ListSettingsView = ({ layout, slug }) => {
return acc;
}, []);
// const handleClickEditLabel = labelToEdit => {
// dispatch({
// type: 'SET_LABEL_TO_EDIT',
// labelToEdit,
// });
// toggleModalForm();
// };
// const handleClosed = () => {
// dispatch({
// type: 'UNSET_LABEL_TO_EDIT',
// });
// };
// const move = (originalIndex, atIndex) => {
// dispatch({
// type: 'MOVE_FIELD',
// originalIndex,
// atIndex,
// });
// };
// const [, drop] = useDrop({ accept: ItemTypes.FIELD });
// const renderForm = () => {
// const type = get(attributes, [labelToEdit, 'type'], 'text');
// const relationType = get(attributes, [labelToEdit, 'relationType']);
// let shouldDisplaySortToggle = !['media', 'relation'].includes(type);
// const label = formatMessage({ id: getTrad('form.Input.label') });
// const description = formatMessage({ id: getTrad('form.Input.label.inputDescription') });
// if (['oneWay', 'oneToOne', 'manyToOne'].includes(relationType)) {
// shouldDisplaySortToggle = true;
// }
// return (
// <>
// <div className="col-6" style={{ marginBottom: 4 }}>
// <Input
// description={description}
// label={label}
// type="text"
// name="label"
// onBlur={() => {}}
// value={get(labelForm, 'label', '')}
// onChange={handleChangeEditLabel}
// />
// </div>
// {shouldDisplaySortToggle && (
// <div className="col-6" style={{ marginBottom: 4 }}>
// <Input
// label={formatMessage({ id: getTrad('form.Input.sort.field') })}
// type="bool"
// name="sortable"
// value={get(labelForm, 'sortable', false)}
// onChange={handleChangeEditLabel}
// />
// </div>
// )}
// </>
// );
// };
const move = (originalIndex, atIndex) => {
dispatch({
type: 'MOVE_FIELD',
originalIndex,
atIndex,
});
};
return (
<Layout>
@ -294,8 +239,9 @@ const ListSettingsView = ({ layout, slug }) => {
listRemainingFields={listRemainingFields}
displayedFields={displayedFields}
onAddField={handleAddField}
onRemoveField={handleRemoveField}
onClickEditField={handleClickEditField}
onMoveField={move}
onRemoveField={handleRemoveField}
metadatas={modifiedData.metadatas}
/>
</Box>
@ -326,123 +272,6 @@ const ListSettingsView = ({ layout, slug }) => {
</form>
</Main>
</Layout>
// <LayoutDndProvider
// isDraggingSibling={isDraggingSibling}
// setIsDraggingSibling={setIsDraggingSibling}
// >
// <SettingsViewWrapper
// displayedFields={displayedFields}
// inputs={forms}
// isLoading={false}
// initialData={initialData}
// modifiedData={modifiedData}
// onChange={handleChange}
// onConfirmReset={() => {
// dispatch({
// type: 'ON_RESET',
// });
// }}
// onConfirmSubmit={handleConfirm}
// onModalConfirmClosed={refetchData}
// name={getName}
// >
// <DragWrapper>
// <div className="row">
// <div className="col-12">
// <SortWrapper
// ref={drop}
// style={{
// display: 'flex',
// width: '100%',
// }}
// >
// {displayedFields.map((item, index) => {
// const label = get(modifiedData, ['metadatas', item, 'list', 'label'], '');
// return (
// <Label
// count={displayedFields.length}
// key={item}
// index={index}
// isDraggingSibling={isDraggingSibling}
// label={label}
// move={move}
// name={item}
// onClick={handleClickEditLabel}
// onRemove={e => {
// e.stopPropagation();
// if (displayedFields.length === 1) {
// toggleNotification({
// type: 'info',
// message: { id: getTrad('notification.info.minimumFields') },
// });
// } else {
// dispatch({
// type: 'REMOVE_FIELD',
// index,
// });
// }
// }}
// selectedItem={labelToEdit}
// setIsDraggingSibling={setIsDraggingSibling}
// />
// );
// })}
// </SortWrapper>
// </div>
// </div>
// <DropdownButton
// isOpen={isOpen}
// toggle={() => {
// if (listRemainingFields.length > 0) {
// setIsOpen(prevState => !prevState);
// }
// }}
// direction="down"
// style={{
// position: 'absolute',
// top: 11,
// right: 10,
// }}
// >
// <Toggle disabled={listRemainingFields.length === 0} />
// <MenuDropdown>
// {listRemainingFields.map(item => (
// <DropdownItem
// key={item}
// onClick={() => {
// dispatch({
// type: 'ADD_FIELD',
// item,
// });
// }}
// >
// {item}
// </DropdownItem>
// ))}
// </MenuDropdown>
// </DropdownButton>
// </DragWrapper>
// </SettingsViewWrapper>
// <PopupForm
// headerId={getTrad('containers.ListSettingsView.modal-form.edit-label')}
// isOpen={isModalFormOpen}
// onClosed={handleClosed}
// onSubmit={e => {
// e.preventDefault();
// toggleModalForm();
// dispatch({
// type: 'SUBMIT_LABEL_FORM',
// });
// }}
// onToggle={toggleModalForm}
// renderForm={renderForm}
// subHeaderContent={labelToEdit}
// type={get(attributes, [labelToEdit, 'type'], 'text')}
// />
// </LayoutDndProvider>
);
};

View File

@ -1,7 +1,7 @@
import produce from 'immer'; // current
import set from 'lodash/set';
import get from 'lodash/get';
// import { arrayMoveItem } from '../../utils';
import { arrayMoveItem } from '../../utils';
const initialState = {
fieldForm: {},
@ -20,16 +20,16 @@ const reducer = (state = initialState, action) =>
set(draftState, layoutFieldListPath, [action.item, ...layoutFieldList]);
break;
}
// case 'MOVE_FIELD': {
// const layoutFieldList = get(state, layoutFieldListPath, []);
// const { originalIndex, atIndex } = action;
// set(
// draftState,
// layoutFieldListPath,
// arrayMoveItem(layoutFieldList, originalIndex, atIndex)
// );
// break;
// }
case 'MOVE_FIELD': {
const layoutFieldList = get(state, layoutFieldListPath, []);
const { originalIndex, atIndex } = action;
set(
draftState,
layoutFieldListPath,
arrayMoveItem(layoutFieldList, originalIndex, atIndex)
);
break;
}
case 'ON_CHANGE': {
set(draftState, ['modifiedData', ...action.keys.split('.')], action.value);
break;
@ -38,10 +38,6 @@ const reducer = (state = initialState, action) =>
set(draftState, ['fieldForm', action.name], action.value);
break;
}
// case 'ON_RESET': {
// draftState.modifiedData = state.initialData;
// break;
// }
case 'REMOVE_FIELD': {
const layoutFieldList = get(state, layoutFieldListPath, []);
set(