Fixes bug with SVG export
This commit is contained in:
parent
0bf450b01d
commit
f9c688056e
5 changed files with 44 additions and 97 deletions
|
@ -1,19 +1,20 @@
|
||||||
import * as Sentry from '@sentry/node'
|
import * as Sentry from '@sentry/node'
|
||||||
import { ErrorBoundary } from 'react-error-boundary'
|
|
||||||
import Bounds from './bounds/bounding-box'
|
|
||||||
import BoundsBg from './bounds/bounds-bg'
|
|
||||||
import Brush from './brush'
|
|
||||||
import ContextMenu from './context-menu/context-menu'
|
|
||||||
import Coop from './coop/coop'
|
|
||||||
import Defs from './defs'
|
|
||||||
import Handles from './bounds/handles'
|
|
||||||
import Page from './page'
|
|
||||||
import React, { useRef } from 'react'
|
import React, { useRef } from 'react'
|
||||||
|
|
||||||
|
import { ErrorBoundary } from 'react-error-boundary'
|
||||||
import state, { useSelector } from 'state'
|
import state, { useSelector } from 'state'
|
||||||
import styled from 'styles'
|
import styled from 'styles'
|
||||||
import useCamera from 'hooks/useCamera'
|
import useCamera from 'hooks/useCamera'
|
||||||
import useCanvasEvents from 'hooks/useCanvasEvents'
|
import useCanvasEvents from 'hooks/useCanvasEvents'
|
||||||
import useZoomEvents from 'hooks/useZoomEvents'
|
import useZoomEvents from 'hooks/useZoomEvents'
|
||||||
|
import Bounds from './bounds/bounding-box'
|
||||||
|
import BoundsBg from './bounds/bounds-bg'
|
||||||
|
import Handles from './bounds/handles'
|
||||||
|
import ContextMenu from './context-menu/context-menu'
|
||||||
|
import Coop from './coop/coop'
|
||||||
|
import Brush from './brush'
|
||||||
|
import Defs from './defs'
|
||||||
|
import Page from './page'
|
||||||
|
|
||||||
function resetError() {
|
function resetError() {
|
||||||
null
|
null
|
||||||
|
|
|
@ -114,8 +114,8 @@ function addToTree(
|
||||||
shape.children
|
shape.children
|
||||||
.map((id) => tld.getShape(data, id))
|
.map((id) => tld.getShape(data, id))
|
||||||
.sort((a, b) => a.childIndex - b.childIndex)
|
.sort((a, b) => a.childIndex - b.childIndex)
|
||||||
.forEach((shape) => {
|
.forEach((childShape) => {
|
||||||
addToTree(data, selectedIds, allowHovers, node.children, shape)
|
addToTree(data, selectedIds, allowHovers, node.children, childShape)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,76 +0,0 @@
|
||||||
import styled from 'styles'
|
|
||||||
import { useSelector } from 'state'
|
|
||||||
import tld from 'utils/tld'
|
|
||||||
import { deepCompareArrays } from 'utils'
|
|
||||||
import { getShapeUtils } from 'state/shape-utils'
|
|
||||||
import { memo } from 'react'
|
|
||||||
|
|
||||||
export default function Selected(): JSX.Element {
|
|
||||||
const currentSelectedShapeIds = useSelector(
|
|
||||||
(s) => s.values.selectedIds,
|
|
||||||
deepCompareArrays
|
|
||||||
)
|
|
||||||
|
|
||||||
const isSelecting = useSelector((s) => s.isIn('selecting'))
|
|
||||||
|
|
||||||
if (!isSelecting) return null
|
|
||||||
|
|
||||||
return (
|
|
||||||
<g>
|
|
||||||
{currentSelectedShapeIds.map((id) => (
|
|
||||||
<ShapeOutline key={id} id={id} />
|
|
||||||
))}
|
|
||||||
</g>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export const ShapeOutline = memo(function ShapeOutline({ id }: { id: string }) {
|
|
||||||
// const rIndicator = useRef<SVGUseElement>(null)
|
|
||||||
|
|
||||||
const shape = useSelector((s) => tld.getShape(s.data, id))
|
|
||||||
|
|
||||||
// const events = useShapeEvents(id, shape?.type === ShapeType.Group, rIndicator)
|
|
||||||
|
|
||||||
if (!shape) return null
|
|
||||||
|
|
||||||
// This needs computation from state, similar to bounds, in order
|
|
||||||
// to handle parent rotation.
|
|
||||||
|
|
||||||
const center = getShapeUtils(shape).getCenter(shape)
|
|
||||||
|
|
||||||
const transform = `
|
|
||||||
rotate(${shape.rotation * (180 / Math.PI)}, ${center})
|
|
||||||
translate(${shape.point})
|
|
||||||
`
|
|
||||||
|
|
||||||
return (
|
|
||||||
<SelectIndicator
|
|
||||||
// ref={rIndicator}
|
|
||||||
as="use"
|
|
||||||
href={'#' + id}
|
|
||||||
transform={transform}
|
|
||||||
isLocked={shape.isLocked}
|
|
||||||
// {...events}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
const SelectIndicator = styled('path', {
|
|
||||||
// zStrokeWidth: 2,
|
|
||||||
strokeLineCap: 'round',
|
|
||||||
strokeLinejoin: 'round',
|
|
||||||
stroke: 'red',
|
|
||||||
strokeWidth: '10',
|
|
||||||
pointerEvents: 'none',
|
|
||||||
fill: 'red',
|
|
||||||
|
|
||||||
variants: {
|
|
||||||
isLocked: {
|
|
||||||
true: {
|
|
||||||
zDash: 2,
|
|
||||||
},
|
|
||||||
false: {},
|
|
||||||
},
|
|
||||||
variant: {},
|
|
||||||
},
|
|
||||||
})
|
|
|
@ -3,6 +3,7 @@ import { Shape as _Shape, ShapeType, TextShape } from 'types'
|
||||||
import { getShapeUtils } from 'state/shape-utils'
|
import { getShapeUtils } from 'state/shape-utils'
|
||||||
import { shallowEqual } from 'utils'
|
import { shallowEqual } from 'utils'
|
||||||
import { memo, useRef } from 'react'
|
import { memo, useRef } from 'react'
|
||||||
|
import styled from 'styles'
|
||||||
|
|
||||||
interface ShapeProps {
|
interface ShapeProps {
|
||||||
shape: _Shape
|
shape: _Shape
|
||||||
|
@ -26,16 +27,14 @@ const Shape = memo(
|
||||||
|
|
||||||
const center = utils.getCenter(shape)
|
const center = utils.getCenter(shape)
|
||||||
const rotation = shape.rotation * (180 / Math.PI)
|
const rotation = shape.rotation * (180 / Math.PI)
|
||||||
const transform = `
|
const transform = `rotate(${rotation}, ${center}) translate(${shape.point})`
|
||||||
rotate(${rotation}, ${center})
|
|
||||||
translate(${shape.point})
|
|
||||||
`
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<g
|
<ShapeGroup
|
||||||
ref={rGroup}
|
ref={rGroup}
|
||||||
id={shape.id}
|
id={shape.id}
|
||||||
transform={transform}
|
transform={transform}
|
||||||
|
isCurrentParent={isCurrentParent}
|
||||||
filter={isHovered ? 'url(#expand)' : 'none'}
|
filter={isHovered ? 'url(#expand)' : 'none'}
|
||||||
{...events}
|
{...events}
|
||||||
>
|
>
|
||||||
|
@ -50,7 +49,7 @@ const Shape = memo(
|
||||||
isCurrentParent={isCurrentParent}
|
isCurrentParent={isCurrentParent}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</g>
|
</ShapeGroup>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
shallowEqual
|
shallowEqual
|
||||||
|
@ -110,3 +109,27 @@ function EditingTextShape({ shape }: { shape: TextShape }) {
|
||||||
isCurrentParent: false,
|
isCurrentParent: false,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const ShapeGroup = styled('g', {
|
||||||
|
outline: 'none',
|
||||||
|
|
||||||
|
'& > *[data-shy=true]': {
|
||||||
|
opacity: 0,
|
||||||
|
},
|
||||||
|
|
||||||
|
'&:hover': {
|
||||||
|
'& > *[data-shy=true]': {
|
||||||
|
opacity: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
variants: {
|
||||||
|
isCurrentParent: {
|
||||||
|
true: {
|
||||||
|
'& > *[data-shy=true]': {
|
||||||
|
opacity: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
|
@ -68,12 +68,11 @@ class Clipboard {
|
||||||
shapes
|
shapes
|
||||||
.sort((a, b) => a.childIndex - b.childIndex)
|
.sort((a, b) => a.childIndex - b.childIndex)
|
||||||
.forEach((shape) => {
|
.forEach((shape) => {
|
||||||
const group = document.getElementById(shape.id + '-group')
|
const group = document.getElementById(shape.id)
|
||||||
const node = document.getElementById(shape.id)
|
|
||||||
|
|
||||||
const groupClone = group.cloneNode()
|
const groupClone = group.cloneNode(true)
|
||||||
|
|
||||||
groupClone.appendChild(node.cloneNode(true))
|
// TODO: Add children if the shape is a group
|
||||||
|
|
||||||
svg.appendChild(groupClone)
|
svg.appendChild(groupClone)
|
||||||
})
|
})
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue