tldraw/components/canvas/canvas.tsx

100 lines
2.4 KiB
TypeScript
Raw Normal View History

2021-07-07 14:42:17 +00:00
import * as Sentry from '@sentry/node'
import React, { useEffect, useRef } from 'react'
2021-07-09 22:35:38 +00:00
import { ErrorBoundary } from 'react-error-boundary'
2021-07-09 22:35:38 +00:00
import state, { useSelector } from 'state'
import styled from 'styles'
import useCamera from 'hooks/useCamera'
import useCanvasEvents from 'hooks/useCanvasEvents'
import useZoomEvents from 'hooks/useZoomEvents'
2021-05-28 14:37:23 +00:00
import Bounds from './bounds/bounding-box'
import BoundsBg from './bounds/bounds-bg'
2021-07-09 22:35:38 +00:00
import Handles from './bounds/handles'
2021-06-30 20:31:29 +00:00
import ContextMenu from './context-menu/context-menu'
import Coop from './coop/coop'
2021-07-09 22:35:38 +00:00
import Brush from './brush'
2021-06-30 20:31:29 +00:00
import Defs from './defs'
import Page from './page'
import useSafariFocusOutFix from 'hooks/useSafariFocusOutFix'
2021-05-09 13:04:42 +00:00
function resetError() {
null
}
2021-06-21 21:35:28 +00:00
export default function Canvas(): JSX.Element {
2021-05-09 13:04:42 +00:00
const rCanvas = useRef<SVGSVGElement>(null)
const rGroup = useRef<SVGGElement>(null)
2021-05-09 21:22:25 +00:00
useCamera(rGroup)
2021-05-28 16:25:43 +00:00
useZoomEvents()
useSafariFocusOutFix()
const events = useCanvasEvents(rCanvas)
2021-05-10 12:16:57 +00:00
const isSettingCamera = useSelector((s) => s.isIn('settingCamera'))
const isReady = useSelector((s) => s.isIn('ready'))
2021-05-10 12:16:57 +00:00
useEffect(() => {
if (isSettingCamera) {
state.send('MOUNTED_SHAPES')
}
}, [isSettingCamera])
2021-05-09 13:04:42 +00:00
return (
2021-06-10 09:49:16 +00:00
<ContextMenu>
<MainSVG ref={rCanvas} {...events}>
<ErrorBoundary FallbackComponent={ErrorFallback} onReset={resetError}>
<Defs />
<g ref={rGroup} id="shapes" opacity={isReady ? 1 : 0}>
<BoundsBg />
<Page />
<Coop />
<Bounds />
<Handles />
<Brush />
</g>
</ErrorBoundary>
2021-06-10 09:49:16 +00:00
</MainSVG>
</ContextMenu>
2021-05-09 13:04:42 +00:00
)
}
2021-05-28 14:37:23 +00:00
const MainSVG = styled('svg', {
position: 'fixed',
2021-06-18 14:39:07 +00:00
overflow: 'hidden',
2021-05-09 13:04:42 +00:00
top: 0,
left: 0,
2021-05-28 14:37:23 +00:00
width: '100%',
height: '100%',
touchAction: 'none',
2021-05-09 13:04:42 +00:00
zIndex: 100,
pointerEvents: 'all',
backgroundColor: '$canvas',
borderTop: '1px solid $border',
borderBottom: '1px solid $border',
2021-05-23 13:46:04 +00:00
2021-05-28 14:37:23 +00:00
'& *': {
userSelect: 'none',
2021-05-23 13:46:04 +00:00
},
2021-05-09 13:04:42 +00:00
})
function ErrorFallback({ error, resetErrorBoundary }) {
React.useEffect(() => {
2021-07-07 14:42:17 +00:00
const copy =
'Sorry, something went wrong. Press Ok to reset the document, or press cancel to continue and see if it resolves itself.'
console.error(error)
2021-07-07 14:42:17 +00:00
Sentry.captureException(error)
if (window.confirm(copy)) {
2021-07-07 14:42:17 +00:00
state.send('RESET_DOCUMENT_STATE')
resetErrorBoundary()
}
}, [])
2021-07-07 14:42:17 +00:00
return <g />
}