mirror of
https://github.com/strapi/strapi.git
synced 2025-12-28 15:44:59 +00:00
dnd draggable card
This commit is contained in:
parent
ba9eb03f70
commit
8eb0fcc8fb
@ -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,
|
||||
};
|
||||
|
||||
@ -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(
|
||||
|
||||
@ -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>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@ -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(
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user