Files
payload/src/admin/components/forms/DraggableSection/index.js

174 lines
5.1 KiB
JavaScript

import React, { useState } from 'react';
import PropTypes from 'prop-types';
import AnimateHeight from 'react-animate-height';
import { Draggable } from 'react-beautiful-dnd';
import ActionPanel from './ActionPanel';
import SectionTitle from './SectionTitle';
import PositionPanel from './PositionPanel';
import Button from '../../elements/Button';
import { NegativeFieldGutterProvider } from '../FieldTypeGutter/context';
import FieldTypeGutter from '../FieldTypeGutter';
import RenderFields from '../RenderFields';
import './index.scss';
const baseClass = 'draggable-section';
const DraggableSection = (props) => {
const {
moveRow,
addRow,
removeRow,
rowIndex,
rowCount,
parentPath,
fieldSchema,
label,
blockType,
fieldTypes,
toggleRowCollapse,
id,
positionPanelVerticalAlignment,
actionPanelVerticalAlignment,
permissions,
isOpen,
readOnly,
} = props;
const [isHovered, setIsHovered] = useState(false);
const classes = [
baseClass,
isOpen ? 'is-open' : 'is-closed',
isHovered && 'is-hovered',
].filter(Boolean).join(' ');
return (
<Draggable
draggableId={id}
index={rowIndex}
isDropDisabled={readOnly}
>
{(providedDrag) => (
<div
ref={providedDrag.innerRef}
className={classes}
onMouseLeave={() => setIsHovered(false)}
onMouseOver={() => setIsHovered(true)}
onFocus={() => setIsHovered(true)}
{...providedDrag.draggableProps}
>
<div className={`${baseClass}__content-wrapper`}>
<FieldTypeGutter
variant="left"
dragHandleProps={providedDrag.dragHandleProps}
>
<PositionPanel
moveRow={moveRow}
rowCount={rowCount}
positionIndex={rowIndex}
verticalAlignment={positionPanelVerticalAlignment}
/>
</FieldTypeGutter>
<div className={`${baseClass}__render-fields-wrapper`}>
{blockType === 'blocks' && (
<div className={`${baseClass}__section-header`}>
<SectionTitle
label={label}
path={`${parentPath}.${rowIndex}.blockName`}
readOnly={readOnly}
/>
<Button
icon="chevron"
onClick={toggleRowCollapse}
buttonStyle="icon-label"
className={`toggle-collapse toggle-collapse--is-${isOpen ? 'open' : 'closed'}`}
round
/>
</div>
)}
<AnimateHeight
height={isOpen ? 'auto' : 0}
duration={0}
>
<NegativeFieldGutterProvider allow={false}>
<RenderFields
readOnly={readOnly}
fieldTypes={fieldTypes}
key={rowIndex}
permissions={permissions}
fieldSchema={fieldSchema.map((field) => ({
...field,
path: `${parentPath}.${rowIndex}${field.name ? `.${field.name}` : ''}`,
}))}
/>
</NegativeFieldGutterProvider>
</AnimateHeight>
</div>
<FieldTypeGutter
variant="right"
className="actions"
dragHandleProps={providedDrag.dragHandleProps}
>
{!readOnly && (
<ActionPanel
rowIndex={rowIndex}
addRow={addRow}
removeRow={removeRow}
label={label}
verticalAlignment={actionPanelVerticalAlignment}
isHovered={isHovered}
{...props}
/>
)}
</FieldTypeGutter>
</div>
</div>
)}
</Draggable>
);
};
DraggableSection.defaultProps = {
toggleRowCollapse: undefined,
rowCount: null,
initialData: undefined,
label: '',
blockType: '',
isOpen: true,
positionPanelVerticalAlignment: 'sticky',
actionPanelVerticalAlignment: 'sticky',
permissions: {},
readOnly: false,
};
DraggableSection.propTypes = {
moveRow: PropTypes.func.isRequired,
addRow: PropTypes.func.isRequired,
removeRow: PropTypes.func.isRequired,
toggleRowCollapse: PropTypes.func,
rowIndex: PropTypes.number.isRequired,
parentPath: PropTypes.string.isRequired,
label: PropTypes.string,
fieldSchema: PropTypes.arrayOf(PropTypes.shape({})).isRequired,
rowCount: PropTypes.number,
initialData: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.shape({})]),
isOpen: PropTypes.bool,
blockType: PropTypes.string,
fieldTypes: PropTypes.shape({}).isRequired,
id: PropTypes.string.isRequired,
positionPanelVerticalAlignment: PropTypes.oneOf(['top', 'center', 'sticky']),
actionPanelVerticalAlignment: PropTypes.oneOf(['top', 'center', 'sticky']),
permissions: PropTypes.shape({}),
readOnly: PropTypes.bool,
};
export default DraggableSection;