Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { forwardRef, useState } from 'react';
import React, {forwardRef, useCallback, useEffect, useState} from 'react';
import PropTypes from 'prop-types';
import { isEmpty } from 'lodash';
import { FormattedMessage } from 'react-intl';
Expand All @@ -15,6 +15,9 @@ import RemoveWrapper from './RemoveWrapper';
import SubWrapper from './SubWrapper';
import Wrapper from './Wrapper';
import Close from './Close';
import ResizeWrapper from "./ResizeWrapper";
import useResize from "./utils/useResize";
import {OVER_EDIT, OVER_GRAB, OVER_REMOVE, OVER_RESIZE} from "./constants";

/* eslint-disable */
const DraggedField = forwardRef(
Expand All @@ -26,80 +29,99 @@ const DraggedField = forwardRef(
componentUid,
isDragging,
isHidden,
isOverDynamicZone,
isSub,
isResizeable,
label,
name,
onClick,
onRemove,
onResize,
selectedItem,
size,
style,
type,
withLongerHeight,
},
ref
) => {
const { isDraggingSibling } = useLayoutDnd();
const [isOverRemove, setIsOverRemove] = useState(false);
const [isOverEditBlock, setIsOverEditBlock] = useState(false);

const [isOver, setIsOver] = useState(null);
const [columnWidth, setColumnWidth] = useState(0);

const opacity = isDragging ? 0.2 : 1;
const isSelected = selectedItem === name;
const showEditBlockOverState = isOverEditBlock && !isOverDynamicZone;
const displayedLabel = isEmpty(label) ? name : label;

const [triggerRef, resizedRef, width, , isResizing, initWidth] = useResize(2 * columnWidth, 12 * columnWidth);

const handleOnResize = useCallback((width) => {
const newSize = Math.ceil((width / columnWidth));

if (newSize > 1 && newSize <= 12 && size !== newSize) {
onResize((newSize - size));
}
}, [columnWidth, onResize, size]);

useEffect(() => {
// Calculate column width when resize starts
if (initWidth) {
setColumnWidth(initWidth / size);
}
}, [initWidth]);

useEffect(() => {
if (!onResize || !width) {
return;
}
handleOnResize(width);
}, [width]);

return (
<Wrapper
count={count}
onDrag={() => setIsOverEditBlock(false)}
isSelected={isSelected}
isSub={isSub}
isOverEditBlock={showEditBlockOverState}
isOverRemove={isOverRemove}
onDrag={() => setIsOver(null)}
style={style}
isResizing={isResizing}
withLongerHeight={withLongerHeight}
>
{!isHidden && (
<SubWrapper
className="sub_wrapper"
isSelected={isSelected}
isOverEditBlock={isOverEditBlock}
isOverRemove={isOverRemove}
onMouseEnter={() => {
if (!isSub && !isDraggingSibling) {
setIsOverEditBlock(true);
}
}}
onMouseLeave={() => {
setIsOverEditBlock(false);
}}
onClick={() => {
onClick(name);
}}
isSub={isSub}
isOver={isOver}
style={{ opacity }}
ref={resizedRef}
withLongerHeight={withLongerHeight}
>
<GrabWrapper
className="grab"
isSelected={isSelected}
isOverEditBlock={showEditBlockOverState}
isOverRemove={isOverRemove}
ref={ref}
onClick={e => {
e.stopPropagation();
e.preventDefault();
}}
>
{withLongerHeight ? (
<GrabLarge style={{ marginRight: 10, cursor: 'move' }} />
) : (
<Grab style={{ marginRight: 10, cursor: 'move' }} />
)}
</GrabWrapper>
{ !isSub &&
<GrabWrapper
className="grab"
isSelected={isSelected}
isOver={isOver}
ref={ref}
onMouseEnter={() => setIsOver(OVER_GRAB)}
onMouseLeave={() => setIsOver(null)}
>
{ withLongerHeight ? <GrabLarge /> : <Grab /> }
</GrabWrapper>
}
<NameWrapper
className="name"
isSelected={isSelected}
isOverEditBlock={showEditBlockOverState}
isOverRemove={isOverRemove}
isOver={isOver}
onClick={() => {
onClick(name);
}}
onMouseEnter={() => {
if (!isSub && !isDraggingSibling) {
setIsOver(OVER_EDIT);
}
}}
onMouseLeave={() => {
setIsOver(null);
}}
>
{children ? (
<>
Expand All @@ -110,25 +132,30 @@ const DraggedField = forwardRef(
<span>{displayedLabel}</span>
)}
</NameWrapper>
<RemoveWrapper
className="remove"
isSelected={isSelected}
isOverEditBlock={showEditBlockOverState}
isOverRemove={isOverRemove}
onClick={onRemove}
onMouseEnter={() => {
if (!isSub) {
setIsOverRemove(true);
}
}}
onMouseLeave={() => setIsOverRemove(false)}
>
{isOverRemove && !isSelected && <Close />}
{((showEditBlockOverState && !isOverRemove) || isSelected) && <Pencil />}
{!showEditBlockOverState && !isOverRemove && !isSelected && (
<Close width="10px" height="10px" />
)}
</RemoveWrapper>
{!isSub &&
<RemoveWrapper
className="remove"
isSelected={isSelected}
isOver={isOver}
onClick={onRemove}
onMouseEnter={() => setIsOver(OVER_REMOVE)}
onMouseLeave={() => setIsOver(null)}
>
{(isOver === OVER_REMOVE && !isSelected) ? <Close/> : <Pencil/>}
</RemoveWrapper>
}
{(!isSub && isResizeable) &&
<ResizeWrapper
className="resize"
isSelected={isSelected}
isOver={isOver}
ref={triggerRef}
onMouseEnter={() => setIsOver(OVER_RESIZE)}
onMouseLeave={() => setIsOver(null)}
>
<FontAwesomeIcon icon="arrows-alt-h" />
</ResizeWrapper>
}
</SubWrapper>
)}
{type === 'component' && (
Expand Down Expand Up @@ -161,12 +188,14 @@ DraggedField.defaultProps = {
componentUid: null,
isDragging: false,
isHidden: false,
isOverDynamicZone: false,
isSub: false,
isResizeable: false,
label: '',
onClick: () => {},
onRemove: () => {},
onResize: null,
selectedItem: '',
size: null,
shouldToggleDraggedFieldOverState: false,
style: {},
withLongerHeight: false,
Expand All @@ -179,13 +208,15 @@ DraggedField.propTypes = {
componentUid: PropTypes.string,
isDragging: PropTypes.bool,
isHidden: PropTypes.bool,
isOverDynamicZone: PropTypes.bool,
isSub: PropTypes.bool,
isResizeable: PropTypes.bool,
label: PropTypes.string,
name: PropTypes.string.isRequired,
onClick: PropTypes.func,
onRemove: PropTypes.func,
onResize: PropTypes.func,
selectedItem: PropTypes.string,
size: PropTypes.number,
style: PropTypes.object,
type: PropTypes.string,
withLongerHeight: PropTypes.bool,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import {OVER_EDIT, OVER_GRAB, OVER_REMOVE, OVER_RESIZE} from "../constants";

const getBackgroundColor = (isOver, isSelected, isSub) => {
if (isOver === OVER_REMOVE) {
return '#ffe9e0';
}
if (isOver === OVER_RESIZE) {
return '#f4fff7';
}
if (isSelected || isOver === OVER_EDIT || isOver === OVER_GRAB) {
return '#e6f0fb';
}
if (isSub) {
return '#ffffff';
}

return '#fafafb';
};

export default getBackgroundColor;
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import {OVER_EDIT, OVER_GRAB, OVER_REMOVE, OVER_RESIZE} from "../constants";

const getBorderColor = (isOver, isSelected) => {
if (isOver === OVER_REMOVE) {
return '#ffa784';
}
if (isOver === OVER_RESIZE) {
return '#bafbae';
}
if (isSelected || isOver === OVER_EDIT || isOver === OVER_GRAB) {
return '#aed4fb';
}

return '#e9eaeb';
};

export default getBorderColor;
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
const getColor = (isOverRemove, isSelected, isOverEditBlock) => {
if (isOverRemove) {
return '#ffa784';
import {OVER_EDIT, OVER_GRAB, OVER_REMOVE, OVER_RESIZE} from "../constants";

const getColor = (isOver, isSelected) => {
if (isOver === OVER_REMOVE) {
return '#f64d0a';
}
if (isOver === OVER_RESIZE) {
return '#34ac64';
}
if (isSelected || isOverEditBlock) {
return '#aed4fb';
if (isSelected || isOver === OVER_EDIT || isOver === OVER_GRAB) {
return '#007eff';
}

return '#e9eaeb';
return '#b4b6ba';
};

export default getColor;
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import {useCallback, useEffect, useRef, useState} from "react";
import PropTypes from 'prop-types';

const useResize = (minWidth, maxWidth) => {
const triggerRef = useRef(null);
const triggerPosRef = useRef(null);
const resizedRef = useRef(null);
const resizedInitWidthRef = useRef(null);
const [width, setWidth] = useState(null);
const [offset, setOffset] = useState(null);

const handleResize = useCallback((e) => {
if (!triggerPosRef.current) return;

e.preventDefault();

const offset = (e.pageX - triggerPosRef.current);
const width = Math.min(Math.max((resizedInitWidthRef.current + offset), minWidth), maxWidth);

setOffset(offset);
setWidth(width);
resizedRef.current.style.width = `${width}px`;
}, [resizedRef, minWidth, maxWidth]);

const stopResize = useCallback(() => {
if (!triggerPosRef.current) return;

triggerPosRef.current = null;
resizedRef.current.style.width = `auto`;
}, []);

const startResize = useCallback((e) => {
triggerPosRef.current = e.pageX;
resizedInitWidthRef.current = resizedRef.current.getBoundingClientRect().width;
}, [resizedRef]);

useEffect(() => {
if (!triggerRef.current) {
return () => {};
}
const trigger = triggerRef.current;

// Remove old listener
trigger.removeEventListener('mousedown', startResize);
document.removeEventListener('mousemove', handleResize);
document.removeEventListener('mouseup', stopResize);
// Add new listener
trigger.addEventListener('mousedown', startResize);
document.addEventListener('mousemove', handleResize);
document.addEventListener('mouseup', stopResize);

return () => {
trigger.removeEventListener('mousedown', startResize);
document.removeEventListener('mousemove', handleResize);
document.removeEventListener('mouseup', stopResize);
}
}, [triggerRef, startResize, handleResize, stopResize]);

return [
triggerRef,
resizedRef,
width,
offset,
!!triggerPosRef.current,
resizedInitWidthRef.current,
]
}

useResize.propTypes = {
minWidth: PropTypes.number,
maxWidth: PropTypes.number,
}

useResize.defaultProps = {
minWidth: 0,
maxWidth: null,
}

export default useResize;
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,8 @@ import { hasPermissions, useUser } from 'strapi-helper-plugin';
import pluginId from '../../pluginId';
import pluginPermissions from '../../permissions';
import DynamicComponentCard from '../DynamicComponentCard';
import Tooltip from './Tooltip';

const DynamicComponent = ({ componentUid, friendlyName, icon, setIsOverDynamicZone }) => {
const [isOver, setIsOver] = useState(false);
const DynamicComponent = ({ componentUid, friendlyName, icon }) => {
const [{ isLoading, canAccess }, setState] = useState({ isLoading: true, canAccess: false });
const { push } = useHistory();
const userPermissions = useUser();
Expand All @@ -31,27 +29,18 @@ const DynamicComponent = ({ componentUid, friendlyName, icon, setIsOverDynamicZo
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

const handleMouseEvent = () => {
setIsOverDynamicZone(v => !v);
setIsOver(v => !v);
};

return (
<DynamicComponentCard
componentUid={componentUid}
friendlyName={friendlyName}
icon={icon}
isOver={isOver}
onClick={() => {
if (!isLoading && canAccess) {
push(`/plugins/${pluginId}/components/${componentUid}/configurations/edit`);
}
}}
onMouseEvent={handleMouseEvent}
tradId="components.DraggableAttr.edit"
>
<Tooltip isOver={isOver}>{componentUid}</Tooltip>
</DynamicComponentCard>
/>
);
};

Expand All @@ -64,7 +53,6 @@ DynamicComponent.propTypes = {
componentUid: PropTypes.string.isRequired,
friendlyName: PropTypes.string,
icon: PropTypes.string,
setIsOverDynamicZone: PropTypes.func.isRequired,
};

export default DynamicComponent;

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ const DraggedFieldWithPreview = forwardRef(
name,
onClickEdit,
onClickRemove,
onResize,
selectedItem,
showLeftCarret,
showRightCarret,
Expand All @@ -44,11 +45,11 @@ const DraggedFieldWithPreview = forwardRef(

const componentData = get(componentLayouts, [componentUid], {});
const componentLayout = get(componentData, ['layouts', 'edit'], []);
const getWrapperWitdh = colNum => `${(1 / 12) * colNum * 100}%`;
const getWrapperWidth = colNum => `${(1 / 12) * colNum * 100}%`;

return (
<div
style={{ width: getWrapperWitdh(size) }}
style={{ width: getWrapperWidth(size) }}
onDrag={() => {
if (isFullSize && !dragStart) {
setDragStart(true);
Expand All @@ -75,6 +76,9 @@ const DraggedFieldWithPreview = forwardRef(
name={name}
onClick={onClickEdit}
onRemove={onClickRemove}
onResize={onResize}
size={size}
isResizeable={type !== 'component' && type !== 'dynamiczone' && !!onResize}
ref={refs.dragRef}
selectedItem={selectedItem}
style={{ display, marginRight: 0, paddingRight: 0 }}
Expand Down Expand Up @@ -111,7 +115,7 @@ const DraggedFieldWithPreview = forwardRef(
<div
key={field.name}
style={{
width: getWrapperWitdh(field.size),
width: getWrapperWidth(field.size),
marginBottom: '6px',
}}
>
Expand Down Expand Up @@ -163,6 +167,7 @@ DraggedFieldWithPreview.defaultProps = {
label: '',
onClickEdit: () => {},
onClickRemove: () => {},
onResize: null,
selectedItem: '',
showLeftCarret: false,
showRightCarret: false,
Expand All @@ -181,6 +186,7 @@ DraggedFieldWithPreview.propTypes = {
name: PropTypes.string.isRequired,
onClickEdit: PropTypes.func,
onClickRemove: PropTypes.func,
onResize: PropTypes.func,
selectedItem: PropTypes.string,
showLeftCarret: PropTypes.bool,
showRightCarret: PropTypes.bool,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,21 @@ import DraggedFieldWithPreview from '../DraggedFieldWithPreview';

import ItemTypes from '../../utils/ItemTypes';

const Item = ({
componentUid,
dynamicZoneComponents,
itemIndex,
moveItem,
moveRow,
name,
removeField,
rowIndex,
size,
type,
}) => {
const Item = (
{
componentUid,
dynamicZoneComponents,
itemIndex,
moveItem,
moveRow,
resizeItem,
name,
removeField,
rowIndex,
size,
type,
}
) => {
const {
goTo,
componentLayouts,
Expand Down Expand Up @@ -217,6 +220,9 @@ const Item = ({
e.stopPropagation();
removeField(rowIndex, itemIndex);
}}
onResize={(offset) => {
resizeItem(rowIndex, itemIndex, offset);
}}
selectedItem={selectedItemName}
showLeftCarret={showLeftCarret}
showRightCarret={showRightCarret}
Expand All @@ -238,6 +244,7 @@ Item.propTypes = {
dynamicZoneComponents: PropTypes.array,
itemIndex: PropTypes.number.isRequired,
moveItem: PropTypes.func.isRequired,
resizeItem: PropTypes.func.isRequired,
moveRow: PropTypes.func.isRequired,
name: PropTypes.string.isRequired,
removeField: PropTypes.func.isRequired,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const FieldsReorder = ({ className }) => {
moveRow,
onAddData,
removeField,
resizeItem,
} = useLayoutDnd();

const getComponent = useCallback(
Expand Down Expand Up @@ -68,6 +69,7 @@ const FieldsReorder = ({ className }) => {
key={name}
moveRow={moveRow}
moveItem={moveItem}
resizeItem={resizeItem}
name={name}
removeField={removeField}
rowIndex={rowIndex}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,15 @@ const EditSettingsView = ({ components, mainLayout, isContentTypeView, slug, upd
});
};

const resizeItem = (rowIndex, index, offset) => {
dispatch({
type: 'RESIZE_ITEM',
index,
rowIndex,
offset,
});
};

const toggleModalForm = () => {
setIsModalFormOpen(prevState => !prevState);
};
Expand Down Expand Up @@ -236,6 +245,7 @@ const EditSettingsView = ({ components, mainLayout, isContentTypeView, slug, upd
metadatas={get(modifiedData, ['metadatas'], {})}
moveItem={moveItem}
moveRow={moveRow}
resizeItem={resizeItem}
onAddData={name => {
dispatch({
type: 'ON_ADD_DATA',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,18 @@ const reducer = (state, action) => {

return state.updateIn(layoutPathEdit, () => fromJS(updatedList));
}
case 'RESIZE_ITEM': {
const newState = state.updateIn([...layoutPathEdit, action.rowIndex, 'rowContent', action.index, 'size'], size => {
if ((action.offset > 0 && size >= 12) || (action.offset < 0 && size <= 1)) {
return size;
}

return size + action.offset;
});
const resizedList = fromJS(formatLayout(newState.getIn(layoutPathEdit).toJS()));

return state.updateIn(layoutPathEdit, () => resizedList);
}
case 'SET_FIELD_TO_EDIT':
return state
.update('metaToEdit', () => action.name)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,20 +84,12 @@ function syncLayouts(configuration, schema) {
hasRelationAttribute(schema, attr)
);

let elementsToReAppend = [];
let cleanEdit = [];
for (let row of edit) {
let newRow = [];

for (let el of row) {
if (!hasEditableAttribute(schema, el.name)) continue;

// if size of the element has changed (type changes)
if (typeToSize(schema.attributes[el.name].type) !== el.size) {
elementsToReAppend.push(el.name);
continue;
}

newRow.push(el);
}

Expand All @@ -106,8 +98,6 @@ function syncLayouts(configuration, schema) {
}
}

cleanEdit = appendToEditLayout(cleanEdit, elementsToReAppend, schema);

const newAttributes = _.difference(
Object.keys(schema.attributes),
Object.keys(configuration.metadatas)
Expand Down