112 lines
2.5 KiB
TypeScript
112 lines
2.5 KiB
TypeScript
import useShapeEvents from 'hooks/useShapeEvents'
|
|
import { Shape as _Shape, ShapeType, TextShape } from 'types'
|
|
import { getShapeUtils } from 'state/shape-utils'
|
|
import { shallowEqual } from 'utils'
|
|
import { memo, useRef } from 'react'
|
|
|
|
interface ShapeProps {
|
|
shape: _Shape
|
|
isEditing: boolean
|
|
isHovered: boolean
|
|
isSelected: boolean
|
|
isCurrentParent: boolean
|
|
}
|
|
|
|
const Shape = memo(
|
|
({
|
|
shape,
|
|
isEditing,
|
|
isHovered,
|
|
isSelected,
|
|
isCurrentParent,
|
|
}: ShapeProps) => {
|
|
const rGroup = useRef<SVGGElement>(null)
|
|
const events = useShapeEvents(shape.id, isCurrentParent, rGroup)
|
|
const utils = getShapeUtils(shape)
|
|
|
|
const center = utils.getCenter(shape)
|
|
const rotation = shape.rotation * (180 / Math.PI)
|
|
const transform = `
|
|
rotate(${rotation}, ${center})
|
|
translate(${shape.point})
|
|
`
|
|
|
|
return (
|
|
<g
|
|
ref={rGroup}
|
|
id={shape.id}
|
|
transform={transform}
|
|
filter={isHovered ? 'url(#expand)' : 'none'}
|
|
{...events}
|
|
>
|
|
{isEditing && shape.type === ShapeType.Text ? (
|
|
<EditingTextShape shape={shape} />
|
|
) : (
|
|
<RenderedShape
|
|
shape={shape}
|
|
isEditing={isEditing}
|
|
isHovered={isHovered}
|
|
isSelected={isSelected}
|
|
isCurrentParent={isCurrentParent}
|
|
/>
|
|
)}
|
|
</g>
|
|
)
|
|
},
|
|
shallowEqual
|
|
)
|
|
|
|
export default Shape
|
|
|
|
interface RenderedShapeProps {
|
|
shape: _Shape
|
|
isEditing: boolean
|
|
isHovered: boolean
|
|
isSelected: boolean
|
|
isCurrentParent: boolean
|
|
}
|
|
|
|
const RenderedShape = memo(
|
|
function RenderedShape({
|
|
shape,
|
|
isEditing,
|
|
isHovered,
|
|
isSelected,
|
|
isCurrentParent,
|
|
}: RenderedShapeProps) {
|
|
return getShapeUtils(shape).render(shape, {
|
|
isEditing,
|
|
isHovered,
|
|
isSelected,
|
|
isCurrentParent,
|
|
})
|
|
},
|
|
(prev, next) => {
|
|
if (
|
|
prev.isEditing !== next.isEditing ||
|
|
prev.isHovered !== next.isHovered ||
|
|
prev.isSelected !== next.isSelected ||
|
|
prev.isCurrentParent !== next.isCurrentParent
|
|
) {
|
|
return false
|
|
}
|
|
|
|
if (next.shape !== prev.shape) {
|
|
return !getShapeUtils(next.shape).shouldRender(next.shape, prev.shape)
|
|
}
|
|
|
|
return true
|
|
}
|
|
)
|
|
|
|
function EditingTextShape({ shape }: { shape: TextShape }) {
|
|
const ref = useRef<HTMLTextAreaElement>(null)
|
|
|
|
return getShapeUtils(shape).render(shape, {
|
|
ref,
|
|
isEditing: true,
|
|
isHovered: false,
|
|
isSelected: false,
|
|
isCurrentParent: false,
|
|
})
|
|
}
|