kopia lustrzana https://github.com/Tldraw/Tldraw
85 wiersze
2.8 KiB
TypeScript
85 wiersze
2.8 KiB
TypeScript
import * as _Dropdown from '@radix-ui/react-dropdown-menu'
|
|
import { useContainer, useEditor, useValue } from '@tldraw/editor'
|
|
import { ReactNode, forwardRef, memo, useCallback } from 'react'
|
|
import { tldrawConstants } from '../../../tldraw-constants'
|
|
import { useBreakpoint } from '../../context/breakpoints'
|
|
import { useMenuIsOpen } from '../../hooks/useMenuIsOpen'
|
|
import { useTranslation } from '../../hooks/useTranslation/useTranslation'
|
|
import { TldrawUiButton } from '../primitives/Button/TldrawUiButton'
|
|
import { TldrawUiMenuContextProvider } from '../primitives/menus/TldrawUiMenuContext'
|
|
import { DefaultZoomMenuContent } from './DefaultZoomMenuContent'
|
|
|
|
const { PORTRAIT_BREAKPOINT, ANIMATION_MEDIUM_MS } = tldrawConstants
|
|
|
|
/** @public */
|
|
export type TLUiZoomMenuProps = {
|
|
children?: ReactNode
|
|
}
|
|
|
|
/** @public */
|
|
export const DefaultZoomMenu = memo(function DefaultZoomMenu({ children }: TLUiZoomMenuProps) {
|
|
const container = useContainer()
|
|
const [isOpen, onOpenChange] = useMenuIsOpen('zoom menu')
|
|
|
|
// Get the zoom menu content, either the default component or the user's
|
|
// override. If there's no menu content, then the user has set it to null,
|
|
// so skip rendering the menu.
|
|
const content = children ?? <DefaultZoomMenuContent />
|
|
|
|
return (
|
|
<_Dropdown.Root dir="ltr" open={isOpen} onOpenChange={onOpenChange} modal={false}>
|
|
<_Dropdown.Trigger asChild dir="ltr">
|
|
<ZoomTriggerButton />
|
|
</_Dropdown.Trigger>
|
|
<_Dropdown.Portal container={container}>
|
|
<_Dropdown.Content
|
|
className="tlui-menu"
|
|
side="top"
|
|
align="start"
|
|
alignOffset={0}
|
|
sideOffset={8}
|
|
collisionPadding={4}
|
|
>
|
|
<TldrawUiMenuContextProvider type="menu" sourceId="zoom-menu">
|
|
{content}
|
|
</TldrawUiMenuContextProvider>
|
|
</_Dropdown.Content>
|
|
</_Dropdown.Portal>
|
|
</_Dropdown.Root>
|
|
)
|
|
})
|
|
|
|
const ZoomTriggerButton = forwardRef<HTMLButtonElement, any>(
|
|
function ZoomTriggerButton(props, ref) {
|
|
const editor = useEditor()
|
|
const breakpoint = useBreakpoint()
|
|
const zoom = useValue('zoom', () => editor.getZoomLevel(), [editor])
|
|
const msg = useTranslation()
|
|
|
|
const handleDoubleClick = useCallback(() => {
|
|
editor.resetZoom(editor.getViewportScreenCenter(), { duration: ANIMATION_MEDIUM_MS })
|
|
}, [editor])
|
|
|
|
return (
|
|
<TldrawUiButton
|
|
ref={ref}
|
|
{...props}
|
|
type="icon"
|
|
title={`${msg('navigation-zone.zoom')}`}
|
|
data-testid="minimap.zoom-menu-button"
|
|
className={
|
|
breakpoint < PORTRAIT_BREAKPOINT.TABLET_SM
|
|
? 'tlui-zoom-menu__button'
|
|
: 'tlui-zoom-menu__button__pct'
|
|
}
|
|
onDoubleClick={handleDoubleClick}
|
|
icon={breakpoint < PORTRAIT_BREAKPOINT.MOBILE ? 'zoom-in' : undefined}
|
|
>
|
|
{breakpoint < PORTRAIT_BREAKPOINT.MOBILE ? null : (
|
|
<span style={{ flexGrow: 0, textAlign: 'center' }}>{Math.floor(zoom * 100)}%</span>
|
|
)}
|
|
</TldrawUiButton>
|
|
)
|
|
}
|
|
)
|