kopia lustrzana https://github.com/Tldraw/Tldraw
119 wiersze
3.5 KiB
TypeScript
119 wiersze
3.5 KiB
TypeScript
import * as React from 'react'
|
|
import * as DropdownMenu from '@radix-ui/react-dropdown-menu'
|
|
import { Panel } from '~components/Primitives/Panel'
|
|
import { ToolButton } from '~components/Primitives/ToolButton'
|
|
import { TDShapeType, TDSnapshot, TDToolType } from '~types'
|
|
import { useTldrawApp } from '~hooks'
|
|
import { SquareIcon, CircleIcon, VercelLogoIcon } from '@radix-ui/react-icons'
|
|
import { Tooltip } from '~components/Primitives/Tooltip'
|
|
import { LineIcon } from '~components/Primitives/icons'
|
|
import { useIntl } from 'react-intl'
|
|
|
|
interface ShapesMenuProps {
|
|
activeTool: TDToolType
|
|
isToolLocked: boolean
|
|
}
|
|
|
|
type ShapeShape =
|
|
| TDShapeType.Rectangle
|
|
| TDShapeType.Ellipse
|
|
| TDShapeType.Triangle
|
|
| TDShapeType.Line
|
|
|
|
const shapeShapes: ShapeShape[] = [
|
|
TDShapeType.Rectangle,
|
|
TDShapeType.Ellipse,
|
|
TDShapeType.Triangle,
|
|
TDShapeType.Line,
|
|
]
|
|
|
|
const shapeShapeIcons = {
|
|
[TDShapeType.Rectangle]: <SquareIcon />,
|
|
[TDShapeType.Ellipse]: <CircleIcon />,
|
|
[TDShapeType.Triangle]: <VercelLogoIcon />,
|
|
[TDShapeType.Line]: <LineIcon />,
|
|
}
|
|
|
|
const statusSelector = (s: TDSnapshot) => s.appState.status
|
|
|
|
enum Status {
|
|
SpacePanning = 'spacePanning',
|
|
}
|
|
|
|
export const ShapesMenu = React.memo(function ShapesMenu({
|
|
activeTool,
|
|
isToolLocked,
|
|
}: ShapesMenuProps) {
|
|
const app = useTldrawApp()
|
|
const intl = useIntl()
|
|
|
|
const status = app.useStore(statusSelector)
|
|
|
|
const [lastActiveTool, setLastActiveTool] = React.useState<ShapeShape>(TDShapeType.Rectangle)
|
|
|
|
React.useEffect(() => {
|
|
if (shapeShapes.includes(activeTool as ShapeShape) && lastActiveTool !== activeTool) {
|
|
setLastActiveTool(activeTool as ShapeShape)
|
|
}
|
|
}, [activeTool])
|
|
|
|
const selectShapeTool = React.useCallback(() => {
|
|
app.selectTool(lastActiveTool)
|
|
}, [activeTool, app])
|
|
|
|
const handleDoubleClick = React.useCallback(() => {
|
|
app.toggleToolLock()
|
|
}, [app])
|
|
|
|
const handleKeyDown = React.useCallback((e: React.KeyboardEvent<HTMLButtonElement>) => {
|
|
if (e.key === ' ') {
|
|
if (app.shiftKey) {
|
|
e.preventDefault()
|
|
}
|
|
}
|
|
}, [])
|
|
|
|
const isActive = shapeShapes.includes(activeTool as ShapeShape)
|
|
|
|
return (
|
|
<DropdownMenu.Root dir="ltr" onOpenChange={selectShapeTool}>
|
|
<DropdownMenu.Trigger dir="ltr" asChild id="TD-PrimaryTools-Shapes">
|
|
<ToolButton
|
|
disabled={isActive && app.shiftKey} // otherwise this continuously opens and closes on "SpacePanning"
|
|
variant="primary"
|
|
onDoubleClick={handleDoubleClick}
|
|
isToolLocked={isActive && isToolLocked}
|
|
isActive={isActive}
|
|
onKeyDown={handleKeyDown}
|
|
>
|
|
{shapeShapeIcons[lastActiveTool]}
|
|
</ToolButton>
|
|
</DropdownMenu.Trigger>
|
|
<DropdownMenu.Content asChild dir="ltr" side="top" sideOffset={12}>
|
|
<Panel side="center">
|
|
{shapeShapes.map((shape, i) => (
|
|
<Tooltip
|
|
key={shape}
|
|
label={intl.formatMessage({ id: shape[0].toUpperCase() + shape.slice(1) })}
|
|
kbd={(4 + i).toString()}
|
|
id={`TD-PrimaryTools-Shapes-${shape}`}
|
|
>
|
|
<DropdownMenu.Item asChild>
|
|
<ToolButton
|
|
variant="primary"
|
|
onClick={() => {
|
|
app.selectTool(shape)
|
|
setLastActiveTool(shape)
|
|
}}
|
|
>
|
|
{shapeShapeIcons[shape]}
|
|
</ToolButton>
|
|
</DropdownMenu.Item>
|
|
</Tooltip>
|
|
))}
|
|
</Panel>
|
|
</DropdownMenu.Content>
|
|
</DropdownMenu.Root>
|
|
)
|
|
})
|