Skip to content

Commit

Permalink
Add parent inspector and hover through inspector (#51)
Browse files Browse the repository at this point in the history
* Add parent inspector and hover through inspector

* Update element layout

* Update icons
  • Loading branch information
foyarash authored Feb 13, 2020
1 parent 0e1d6f4 commit 0b93a46
Show file tree
Hide file tree
Showing 12 changed files with 222 additions and 74 deletions.
5 changes: 4 additions & 1 deletion src/components/inspector/ActionButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,16 @@ interface Props
icon: IconButtonProps['icon']
as?: IconButtonProps['as']
label: string
onClick?: () => void
onClick?: IconButtonProps['onClick']
variantColor?: IconButtonProps['variantColor']
}

const ActionButton: React.FC<Props> = ({
icon,
as,
label,
onClick,
variantColor,
...props
}) => {
return (
Expand All @@ -30,6 +32,7 @@ const ActionButton: React.FC<Props> = ({
onClick={onClick}
icon={icon}
aria-label={label}
variantColor={variantColor}
/>
</Tooltip>
)
Expand Down
16 changes: 13 additions & 3 deletions src/components/inspector/ChildrenInspector.tsx
Original file line number Diff line number Diff line change
@@ -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 = () => {
Expand All @@ -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 (
<ChildrenList
childrenList={childrenComponent}
<ElementsList
elements={childrenComponent}
moveItem={moveChildren}
onSelect={onSelectChild}
onHover={onHoverChild}
onUnhover={onUnhoverChild}
/>
)
}
Expand Down
7 changes: 6 additions & 1 deletion src/components/inspector/Inspector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -88,7 +89,11 @@ const Inspector = () => {
<Panels component={component} isRoot={isRoot} />
</Box>

<StylesPanel isRoot={isRoot} showChildren={componentHasChildren} />
<StylesPanel
isRoot={isRoot}
showChildren={componentHasChildren}
parentIsRoot={parentIsRoot}
/>
</>
)
}
Expand Down
33 changes: 33 additions & 0 deletions src/components/inspector/ParentInspector.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<ElementListItem
type={parentComponent.type}
onMouseOver={onHover}
onMouseOut={onUnhover}
onSelect={onSelect}
/>
)
}

export default ParentInspector
35 changes: 0 additions & 35 deletions src/components/inspector/children/ChildrenList.tsx

This file was deleted.

52 changes: 52 additions & 0 deletions src/components/inspector/elements-list/ElementListItem.tsx
Original file line number Diff line number Diff line change
@@ -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<IComponent, 'type'> {
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<HTMLDivElement>,
) => {
return (
<PseudoBox
boxSizing="border-box"
transition="margin 200ms"
my={1}
rounded="md"
p={1}
display="flex"
alignItems="center"
cursor={draggable ? 'move' : undefined}
opacity={opacity}
ref={ref}
onMouseOver={onMouseOver}
onMouseOut={onMouseOut}
>
<Flex justify="space-between" align="center" w="100%">
<Flex align="center">
{draggable && <Icon fontSize="xs" mr={2} name="arrow-up-down" />}
<Text letterSpacing="wide" fontSize="sm" textTransform="capitalize">
{type}
</Text>
</Flex>
<ActionButton
label="Inspect"
onClick={onSelect}
icon="settings"
variantColor="blackAlpha"
/>
</Flex>
</PseudoBox>
)
},
)

export default ElementListItem
Original file line number Diff line number Diff line change
@@ -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<IComponent, 'type'> {
interface Props extends Pick<IComponent, 'type' | 'id'> {
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<Props> = ({
const ElementListItemDraggable: React.FC<Props> = ({
type,
id,
onSelect,
moveItem,
index,
onHover,
onUnhover,
}) => {
const ref = useRef<HTMLDivElement>(null)
const [, drop] = useDrop({
Expand All @@ -42,7 +45,9 @@ const ChildElement: React.FC<Props> = ({
if (dragIndex > hoverIndex && hoverClientY > hoverMiddleY) {
return
}
moveItem(dragIndex, hoverIndex)
if (moveItem) {
moveItem(dragIndex, hoverIndex)
}
// @ts-ignore
item.index = hoverIndex
},
Expand All @@ -58,30 +63,25 @@ const ChildElement: React.FC<Props> = ({

drag(drop(ref))

const onSelectChild = () => {
const onSelectElement = () => {
onSelect(id)
}

const onMouseOver = () => {
onHover(id)
}

return (
<PseudoBox
boxSizing="border-box"
transition="margin 200ms"
my={1}
rounded="md"
p={1}
display="flex"
alignItems="center"
cursor="move"
opacity={opacity}
<ElementListItem
ref={ref}
onClick={onSelectChild}
>
<Icon fontSize="xs" mr={2} name="drag-handle" />
<Text letterSpacing="wide" fontSize="sm" textTransform="capitalize">
{type}
</Text>
</PseudoBox>
onSelect={onSelectElement}
opacity={opacity}
onMouseOver={onMouseOver}
onMouseOut={onUnhover}
type={type}
draggable
/>
)
}

export default ChildElement
export default ElementListItemDraggable
41 changes: 41 additions & 0 deletions src/components/inspector/elements-list/ElementsList.tsx
Original file line number Diff line number Diff line change
@@ -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<Props> = ({
elements,
moveItem,
onSelect,
onHover,
onUnhover,
}) => {
return (
<Box mx={2} h="100%">
{elements.map(
(element, index) =>
element && (
<ElementListItem
key={element.id}
type={element.type}
index={index}
moveItem={moveItem}
id={element.id}
onSelect={onSelect}
onHover={onHover}
onUnhover={onUnhover}
/>
),
)}
</Box>
)
}

export default ElementsList
14 changes: 13 additions & 1 deletion src/components/inspector/panels/StylesPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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<Props> = ({ isRoot, showChildren }) => (
const StylesPanel: React.FC<Props> = ({
isRoot,
showChildren,
parentIsRoot,
}) => (
<Accordion defaultIndex={[0]} allowMultiple>
{!isRoot && !parentIsRoot && (
<AccordionContainer title="Parent">
<ParentInspector />
</AccordionContainer>
)}

{showChildren && (
<AccordionContainer title="Children">
<ChildrenInspector />
Expand Down
16 changes: 16 additions & 0 deletions src/core/models/components.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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[]
Expand Down Expand Up @@ -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,
}
},
},
})

Expand Down
Loading

0 comments on commit 0b93a46

Please sign in to comment.