+ {/* Root Components */}
}
@@ -62,6 +67,8 @@ const DragDropPanel = (props): JSX.Element => {
+
+ {/* HTML Components */}
}
@@ -93,7 +100,7 @@ const DragDropPanel = (props): JSX.Element => {
-
+
{/* MUI Components */}
{
- {htmlTypesToRender.map((option) => {
- if (option.name === 'MUI') {
- return (
-
- );
- }
+ {muiTypesToRender.map((option) => {
+ return (
+
+ );
})}
-
+
{/* React Router */}
{
-
+
{/* Next.js */}
{state.projectType === 'Next.js' ? (
Next.js
@@ -183,4 +188,3 @@ const DragDropPanel = (props): JSX.Element => {
};
export default DragDropPanel;
-
diff --git a/app/src/components/left/HTMLItem.tsx b/app/src/components/left/HTMLItem.tsx
index 028ab8cd..cbe65eef 100644
--- a/app/src/components/left/HTMLItem.tsx
+++ b/app/src/components/left/HTMLItem.tsx
@@ -12,12 +12,14 @@ import * as Icons from '@mui/icons-material';
import { useDispatch, useSelector } from 'react-redux';
import { addChild } from '../../redux/reducers/slice/appStateSlice';
import { emitEvent } from '../../helperFunctions/socket';
+import { RootState } from '../../redux/store';
const useStyles = makeStyles({
HTMLPanelItem: {
height: 'auto',
width: 'auto',
fontSize: 'small',
+ alignItems: 'center',
display: 'flex',
flexDirection: 'row',
justifyContent: 'space-evenly',
@@ -40,10 +42,8 @@ const HTMLItem: React.FC<{
}> = ({ name, id, icon, handleDelete }) => {
const IconComponent = Icons[icon];
-
const roomCode = useSelector((store: RootState) => store.roomSlice.roomCode); // current roomCode
-
const classes = useStyles();
const [modal, setModal] = useState(null);
const [{ isDragging }, drag] = useDrag({
@@ -113,7 +113,6 @@ const HTMLItem: React.FC<{
);
};
-
const dispatch = useDispatch();
const handleClick = () => {
@@ -140,7 +139,10 @@ const HTMLItem: React.FC<{
{id <= 20 && (
{
@@ -183,4 +185,3 @@ const HTMLItem: React.FC<{
};
export default HTMLItem;
-
diff --git a/app/src/components/left/MUIItem.tsx b/app/src/components/left/MUIItem.tsx
new file mode 100644
index 00000000..b91a59f7
--- /dev/null
+++ b/app/src/components/left/MUIItem.tsx
@@ -0,0 +1,195 @@
+import React, { useState } from 'react';
+import Grid from '@mui/material/Grid';
+import List from '@mui/material/List';
+import ListItem from '@mui/material/ListItem';
+import ListItemText from '@mui/material/ListItemText';
+import makeStyles from '@mui/styles/makeStyles';
+import { useDrag } from 'react-dnd';
+
+import { ItemTypes } from '../../constants/ItemTypes';
+import { RootState } from '../../redux/store';
+import * as Icons from '@mui/icons-material'; // Assuming a collection of MUI icons
+import CodeIcon from '@mui/icons-material/Code'; // Default icon if specific icon not provided
+import { useDispatch, useSelector } from 'react-redux';
+import { addChild } from '../../redux/reducers/slice/appStateSlice';
+import createModal from '../right/createModal'; // Modal creation utility
+import { emitEvent } from '../../helperFunctions/socket'; // Event emission utility
+
+// Define component styles using MUI styling solutions
+const useStyles = makeStyles({
+ MUIPanelItem: {
+ height: 'auto',
+ width: 'auto',
+ fontSize: 'small',
+ display: 'flex',
+ flexDirection: 'row',
+ justifyContent: 'space-evenly',
+ alignItems: 'center',
+ textAlign: 'center',
+ cursor: 'grab'
+ },
+ lightThemeFontColor: {
+ color: '#8F8F8F'
+ },
+ darkThemeFontColor: {
+ color: '#8F8F8F'
+ }
+});
+
+const MUIItem: React.FC<{
+ name: string;
+ id: number;
+ icon: any;
+ handleDelete: (id: number) => void;
+}> = ({ name, id, icon, handleDelete }) => {
+ const IconComponent = Icons[icon];
+
+ const roomCode = useSelector((store: RootState) => store.roomSlice.roomCode); // current roomCode
+
+ // Use drag and drop functionality
+ const classes = useStyles();
+ const [modal, setModal] = useState(null);
+
+ const item = {
+ type: ItemTypes.INSTANCE,
+ newInstance: true,
+ instanceType: 'MUI Component', // MUI Element? - we should carefully consider what we call this
+ name,
+ icon,
+ instanceTypeId: id
+ };
+
+ // console.log('draggable item', item);
+
+ const [{ isDragging }, drag] = useDrag({
+ item,
+ collect: (monitor: any) => ({
+ isDragging: !!monitor.isDragging()
+ })
+ });
+
+ const closeModal = () => setModal(null);
+ const deleteAllInstances = (deleteID: number) => {
+ const children = (
+
+ handleDelete(deleteID)}
+ style={{
+ border: '1px solid #C6C6C6',
+ marginBottom: '2%',
+ marginTop: '5%'
+ }}
+ >
+
+
+
+
+
+
+ );
+ setModal(
+ createModal({
+ closeModal,
+ children,
+ message:
+ 'Deleting this element will delete all instances of this element within the application.\nDo you still wish to proceed?',
+ primBtnLabel: null,
+ primBtnAction: null,
+ secBtnAction: null,
+ secBtnLabel: null,
+ open: true
+ })
+ );
+ };
+
+ const dispatch = useDispatch();
+
+ const handleClick = () => {
+ const childData = {
+ type: 'MUI Component',
+ typeId: id,
+ childId: null,
+ contextParam: {
+ allContext: []
+ }
+ };
+
+ dispatch(addChild(childData));
+ if (roomCode) {
+ // Emit 'addChildAction' event to the server
+ emitEvent('addChildAction', roomCode, childData);
+ }
+ };
+
+ // id over/under 20 logic
+ // html-g{name} - html grid name = item
+ return (
+
+ {id >= 20 && (
+ {
+ handleClick();
+ }}
+ >
+ {typeof IconComponent !== 'undefined' && (
+
+ )}
+ {name}
+
+ )}
+
+ {id < 20 && (
+ {
+ handleClick();
+ }}
+ >
+ {typeof CodeIcon !== 'undefined' && (
+
+ )}
+ {name}
+ deleteAllInstances(id)}
+ >
+ X
+
+
+ )}
+ {modal}
+
+ );
+};
+
+export default MUIItem;
diff --git a/app/src/components/main/Canvas.tsx b/app/src/components/main/Canvas.tsx
index c491dfd3..3936c3d2 100644
--- a/app/src/components/main/Canvas.tsx
+++ b/app/src/components/main/Canvas.tsx
@@ -211,6 +211,7 @@ const Canvas = forwardRef
(({ zoom }, ref) => {
}
// if item dropped is going to be a new instance (i.e. it came from the left panel), then create a new child component
if (item.newInstance && item.instanceType !== 'Component') {
+ console.log('inside not component check', item);
dispatch(
//update state
addChild({
diff --git a/app/src/components/main/DirectChildMUI.tsx b/app/src/components/main/DirectChildMUI.tsx
new file mode 100644
index 00000000..934ef48a
--- /dev/null
+++ b/app/src/components/main/DirectChildMUI.tsx
@@ -0,0 +1,90 @@
+import React from 'react';
+import { ChildElement, MUIType } from '../../interfaces/Interfaces';
+import { useDrag } from 'react-dnd';
+import { ItemTypes } from '../../constants/ItemTypes';
+import { combineStyles } from '../../helperFunctions/combineStyles';
+import globalDefaultStyle from '../../public/styles/globalDefaultStyles';
+import DeleteButton from './DeleteButton';
+import { useDispatch, useSelector } from 'react-redux';
+import { changeFocus } from '../../redux/reducers/slice/appStateSlice';
+import { RootState } from '../../redux/store';
+import { emitEvent } from '../../helperFunctions/socket';
+
+function DirectChildMUI({ childId, name, type, typeId, style }: ChildElement) {
+ const state = useSelector((store: RootState) => store.appState);
+
+ const roomCode = useSelector((store: RootState) => store.roomSlice.roomCode);
+
+ const dispatch = useDispatch();
+
+ // find the MUI element corresponding with this instance of an MUI element
+ // find the current component to render on the canvas
+ const MUIType: MUIType = state.MUITypes.find(
+ (type: MUIType) => type.id === typeId
+ );
+ // hook that allows component to be draggable
+ const [{ isDragging }, drag] = useDrag({
+ // setting item attributes to be referenced when updating state with new instance of dragged item
+ item: {
+ type: ItemTypes.INSTANCE,
+ newInstance: false,
+ childId: childId,
+ instanceType: type,
+ instanceTypeId: typeId
+ },
+ collect: (monitor: any) => ({
+ isDragging: !!monitor.isDragging()
+ })
+ });
+
+ const changeFocusFunction = (componentId: number, childId: number | null) => {
+ dispatch(changeFocus({ componentId, childId }));
+ if (roomCode) {
+ emitEvent('changeFocusAction', roomCode, {
+ componentId: componentId,
+ childId: childId
+ });
+ // console.log('emit focus event from DirectChildMUI');
+ }
+ };
+
+ // onClickHandler is responsible for changing the focused component and child component
+ function onClickHandler(event) {
+ event.stopPropagation();
+ changeFocusFunction(state.canvasFocus.componentId, childId);
+ }
+
+ // combine all styles so that higher priority style specifications overrule lower priority style specifications
+ // priority order is 1) style directly set for this child (style), 2) style of the referenced HTML element, and 3) default styling
+ const interactiveStyle = {
+ border:
+ state.canvasFocus.childId === childId
+ ? '2px solid #0671e3'
+ : '1px solid #31343A'
+ };
+
+ const combinedStyle = combineStyles(
+ combineStyles(combineStyles(globalDefaultStyle, MUIType.style), style),
+ interactiveStyle
+ );
+
+ return (
+
+
+ {MUIType.placeHolderShort}
+
+
+
+ );
+}
+
+export default DirectChildMUI;
diff --git a/app/src/components/main/DirectChildMUINestable.tsx b/app/src/components/main/DirectChildMUINestable.tsx
new file mode 100644
index 00000000..f30848cb
--- /dev/null
+++ b/app/src/components/main/DirectChildMUINestable.tsx
@@ -0,0 +1,240 @@
+import React, { useRef } from 'react';
+import { ChildElement, MUIType } from '../../interfaces/Interfaces';
+import { useDrag, useDrop, DropTargetMonitor } from 'react-dnd';
+import { ItemTypes } from '../../constants/ItemTypes';
+import { combineStyles } from '../../helperFunctions/combineStyles';
+import globalDefaultStyle from '../../public/styles/globalDefaultStyles';
+import renderChildren from '../../helperFunctions/renderChildren';
+import DeleteButton from './DeleteButton';
+import validateNewParent from '../../helperFunctions/changePositionValidation';
+import componentNest from '../../helperFunctions/componentNestValidation';
+import AddRoute from './AddRoute';
+import AddLink from './AddLink';
+import { useDispatch, useSelector } from 'react-redux';
+import { RootState } from '../../redux/store';
+import { emitEvent } from '../../helperFunctions/socket';
+
+import {
+ changeFocus,
+ changePosition,
+ addChild,
+ snapShotAction
+} from '../../redux/reducers/slice/appStateSlice';
+
+function DirectChildMUINestable({
+ childId,
+ type,
+ typeId,
+ style,
+ children,
+ name,
+ attributes
+}: ChildElement): React.JSX.Element {
+ const state = useSelector((store: RootState) => store.appState);
+ const contextParam = useSelector((store: RootState) => store.contextSlice);
+
+ const dispatch = useDispatch();
+ const roomCode = useSelector((store: RootState) => store.roomSlice.roomCode);
+
+ const ref = useRef(null);
+
+ // takes a snapshot of state to be used in UNDO and REDO cases. snapShotFunc is also invoked in Canvas.tsx
+ const snapShotFunc = () => {
+ //makes a deep clone of state
+ const deepCopiedState = JSON.parse(JSON.stringify(state));
+ const focusIndex = state.canvasFocus.componentId - 1;
+ //pushes the last user action on the canvas into the past array of Component
+ dispatch(
+ snapShotAction({
+ focusIndex: focusIndex,
+ deepCopiedState: deepCopiedState
+ })
+ );
+ };
+
+ // find the MUI element corresponding with this instance of an MUI element
+ // find the current component to render on the canvas
+ const MUIType: MUIType = state.MUITypes.find(
+ (type: MUIType) => type.id === typeId
+ );
+
+ // hook that allows component to be draggable
+ const [{ isDragging }, drag] = useDrag({
+ // setting item attributes to be referenced when updating state with new instance of dragged item
+ item: {
+ type: ItemTypes.INSTANCE,
+ newInstance: false,
+ childId: childId,
+ instanceType: type,
+ instanceTypeId: typeId,
+ name: name
+ },
+ canDrag: MUIType.id !== 1000, // dragging not permitted if element is separator
+ collect: (monitor: any) => {
+ return {
+ isDragging: !!monitor.isDragging()
+ };
+ }
+ });
+
+ // both useDrop and useDrag used here to allow canvas components to be both a drop target and drag source
+ const [{ isOver }, drop] = useDrop({
+ accept: ItemTypes.INSTANCE,
+ // triggered on drop
+ drop: (item: any, monitor: DropTargetMonitor) => {
+ const didDrop = monitor.didDrop();
+ // takes a snapshot of state to be used in UNDO and REDO cases
+ snapShotFunc();
+ if (didDrop) {
+ return;
+ }
+ // updates state with new instance
+ // if item dropped is going to be a new instance (i.e. it came from the left panel), then create a new child component
+ if (item.newInstance) {
+ if (
+ (item.instanceType === 'Component' &&
+ componentNest(
+ state.components[item.instanceTypeId - 1].children,
+ childId
+ )) ||
+ item.instanceType !== 'Component'
+ ) {
+ dispatch(
+ addChild({
+ type: item.instanceType,
+ typeId: item.instanceTypeId,
+ childId: childId,
+ contextParam: contextParam
+ })
+ );
+ if (roomCode) {
+ emitEvent('addChildAction', roomCode, {
+ type: item.instanceType,
+ typeId: item.instanceTypeId,
+ childId: childId,
+ contextParam: contextParam
+ });
+
+ // console.log(
+ // 'emit addChildAction event is triggered in DirectChildMUINestable'
+ // );
+ }
+ }
+ }
+ // if item is not a new instance, change position of element dragged inside div so that the div is the new parent
+ else {
+ // check to see if the selected child is trying to nest within itself
+ if (validateNewParent(state, item.childId, childId) === true) {
+ dispatch(
+ changePosition({
+ currentChildId: item.childId,
+ newParentChildId: childId,
+ contextParam: contextParam
+ })
+ );
+ if (roomCode) {
+ emitEvent('changePositionAction', roomCode, {
+ currentChildId: item.childId,
+ newParentChildId: childId,
+ contextParam: contextParam
+ });
+
+ // console.log(
+ // 'emit changePosition event is triggered in DirectChildMUINestable'
+ // );
+ }
+ }
+ }
+ },
+
+ collect: (monitor: any) => {
+ return {
+ isOver: !!monitor.isOver({ shallow: true })
+ };
+ }
+ });
+
+ const changeFocusFunction = (componentId: number, childId: number | null) => {
+ dispatch(changeFocus({ componentId, childId }));
+ if (roomCode) {
+ emitEvent('changeFocusAction', roomCode, {
+ componentId: componentId,
+ childId: childId
+ });
+ // console.log('emit focus event from DirectChildMUINestable');
+ }
+ };
+
+ // onClickHandler is responsible for changing the focused component and child component
+ function onClickHandler(event) {
+ event.stopPropagation();
+ changeFocusFunction(state.canvasFocus.componentId, childId);
+ }
+
+ // combine all styles so that higher priority style specifications overrule lower priority style specifications
+ // priority order is 1) style directly set for this child (style), 2) style of the referenced MUI element, and 3) default styling
+ const defaultNestableStyle = { ...globalDefaultStyle };
+ const interactiveStyle = {
+ border:
+ state.canvasFocus.childId === childId
+ ? '2px solid #0671e3'
+ : '1px solid #31343A'
+ };
+
+ // interactive style to change color when nested element is hovered over
+ if (isOver) defaultNestableStyle['#3c59ba'];
+ defaultNestableStyle['backgroundColor'] = isOver
+ ? '#3c59ba'
+ : defaultNestableStyle['backgroundColor'];
+
+ const combinedStyle = combineStyles(
+ combineStyles(combineStyles(defaultNestableStyle, MUIType.style), style),
+ interactiveStyle
+ );
+
+ drag(drop(ref));
+
+ const routeButton = [];
+ if (typeId === 17) {
+ routeButton.push( );
+ }
+ if (typeId === 19) {
+ routeButton.push(
+
+ );
+ }
+
+ return (
+
+
+ {MUIType.placeHolderShort}
+
+ {attributes && attributes.compLink ? ` ${attributes.compLink}` : ''}
+
+ {routeButton}
+
+
+ {renderChildren(children)}
+
+ );
+}
+
+export default DirectChildMUINestable;
diff --git a/app/src/components/main/SeparatorChild.tsx b/app/src/components/main/SeparatorChild.tsx
index 8d9388ec..f2910ebb 100644
--- a/app/src/components/main/SeparatorChild.tsx
+++ b/app/src/components/main/SeparatorChild.tsx
@@ -1,5 +1,10 @@
import React, { useRef } from 'react';
-import { ChildElement, HTMLType, DragItem } from '../../interfaces/Interfaces';
+import {
+ ChildElement,
+ HTMLType,
+ MUIType,
+ DragItem
+} from '../../interfaces/Interfaces';
import { useDrag, useDrop, DropTargetMonitor } from 'react-dnd';
import { ItemTypes } from '../../constants/ItemTypes';
import { combineStyles } from '../../helperFunctions/combineStyles';
@@ -37,6 +42,9 @@ function SeparatorChild({
(type: HTMLType) => type.id === typeId
);
+ const MUIType: MUIType = state.MUITypes.find(
+ (type: MUIType) => type.id === typeId
+ );
// hook that allows component to be draggable
const [{ isDragging }, drag] = useDrag({
// setting item attributes to be referenced when updating state with new instance of dragged item
@@ -47,7 +55,7 @@ function SeparatorChild({
instanceType: type,
instanceTypeId: typeId
},
- canDrag: HTMLType.id !== 1000, // dragging not permitted if element is separator
+ canDrag: HTMLType.id !== 1000 || MUIType.id !== 1000, // dragging not permitted if element is separator
collect: (monitor: any) => {
return {
isDragging: !!monitor.isDragging()
@@ -144,7 +152,7 @@ function SeparatorChild({
// priority order is 1) style directly set for this child (style), 2) style of the referenced HTML element, and 3) default styling
const defaultNestableStyle = { ...globalDefaultStyle };
const separatorStyle = {
- padding: isOver ? '40px 10px' : '2px 10px',
+ padding: isOver ? '40px 10px' : '2px 10px',
margin: '1px 10px',
transition: 'padding 1s ease-out'
};
diff --git a/app/src/helperFunctions/generateCode.ts b/app/src/helperFunctions/generateCode.ts
index bd9b1e9e..35bbf93e 100644
--- a/app/src/helperFunctions/generateCode.ts
+++ b/app/src/helperFunctions/generateCode.ts
@@ -2,6 +2,7 @@ import {
Component,
ChildElement,
HTMLType,
+ MUIType,
ChildStyle,
StateProp
} from '../interfaces/Interfaces';
@@ -17,6 +18,7 @@ const generateCode = (
rootComponents: number[],
projectType: string,
HTMLTypes: HTMLType[],
+ MUITypes: MUIType[],
tailwind: boolean,
contextParam: any
) => {
@@ -26,6 +28,7 @@ const generateCode = (
rootComponents,
projectType,
HTMLTypes,
+ MUITypes,
tailwind,
contextParam
);
@@ -39,6 +42,7 @@ const generateUnformattedCode = (
rootComponents: number[],
projectType: string,
HTMLTypes: HTMLType[],
+ MUITypes: MUIType[],
tailwind: boolean,
contextParam: any
) => {
@@ -105,6 +109,30 @@ const generateUnformattedCode = (
else if (referencedHTML.tag === 'Link') links = true;
if (referencedHTML.tag === 'Image') images = true;
return child;
+ } else if (child.type === 'MUI Component') {
+ const referencedMUI = MUITypes.find((elem) => elem.id === child.typeId);
+ child['tag'] = referencedMUI.tag;
+ if (
+ referencedMUI.tag === 'button' ||
+ referencedMUI.tag === 'card' ||
+ referencedMUI.tag === 'typography' ||
+ referencedMUI.tag === 'input' ||
+ referencedMUI.tag === 'Link' ||
+ referencedMUI.tag === 'Switch' ||
+ referencedMUI.tag === 'Route'
+ ) {
+ child.children = getEnrichedChildren(child);
+ }
+
+ // when we see a Switch or LinkTo, import React Router
+ if (
+ (referencedMUI.tag === 'Switch' || referencedMUI.tag === 'Route') &&
+ projectType === 'Classic React'
+ )
+ importReactRouter = true;
+ else if (referencedMUI.tag === 'Link') links = true;
+ if (referencedMUI.tag === 'Image') images = true;
+ return child;
} else if (child.type === 'Route Link') {
links = true;
child.name = components.find(
@@ -499,6 +527,15 @@ const generateUnformattedCode = (
if (child.children.length !== 0)
importStr += createEventHandler(child.children);
}
+ if (child.type === 'MUI Component') {
+ if (child.events) {
+ for (const [event, funcName] of Object.entries(child.events)) {
+ importStr += `\tconst ${funcName} = () => {};\n`;
+ }
+ }
+ if (child.children.length !== 0)
+ importStr += createEventHandler(child.children);
+ }
});
return importStr;
diff --git a/app/src/helperFunctions/renderChildren.tsx b/app/src/helperFunctions/renderChildren.tsx
index bbae5960..9a19901a 100644
--- a/app/src/helperFunctions/renderChildren.tsx
+++ b/app/src/helperFunctions/renderChildren.tsx
@@ -3,6 +3,8 @@ import { ChildElement } from '../interfaces/Interfaces';
import DirectChildComponent from '../components/main/DirectChildComponent';
import DirectChildHTML from '../components/main/DirectChildHTML';
import DirectChildHTMLNestable from '../components/main/DirectChildHTMLNestable';
+import DirectChildMUI from '../components/main/DirectChildMUI';
+import DirectChildMUINestable from '../components/main/DirectChildMUINestable';
import SeparatorChild from '../components/main/SeparatorChild';
import RouteLink from '../components/main/RouteLink';
import { useSelector } from 'react-redux';
@@ -17,7 +19,12 @@ const renderChildren = (children: ChildElement[]) => {
return children.map((child: ChildElement, i: number) => {
const { type, style, childId, children, attributes, name } = child;
+ // console.log('state components', state.components);
+ // console.log('state MUI type', state.MUITypes);
let { typeId } = child;
+ // console.log('typeID', typeId);
+ // console.log('name', name);
+ // console.log('child.name', state.components[typeId - 1].name);
if (name === '') child.name = state.components[typeId - 1].name;
// A DirectChildComponent is an instance of a top level component
// This component will render IndirectChild components (div/components rendered inside a child component)
@@ -39,7 +46,8 @@ const renderChildren = (children: ChildElement[]) => {
/>
);
}
- // child is a non-nestable type of HTML element (aka NOT divs, forms, OrderedLists, UnorderedLists, menus)
+ // child is a non-nestable type of HTML element
+ // nestable = false -> input(10), img(12), image(20)
else if (
type === 'HTML Element' &&
typeId !== 11 &&
@@ -119,6 +127,63 @@ const renderChildren = (children: ChildElement[]) => {
passedInProps={[]}
/>
);
+ } else if (type === 'MUI Component' && typeId === 31) {
+ return (
+
+ );
+ }
+ // child is a nestable type of HTML element (divs, forms, OrderedLists, UnorderedLists, menus)
+ else if (
+ type === 'MUI Component' &&
+ (typeId === 21 || typeId === 41 || typeId === 51)
+ ) {
+ return (
+
+ );
+ } else if (type === 'MUI Component' && typeId === 1000) {
+ return (
+
+ );
} else if (type === 'HTML Element' && typeId === 1000) {
return (
{
// if no match is found return false
return;
};
+function createHTMLElement(data) {
+ return {
+ ...data,
+ isHTMLElement: true
+ };
+}
+
// update all ids and typeIds to match one another
const updateAllIds = (comp: Component[] | ChildElement[]) => {
// put components' names and ids into an obj
@@ -272,6 +282,7 @@ const appStateSlice = createSlice({
[...state.rootComponents],
state.projectType,
state.HTMLTypes,
+ state.MUITypes,
state.tailwind,
action.payload.contextParam
);
@@ -280,7 +291,6 @@ const appStateSlice = createSlice({
},
addChild: (state, action) => {
- let parentComponentId: number;
const {
type,
typeId,
@@ -288,60 +298,57 @@ const appStateSlice = createSlice({
}: { type: string; typeId: number; childId: any } = action.payload;
// determine the parent component id
- if (action.payload.copyId) {
- parentComponentId = action.payload.copyId;
- } else {
- parentComponentId = state.canvasFocus.componentId;
- }
+ const parentComponentId =
+ action.payload.copyId || state.canvasFocus.componentId;
// make a copy of the components from state
const components = [...state.components];
// find the parent component
const parentComponent = findComponent(components, parentComponentId);
+ if (!parentComponent) return state; // ensure that parent component exists
// if type is 'Component', loop through components to find componentName and componentChildren
let componentName: string = '';
let componentChildren: ChildElement[] = [];
- if (type === 'Component') {
- components.forEach((comp) => {
- if (comp.id === typeId) {
- componentName = comp.name;
- componentChildren = comp.children;
- }
- });
- }
+
if (type === 'Component') {
const originalComponent = findComponent(state.components, typeId);
if (originalComponent) {
+ componentName = originalComponent.name;
+ componentChildren = originalComponent.children;
if (
childTypeExists('Component', parentComponentId, originalComponent)
)
return state;
}
- }
-
- // create a new name based on the type of element
- let newName = state.HTMLTypes.reduce((name, el) => {
- if (typeId === el.id) {
- name = type === 'Component' ? componentName : el.tag;
+ } else if (type === 'Route Link') {
+ const routeLinkComponent = components.find(
+ (comp) => comp.id === typeId
+ );
+ if (routeLinkComponent) {
+ componentName = routeLinkComponent.name;
}
- return name;
- }, '');
-
- if (type === 'Route Link') {
- components.find((comp) => {
- if (comp.id === typeId) {
- newName = comp.name;
- return;
+ } else if (type === 'HTML Element') {
+ componentName = state.HTMLTypes.reduce((name, el) => {
+ if (typeId === el.id) {
+ name = el.tag;
}
- });
+ return name;
+ }, '');
+ } else {
+ componentName = state.MUITypes.reduce((name, el) => {
+ if (typeId === el.id) {
+ name = el.tag;
+ }
+ return name;
+ }, '');
}
const newChild: ChildElement = {
type,
typeId,
- name: newName,
+ name: componentName,
childId: state.nextChildId,
style: {},
attributes: {},
@@ -369,26 +376,20 @@ const appStateSlice = createSlice({
// if the newChild Element is an input or img type, delete the children key/value pair
// if (newChild.name === 'input' && newChild.name === 'img')
// delete newChild.children;
- let directParent: HTMLElement | any;
+ // let directParent: HTMLElement | any;
if (childId === null) {
- if (parentComponent) {
- parentComponent.children.push(topSeparator);
- parentComponent.children.push(newChild);
- }
- }
- // if there is a childId (childId here references the direct parent of the new child) find that child and add new child to its children array
- else {
- if (parentComponent) {
- directParent = findChild(parentComponent, childId);
- //disable nesting a component inside a HTML element
+ parentComponent.children.push(topSeparator, newChild);
+ } else {
+ const directParent = findChild(parentComponent, childId);
+ if (directParent) {
if (directParent.type === 'HTML Element' && type === 'HTML Element') {
- directParent.children.push(topSeparator);
- directParent.children.push(newChild);
+ directParent.children.push(topSeparator, newChild);
} else {
return { ...state };
}
}
}
+
// update canvasFocus to the new child
const canvasFocus = {
...state.canvasFocus,
@@ -396,38 +397,34 @@ const appStateSlice = createSlice({
childId: newChild.childId
};
- const nextChildId = state.nextChildId + 1;
- let nextTopSeparatorId = state.nextTopSeparatorId + 1;
- let addChildArray = components[canvasFocus.componentId - 1].children;
- // merge separator needs interface and type
- addChildArray = manageSeparators.mergeSeparator(addChildArray, 1);
- if (directParent && directParent.name === 'separator')
- nextTopSeparatorId = manageSeparators.handleSeparators(
- // handle separator needs interface and type
- addChildArray,
- 'add'
- );
-
- components[canvasFocus.componentId - 1].children = addChildArray;
+ // Increment IDs
+ state.nextChildId += 1;
+ state.nextTopSeparatorId += 1;
- // generate code
- if (parentComponent) {
- parentComponent.code = generateCode(
- components,
- parentComponentId,
- [...state.rootComponents],
- state.projectType,
- state.HTMLTypes,
- state.tailwind,
- action.payload.contextParam
+ // Update the components array and potentially other parts of the state
+ components[parentComponentId - 1].children =
+ manageSeparators.mergeSeparator(
+ components[parentComponentId - 1].children,
+ 1
);
- }
- // update the state with the new values
+ // Generate code for the component
+ parentComponent.code = generateCode(
+ components,
+ parentComponentId,
+ [...state.rootComponents],
+ state.projectType,
+ state.HTMLTypes,
+ state.MUITypes,
+ state.tailwind,
+ action.payload.contextParam
+ );
+
+ // Update state
state.components = components;
- state.nextChildId = nextChildId;
state.canvasFocus = canvasFocus;
- state.nextTopSeparatorId = nextTopSeparatorId;
+
+ return state;
},
changeTailwind: (state, action) => {
@@ -465,6 +462,7 @@ const appStateSlice = createSlice({
[...state.rootComponents],
state.projectType,
state.HTMLTypes,
+ state.MUITypes,
state.tailwind,
action.payload.contextParam
);
@@ -489,6 +487,7 @@ const appStateSlice = createSlice({
[...state.rootComponents],
state.projectType,
state.HTMLTypes,
+ state.MUITypes,
state.tailwind,
action.payload.contextParam
);
@@ -556,6 +555,7 @@ const appStateSlice = createSlice({
[...state.rootComponents],
state.projectType,
state.HTMLTypes,
+ state.MUITypes,
state.tailwind,
action.payload.contextParam
);
@@ -582,6 +582,7 @@ const appStateSlice = createSlice({
[...state.rootComponents],
state.projectType,
state.HTMLTypes,
+ state.MUITypes,
state.tailwind,
action.payload.contextParam
);
@@ -610,6 +611,7 @@ const appStateSlice = createSlice({
[...state.rootComponents],
state.projectType,
state.HTMLTypes,
+ state.MUITypes,
state.tailwind,
action.payload.contextParam
);
@@ -639,6 +641,7 @@ const appStateSlice = createSlice({
[...state.rootComponents],
state.projectType,
state.HTMLTypes,
+ state.MUITypes,
state.tailwind,
action.payload.contextParam
);
@@ -665,6 +668,7 @@ const appStateSlice = createSlice({
[...state.rootComponents],
state.projectType,
state.HTMLTypes,
+ state.MUITypes,
state.tailwind,
action.payload.contextParam
);
@@ -723,6 +727,7 @@ const appStateSlice = createSlice({
rootComponents,
state.projectType,
state.HTMLTypes,
+ state.MUITypes,
state.tailwind,
action.payload.contextParam
);
@@ -753,6 +758,7 @@ const appStateSlice = createSlice({
[...state.rootComponents],
projectType,
state.HTMLTypes,
+ state.MUITypes,
state.tailwind,
action.payload.contextParam
);
@@ -781,6 +787,7 @@ const appStateSlice = createSlice({
const stylesheet = '';
const resetHTMLTypes = HTMLTypes;
+ const resetMUITypes = MUITypes;
return {
...state,
@@ -791,7 +798,8 @@ const appStateSlice = createSlice({
components,
canvasFocus,
stylesheet,
- HTMLTypes: resetHTMLTypes
+ HTMLTypes: resetHTMLTypes,
+ MUITypes: resetMUITypes
};
},
updateProjectName: (state, action) => {
@@ -814,6 +822,12 @@ const appStateSlice = createSlice({
}
return el.id !== action.payload.id;
});
+ // const MUITypes: MUIType[] = [...state.MUITypes].filter((el) => {
+ // if (el.id === action.payload.id) {
+ // name = el.tag;
+ // }
+ // return el.id !== action.payload.id;
+ // });
const components: Component[] = deleteById(
action.payload.id,
name,
@@ -828,6 +842,7 @@ const appStateSlice = createSlice({
rootComponents,
state.projectType,
state.HTMLTypes,
+ state.MUITypes,
state.tailwind,
action.payload.contextParam
);
@@ -835,6 +850,7 @@ const appStateSlice = createSlice({
state.canvasFocus = canvasFocus;
state.HTMLTypes = HTMLTypes;
+ // state.MUITypes = MUITypes;
},
deleteChild: (state, action) => {
@@ -880,6 +896,7 @@ const appStateSlice = createSlice({
[...state.rootComponents],
state.projectType,
state.HTMLTypes,
+ state.MUITypes,
state.tailwind,
action.payload.contextParam
);
@@ -931,6 +948,7 @@ const appStateSlice = createSlice({
state.rootComponents,
state.projectType,
state.HTMLTypes,
+ state.MUITypes,
state.tailwind,
action.payload.contextParam
);
@@ -959,6 +977,7 @@ const appStateSlice = createSlice({
state.rootComponents,
state.projectType,
state.HTMLTypes,
+ state.MUITypes,
state.tailwind,
action.payload.contextParam
);
@@ -982,6 +1001,7 @@ const appStateSlice = createSlice({
[...state.rootComponents],
state.projectType,
state.HTMLTypes,
+ state.MUITypes,
state.tailwind,
action.payload.contextParam
);
@@ -1035,6 +1055,7 @@ const appStateSlice = createSlice({
[...state.rootComponents],
state.projectType,
state.HTMLTypes,
+ state.MUITypes,
state.tailwind,
action.payload.contextParam
);
@@ -1045,6 +1066,7 @@ const appStateSlice = createSlice({
[...state.rootComponents],
state.projectType,
state.HTMLTypes,
+ state.MUITypes,
state.tailwind,
action.payload.contextParam
);
@@ -1101,6 +1123,7 @@ const appStateSlice = createSlice({
[...state.rootComponents],
state.projectType,
state.HTMLTypes,
+ state.MUITypes,
state.tailwind,
action.payload.contextParam
);
@@ -1125,6 +1148,7 @@ const appStateSlice = createSlice({
[...state.rootComponents],
state.projectType,
state.HTMLTypes,
+ state.MUITypes,
state.tailwind,
action.payload.contextParam
);
@@ -1148,6 +1172,7 @@ const appStateSlice = createSlice({
[...state.rootComponents],
state.projectType,
state.HTMLTypes,
+ state.MUITypes,
state.tailwind,
action.payload.contextParam
);
@@ -1162,6 +1187,7 @@ const appStateSlice = createSlice({
[...state.rootComponents],
state.projectType,
state.HTMLTypes,
+ state.MUITypes,
state.tailwind,
action.payload.contextParam
);
@@ -1266,6 +1292,7 @@ const appStateSlice = createSlice({
[...state.rootComponents],
state.projectType,
state.HTMLTypes,
+ state.MUITypes,
state.tailwind,
action.payload.contextParam
);
@@ -1278,6 +1305,7 @@ const appStateSlice = createSlice({
[...state.rootComponents],
state.projectType,
state.HTMLTypes,
+ state.MUITypes,
state.tailwind,
action.payload.contextParam
);