diff --git a/src/components/inspector/ActionButton.tsx b/src/components/inspector/ActionButton.tsx index 20bacd57cd..e56a5e4fcb 100644 --- a/src/components/inspector/ActionButton.tsx +++ b/src/components/inspector/ActionButton.tsx @@ -11,7 +11,8 @@ interface Props icon: IconButtonProps['icon'] as?: IconButtonProps['as'] label: string - onClick?: () => void + onClick?: IconButtonProps['onClick'] + variantColor?: IconButtonProps['variantColor'] } const ActionButton: React.FC = ({ @@ -19,6 +20,7 @@ const ActionButton: React.FC = ({ as, label, onClick, + variantColor, ...props }) => { return ( @@ -30,6 +32,7 @@ const ActionButton: React.FC = ({ onClick={onClick} icon={icon} aria-label={label} + variantColor={variantColor} /> ) diff --git a/src/components/inspector/ChildrenInspector.tsx b/src/components/inspector/ChildrenInspector.tsx index d5a3894605..a43b4c157b 100644 --- a/src/components/inspector/ChildrenInspector.tsx +++ b/src/components/inspector/ChildrenInspector.tsx @@ -1,7 +1,7 @@ import React from 'react' import { useSelector } from 'react-redux' import { getSelectedComponentChildren } from '../../core/selectors/components' -import ChildrenList from './children/ChildrenList' +import ElementsList from './elements-list/ElementsList' import useDispatch from '../../hooks/useDispatch' const ChildrenInspector = () => { @@ -19,11 +19,21 @@ const ChildrenInspector = () => { dispatch.components.select(id) } + const onHoverChild = (id: IComponent['id']) => { + dispatch.components.hover(id) + } + + const onUnhoverChild = () => { + dispatch.components.unhover() + } + return ( - ) } diff --git a/src/components/inspector/Inspector.tsx b/src/components/inspector/Inspector.tsx index 73aeb5e564..52b37b4674 100644 --- a/src/components/inspector/Inspector.tsx +++ b/src/components/inspector/Inspector.tsx @@ -19,6 +19,7 @@ const Inspector = () => { const { type, rootParentType, id, children } = component const isRoot = id === 'root' + const parentIsRoot = component.parent === 'root' const docType = rootParentType || type const componentHasChildren = children.length > 0 @@ -88,7 +89,11 @@ const Inspector = () => { - + ) } diff --git a/src/components/inspector/ParentInspector.tsx b/src/components/inspector/ParentInspector.tsx new file mode 100644 index 0000000000..a8c91c9a88 --- /dev/null +++ b/src/components/inspector/ParentInspector.tsx @@ -0,0 +1,33 @@ +import React from 'react' +import { useSelector } from 'react-redux' +import { getSelectedComponentParent } from '../../core/selectors/components' +import ElementListItem from './elements-list/ElementListItem' +import useDispatch from '../../hooks/useDispatch' + +const ParentInspector = () => { + const parentComponent = useSelector(getSelectedComponentParent) + const dispatch = useDispatch() + + const onSelect = () => { + dispatch.components.select(parentComponent.id) + } + + const onHover = () => { + dispatch.components.hover(parentComponent.id) + } + + const onUnhover = () => { + dispatch.components.unhover() + } + + return ( + + ) +} + +export default ParentInspector diff --git a/src/components/inspector/children/ChildrenList.tsx b/src/components/inspector/children/ChildrenList.tsx deleted file mode 100644 index 4bc65b4f37..0000000000 --- a/src/components/inspector/children/ChildrenList.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import React from 'react' -import { Box } from '@chakra-ui/core' -import ChildElement from './ChildElement' - -interface Props { - childrenList: IComponent[] - moveItem: (fromIndex: number, toIndex: number) => void - onSelect: (id: IComponent['id']) => void -} - -const ChildrenList: React.FC = ({ - childrenList, - moveItem, - onSelect, -}) => { - return ( - - {childrenList.map( - (child, index) => - child && ( - - ), - )} - - ) -} - -export default ChildrenList diff --git a/src/components/inspector/elements-list/ElementListItem.tsx b/src/components/inspector/elements-list/ElementListItem.tsx new file mode 100644 index 0000000000..7e4db30359 --- /dev/null +++ b/src/components/inspector/elements-list/ElementListItem.tsx @@ -0,0 +1,52 @@ +import React, { forwardRef } from 'react' +import { Icon, PseudoBox, Text, PseudoBoxProps, Flex } from '@chakra-ui/core' +import ActionButton from '../ActionButton' + +interface Props extends Pick { + opacity?: number + onSelect: PseudoBoxProps['onClick'] + onMouseOver: PseudoBoxProps['onMouseOver'] + onMouseOut: PseudoBoxProps['onMouseOut'] + draggable?: boolean +} + +const ElementListItem = forwardRef( + ( + { type, opacity = 1, onSelect, onMouseOut, onMouseOver, draggable }: Props, + ref: React.Ref, + ) => { + return ( + + + + {draggable && } + + {type} + + + + + + ) + }, +) + +export default ElementListItem diff --git a/src/components/inspector/children/ChildElement.tsx b/src/components/inspector/elements-list/ElementListItemDraggable.tsx similarity index 64% rename from src/components/inspector/children/ChildElement.tsx rename to src/components/inspector/elements-list/ElementListItemDraggable.tsx index 0fc20c8738..1b284ce8a9 100644 --- a/src/components/inspector/children/ChildElement.tsx +++ b/src/components/inspector/elements-list/ElementListItemDraggable.tsx @@ -1,22 +1,25 @@ import React, { useRef } from 'react' import { XYCoord, useDrop, DragObjectWithType, useDrag } from 'react-dnd' -import { PseudoBox, Icon, Text } from '@chakra-ui/core' +import ElementListItem from './ElementListItem' -interface Props extends Pick { +interface Props extends Pick { index: number - moveItem: (dragIndex: number, hoverIndex: number) => void - id: IComponent['id'] + moveItem?: (dragIndex: number, hoverIndex: number) => void onSelect: (id: IComponent['id']) => void + onHover: (id: IComponent['id']) => void + onUnhover: () => void } -const ITEM_TYPE = 'childElement' +const ITEM_TYPE = 'elementItem' -const ChildElement: React.FC = ({ +const ElementListItemDraggable: React.FC = ({ type, id, onSelect, moveItem, index, + onHover, + onUnhover, }) => { const ref = useRef(null) const [, drop] = useDrop({ @@ -42,7 +45,9 @@ const ChildElement: React.FC = ({ if (dragIndex > hoverIndex && hoverClientY > hoverMiddleY) { return } - moveItem(dragIndex, hoverIndex) + if (moveItem) { + moveItem(dragIndex, hoverIndex) + } // @ts-ignore item.index = hoverIndex }, @@ -58,30 +63,25 @@ const ChildElement: React.FC = ({ drag(drop(ref)) - const onSelectChild = () => { + const onSelectElement = () => { onSelect(id) } + const onMouseOver = () => { + onHover(id) + } + return ( - - - - {type} - - + onSelect={onSelectElement} + opacity={opacity} + onMouseOver={onMouseOver} + onMouseOut={onUnhover} + type={type} + draggable + /> ) } -export default ChildElement +export default ElementListItemDraggable diff --git a/src/components/inspector/elements-list/ElementsList.tsx b/src/components/inspector/elements-list/ElementsList.tsx new file mode 100644 index 0000000000..9a4107b2ea --- /dev/null +++ b/src/components/inspector/elements-list/ElementsList.tsx @@ -0,0 +1,41 @@ +import React from 'react' +import { Box } from '@chakra-ui/core' +import ElementListItem from './ElementListItemDraggable' + +interface Props { + elements: IComponent[] + moveItem: (fromIndex: number, toIndex: number) => void + onSelect: (id: IComponent['id']) => void + onHover: (id: IComponent['id']) => void + onUnhover: () => void +} + +const ElementsList: React.FC = ({ + elements, + moveItem, + onSelect, + onHover, + onUnhover, +}) => { + return ( + + {elements.map( + (element, index) => + element && ( + + ), + )} + + ) +} + +export default ElementsList diff --git a/src/components/inspector/panels/StylesPanel.tsx b/src/components/inspector/panels/StylesPanel.tsx index ade8f33d91..b670610704 100644 --- a/src/components/inspector/panels/StylesPanel.tsx +++ b/src/components/inspector/panels/StylesPanel.tsx @@ -10,14 +10,26 @@ import AccordionContainer from '../AccordionContainer' import ColorsControl from '../controls/ColorsControl' import EffectsPanel from './styles/EffectsPanel' import ChildrenInspector from '../ChildrenInspector' +import ParentInspector from '../ParentInspector' interface Props { isRoot: boolean showChildren: boolean + parentIsRoot: boolean } -const StylesPanel: React.FC = ({ isRoot, showChildren }) => ( +const StylesPanel: React.FC = ({ + isRoot, + showChildren, + parentIsRoot, +}) => ( + {!isRoot && !parentIsRoot && ( + + + + )} + {showChildren && ( diff --git a/src/core/models/components.ts b/src/core/models/components.ts index 561539bbc7..ba04b8cd2b 100644 --- a/src/core/models/components.ts +++ b/src/core/models/components.ts @@ -7,6 +7,7 @@ import { duplicateComponent, deleteComponent } from '../../utils/recursive' export type ComponentsState = { components: IComponents selectedId: IComponent['id'] + hoveredId?: IComponent['id'] } export type ComponentsStateWithUndo = { past: ComponentsState[] @@ -269,6 +270,21 @@ const components = createModel({ } return state }, + hover( + state: ComponentsState, + componentId: IComponent['id'], + ): ComponentsState { + return { + ...state, + hoveredId: componentId, + } + }, + unhover(state: ComponentsState): ComponentsState { + return { + ...state, + hoveredId: undefined, + } + }, }, }) diff --git a/src/core/selectors/components.ts b/src/core/selectors/components.ts index 697abe3f49..9c8078be2b 100644 --- a/src/core/selectors/components.ts +++ b/src/core/selectors/components.ts @@ -29,3 +29,12 @@ export const getSelectedComponentChildren = (state: RootState) => { getComponentBy(child)(state), ) } + +export const getSelectedComponentParent = (state: RootState) => + state.components.present.components[getSelectedComponent(state).parent] + +export const getHoveredId = (state: RootState) => + state.components.present.hoveredId + +export const getIsHovered = (id: IComponent['id']) => (state: RootState) => + getHoveredId(state) === id diff --git a/src/hooks/useInteractive.ts b/src/hooks/useInteractive.ts index e4011506fb..7e43ecfec7 100644 --- a/src/hooks/useInteractive.ts +++ b/src/hooks/useInteractive.ts @@ -1,8 +1,11 @@ -import { useRef, MouseEvent, useState } from 'react' +import { useRef, MouseEvent } from 'react' import { useSelector } from 'react-redux' import useDispatch from './useDispatch' import { useDrag } from 'react-dnd' -import { getIsSelectedComponent } from '../core/selectors/components' +import { + getIsSelectedComponent, + getIsHovered, +} from '../core/selectors/components' import { getShowLayout } from '../core/selectors/app' export const useInteractive = ( @@ -10,10 +13,9 @@ export const useInteractive = ( enableVisualHelper: boolean = false, ) => { const dispatch = useDispatch() - const [hover, setHover] = useState(false) const showLayout = useSelector(getShowLayout) const isComponentSelected = useSelector(getIsSelectedComponent(component.id)) - + const isHovered = useSelector(getIsHovered(component.id)) const [, drag] = useDrag({ item: { id: component.id, type: component.type, isMoved: true }, }) @@ -24,10 +26,10 @@ export const useInteractive = ( ...component.props, onMouseOver: (event: MouseEvent) => { event.stopPropagation() - setHover(true) + dispatch.components.hover(component.id) }, onMouseOut: () => { - setHover(false) + dispatch.components.unhover() }, onClick: (event: MouseEvent) => { event.preventDefault() @@ -44,7 +46,7 @@ export const useInteractive = ( } } - if (hover || isComponentSelected) { + if (isHovered || isComponentSelected) { props = { ...props, boxShadow: `#4FD1C5 0px 0px 0px 2px inset`,