|
|
@@ -1,16 +1,24 @@
|
|
|
import { useApp } from '@tldraw/react'
|
|
|
import { LogseqContext } from '../../lib/logseq-context'
|
|
|
-import { MOD_KEY, AlignType, DistributeType, isDev, EXPORT_PADDING } from '@tldraw/core'
|
|
|
+import {
|
|
|
+ MOD_KEY,
|
|
|
+ AlignType,
|
|
|
+ DistributeType,
|
|
|
+ isDev,
|
|
|
+ EXPORT_PADDING
|
|
|
+} from '@tldraw/core'
|
|
|
import { observer } from 'mobx-react-lite'
|
|
|
import { TablerIcon } from '../icons'
|
|
|
import { Button } from '../Button'
|
|
|
import { KeyboardShortcut } from '../KeyboardShortcut'
|
|
|
import * as React from 'react'
|
|
|
|
|
|
-import * as ReactContextMenu from '@radix-ui/react-context-menu'
|
|
|
import * as Separator from '@radix-ui/react-separator'
|
|
|
import { toJS } from 'mobx'
|
|
|
|
|
|
+// @ts-ignore
|
|
|
+const LSUI = window.LSUI
|
|
|
+
|
|
|
interface ContextMenuProps {
|
|
|
children: React.ReactNode
|
|
|
collisionRef: React.RefObject<HTMLDivElement>
|
|
|
@@ -35,8 +43,8 @@ export const ContextMenu = observer(function ContextMenu({
|
|
|
}, [])
|
|
|
|
|
|
return (
|
|
|
- <ReactContextMenu.Root
|
|
|
- onOpenChange={open => {
|
|
|
+ <LSUI.ContextMenu
|
|
|
+ onOpenChange={(open: boolean) => {
|
|
|
if (open && !app.isIn('select.contextMenu')) {
|
|
|
app.transition('select').selectedTool.transition('contextMenu')
|
|
|
} else if (!open && app.isIn('select.contextMenu')) {
|
|
|
@@ -44,12 +52,12 @@ export const ContextMenu = observer(function ContextMenu({
|
|
|
}
|
|
|
}}
|
|
|
>
|
|
|
- <ReactContextMenu.Trigger
|
|
|
+ <LSUI.ContextMenuTrigger
|
|
|
disabled={app.editingShape && Object.keys(app.editingShape).length !== 0}
|
|
|
>
|
|
|
{children}
|
|
|
- </ReactContextMenu.Trigger>
|
|
|
- <ReactContextMenu.Content
|
|
|
+ </LSUI.ContextMenuTrigger>
|
|
|
+ <LSUI.ContextMenuContent
|
|
|
className="tl-menu tl-context-menu"
|
|
|
ref={rContent}
|
|
|
onEscapeKeyDown={() => app.transition('select')}
|
|
|
@@ -62,34 +70,35 @@ export const ContextMenu = observer(function ContextMenu({
|
|
|
!app.readOnly &&
|
|
|
app.selectedShapesArray?.some(s => !s.props.isLocked) && (
|
|
|
<>
|
|
|
- <ReactContextMenu.Item>
|
|
|
+ <LSUI.ContextMenuItem>
|
|
|
<div className="tl-menu-button-row pb-0">
|
|
|
<Button
|
|
|
tooltip={t('whiteboard/align-left')}
|
|
|
onClick={() => runAndTransition(() => app.align(AlignType.Left))}
|
|
|
>
|
|
|
- <TablerIcon name="layout-align-left" />
|
|
|
+ <TablerIcon name="layout-align-left"/>
|
|
|
</Button>
|
|
|
<Button
|
|
|
tooltip={t('whiteboard/align-center-horizontally')}
|
|
|
onClick={() => runAndTransition(() => app.align(AlignType.CenterHorizontal))}
|
|
|
>
|
|
|
- <TablerIcon name="layout-align-center" />
|
|
|
+ <TablerIcon name="layout-align-center"/>
|
|
|
</Button>
|
|
|
<Button
|
|
|
tooltip={t('whiteboard/align-right')}
|
|
|
onClick={() => runAndTransition(() => app.align(AlignType.Right))}
|
|
|
>
|
|
|
- <TablerIcon name="layout-align-right" />
|
|
|
+ <TablerIcon name="layout-align-right"/>
|
|
|
</Button>
|
|
|
- <Separator.Root className="tl-toolbar-separator" orientation="vertical" />
|
|
|
+ <Separator.Root className="tl-toolbar-separator"
|
|
|
+ orientation="vertical"/>
|
|
|
<Button
|
|
|
tooltip={t('whiteboard/distribute-horizontally')}
|
|
|
onClick={() =>
|
|
|
runAndTransition(() => app.distribute(DistributeType.Horizontal))
|
|
|
}
|
|
|
>
|
|
|
- <TablerIcon name="layout-distribute-vertical" />
|
|
|
+ <TablerIcon name="layout-distribute-vertical"/>
|
|
|
</Button>
|
|
|
</div>
|
|
|
<div className="tl-menu-button-row pt-0">
|
|
|
@@ -97,135 +106,130 @@ export const ContextMenu = observer(function ContextMenu({
|
|
|
tooltip={t('whiteboard/align-top')}
|
|
|
onClick={() => runAndTransition(() => app.align(AlignType.Top))}
|
|
|
>
|
|
|
- <TablerIcon name="layout-align-top" />
|
|
|
+ <TablerIcon name="layout-align-top"/>
|
|
|
</Button>
|
|
|
<Button
|
|
|
tooltip={t('whiteboard/align-center-vertically')}
|
|
|
onClick={() => runAndTransition(() => app.align(AlignType.CenterVertical))}
|
|
|
>
|
|
|
- <TablerIcon name="layout-align-middle" />
|
|
|
+ <TablerIcon name="layout-align-middle"/>
|
|
|
</Button>
|
|
|
<Button
|
|
|
tooltip={t('whiteboard/align-bottom')}
|
|
|
onClick={() => runAndTransition(() => app.align(AlignType.Bottom))}
|
|
|
>
|
|
|
- <TablerIcon name="layout-align-bottom" />
|
|
|
+ <TablerIcon name="layout-align-bottom"/>
|
|
|
</Button>
|
|
|
- <Separator.Root className="tl-toolbar-separator" orientation="vertical" />
|
|
|
+ <Separator.Root className="tl-toolbar-separator"
|
|
|
+ orientation="vertical"/>
|
|
|
<Button
|
|
|
tooltip={t('whiteboard/distribute-vertically')}
|
|
|
onClick={() =>
|
|
|
runAndTransition(() => app.distribute(DistributeType.Vertical))
|
|
|
}
|
|
|
>
|
|
|
- <TablerIcon name="layout-distribute-horizontal" />
|
|
|
+ <TablerIcon name="layout-distribute-horizontal"/>
|
|
|
</Button>
|
|
|
</div>
|
|
|
- </ReactContextMenu.Item>
|
|
|
- <ReactContextMenu.Separator className="menu-separator" />
|
|
|
- <ReactContextMenu.Item
|
|
|
+ </LSUI.ContextMenuItem>
|
|
|
+ <LSUI.ContextMenuSeparator className="menu-separator"/>
|
|
|
+ <LSUI.ContextMenuItem
|
|
|
className="tl-menu-item"
|
|
|
onClick={() => runAndTransition(app.packIntoRectangle)}
|
|
|
>
|
|
|
- <TablerIcon className="tl-menu-icon" name="layout-grid" />
|
|
|
+ <TablerIcon className="tl-menu-icon" name="layout-grid"/>
|
|
|
{t('whiteboard/pack-into-rectangle')}
|
|
|
- </ReactContextMenu.Item>
|
|
|
- <ReactContextMenu.Separator className="menu-separator" />
|
|
|
+ </LSUI.ContextMenuItem>
|
|
|
+ <LSUI.ContextMenuSeparator className="menu-separator"/>
|
|
|
</>
|
|
|
)}
|
|
|
{app.selectedShapes?.size > 0 && (
|
|
|
<>
|
|
|
- <ReactContextMenu.Item
|
|
|
+ <LSUI.ContextMenuItem
|
|
|
className="tl-menu-item"
|
|
|
onClick={() => runAndTransition(app.api.zoomToSelection)}
|
|
|
>
|
|
|
+ <TablerIcon className="tl-menu-icon" name="circle-dotted"/>
|
|
|
{t('whiteboard/zoom-to-fit')}
|
|
|
- <KeyboardShortcut action="whiteboard/zoom-to-fit" />
|
|
|
- </ReactContextMenu.Item>
|
|
|
- <ReactContextMenu.Separator className="menu-separator" />
|
|
|
+ <KeyboardShortcut action="whiteboard/zoom-to-fit"/>
|
|
|
+ </LSUI.ContextMenuItem>
|
|
|
+ <LSUI.ContextMenuSeparator className="menu-separator"/>
|
|
|
</>
|
|
|
)}
|
|
|
{(app.selectedShapesArray.some(s => s.type === 'group' || app.getParentGroup(s)) ||
|
|
|
- app.selectedShapesArray.length > 1) &&
|
|
|
+ app.selectedShapesArray.length > 1) &&
|
|
|
app.selectedShapesArray?.some(s => !s.props.isLocked) &&
|
|
|
!app.readOnly && (
|
|
|
<>
|
|
|
{app.selectedShapesArray.some(s => s.type === 'group' || app.getParentGroup(s)) && (
|
|
|
- <ReactContextMenu.Item
|
|
|
+ <LSUI.ContextMenuItem
|
|
|
className="tl-menu-item"
|
|
|
onClick={() => runAndTransition(app.api.unGroup)}
|
|
|
>
|
|
|
- <TablerIcon className="tl-menu-icon" name="ungroup" />
|
|
|
+ <TablerIcon className="tl-menu-icon" name="ungroup"/>
|
|
|
{t('whiteboard/ungroup')}
|
|
|
- <KeyboardShortcut action="whiteboard/ungroup" />
|
|
|
- </ReactContextMenu.Item>
|
|
|
+ <KeyboardShortcut action="whiteboard/ungroup"/>
|
|
|
+ </LSUI.ContextMenuItem>
|
|
|
)}
|
|
|
{app.selectedShapesArray.length > 1 &&
|
|
|
app.selectedShapesArray?.some(s => !s.props.isLocked) && (
|
|
|
- <ReactContextMenu.Item
|
|
|
+ <LSUI.ContextMenuItem
|
|
|
className="tl-menu-item"
|
|
|
onClick={() => runAndTransition(app.api.doGroup)}
|
|
|
>
|
|
|
- <TablerIcon className="tl-menu-icon" name="group" />
|
|
|
+ <TablerIcon className="tl-menu-icon" name="group"/>
|
|
|
{t('whiteboard/group')}
|
|
|
- <KeyboardShortcut action="whiteboard/group" />
|
|
|
- </ReactContextMenu.Item>
|
|
|
+ <KeyboardShortcut action="whiteboard/group"/>
|
|
|
+ </LSUI.ContextMenuItem>
|
|
|
)}
|
|
|
- <ReactContextMenu.Separator className="menu-separator" />
|
|
|
+ <LSUI.ContextMenuSeparator className="menu-separator"/>
|
|
|
</>
|
|
|
)}
|
|
|
{app.selectedShapes?.size > 0 && app.selectedShapesArray?.some(s => !s.props.isLocked) && (
|
|
|
<>
|
|
|
{!app.readOnly && (
|
|
|
- <ReactContextMenu.Item
|
|
|
+ <LSUI.ContextMenuItem
|
|
|
className="tl-menu-item"
|
|
|
onClick={() => runAndTransition(app.cut)}
|
|
|
>
|
|
|
- <TablerIcon className="tl-menu-icon" name="cut" />
|
|
|
+ <TablerIcon className="tl-menu-icon" name="cut"/>
|
|
|
{t('whiteboard/cut')}
|
|
|
- </ReactContextMenu.Item>
|
|
|
+ </LSUI.ContextMenuItem>
|
|
|
)}
|
|
|
- <ReactContextMenu.Item
|
|
|
+ <LSUI.ContextMenuItem
|
|
|
className="tl-menu-item"
|
|
|
onClick={() => runAndTransition(app.copy)}
|
|
|
>
|
|
|
- <TablerIcon className="tl-menu-icon" name="copy" />
|
|
|
+ <TablerIcon className="tl-menu-icon" name="copy"/>
|
|
|
{t('whiteboard/copy')}
|
|
|
- <KeyboardShortcut action="editor/copy" />
|
|
|
- </ReactContextMenu.Item>
|
|
|
+ <KeyboardShortcut action="editor/copy"/>
|
|
|
+ </LSUI.ContextMenuItem>
|
|
|
</>
|
|
|
)}
|
|
|
{!app.readOnly && (
|
|
|
- <ReactContextMenu.Item
|
|
|
+ <LSUI.ContextMenuItem
|
|
|
className="tl-menu-item"
|
|
|
onClick={() => runAndTransition(app.paste)}
|
|
|
>
|
|
|
- <TablerIcon className="tl-menu-icon" name="clipboard" />
|
|
|
+ <TablerIcon className="tl-menu-icon" name="clipboard"/>
|
|
|
{t('whiteboard/paste')}
|
|
|
- <div className="tl-menu-right-slot">
|
|
|
- <span className="keyboard-shortcut">
|
|
|
- <code>{MOD_KEY}+v</code>
|
|
|
- </span>
|
|
|
- </div>
|
|
|
- </ReactContextMenu.Item>
|
|
|
+ <KeyboardShortcut shortcut={`${MOD_KEY}+v`}/>
|
|
|
+ </LSUI.ContextMenuItem>
|
|
|
)}
|
|
|
{app.selectedShapes?.size === 1 && !app.readOnly && (
|
|
|
- <ReactContextMenu.Item
|
|
|
+ <LSUI.ContextMenuItem
|
|
|
className="tl-menu-item"
|
|
|
onClick={() => runAndTransition(() => app.paste(undefined, true))}
|
|
|
>
|
|
|
+ <TablerIcon className="tl-menu-icon" name="circle-dotted"/>
|
|
|
{t('whiteboard/paste-as-link')}
|
|
|
- <div className="tl-menu-right-slot">
|
|
|
- <span className="keyboard-shortcut">
|
|
|
- <code>{MOD_KEY}+⇧+v</code>
|
|
|
- </span>
|
|
|
- </div>
|
|
|
- </ReactContextMenu.Item>
|
|
|
+ <KeyboardShortcut shortcut={`${MOD_KEY}+⇧+v`}/>
|
|
|
+ </LSUI.ContextMenuItem>
|
|
|
)}
|
|
|
{app.selectedShapes?.size > 0 && (
|
|
|
<>
|
|
|
- <ReactContextMenu.Separator className="menu-separator" />
|
|
|
- <ReactContextMenu.Item
|
|
|
+ <LSUI.ContextMenuSeparator className="menu-separator"/>
|
|
|
+ <LSUI.ContextMenuItem
|
|
|
className="tl-menu-item"
|
|
|
onClick={() =>
|
|
|
runAndTransition(() =>
|
|
|
@@ -239,107 +243,113 @@ export const ContextMenu = observer(function ContextMenu({
|
|
|
)
|
|
|
}
|
|
|
>
|
|
|
- <TablerIcon className="tl-menu-icon" name="file-export" />
|
|
|
+ <TablerIcon className="tl-menu-icon" name="file-export"/>
|
|
|
{t('whiteboard/export')}
|
|
|
<div className="tl-menu-right-slot">
|
|
|
<span className="keyboard-shortcut"></span>
|
|
|
</div>
|
|
|
- </ReactContextMenu.Item>
|
|
|
+ </LSUI.ContextMenuItem>
|
|
|
</>
|
|
|
)}
|
|
|
- <ReactContextMenu.Separator className="menu-separator" />
|
|
|
- <ReactContextMenu.Item
|
|
|
+ <LSUI.ContextMenuSeparator className="menu-separator"/>
|
|
|
+ <LSUI.ContextMenuItem
|
|
|
className="tl-menu-item"
|
|
|
onClick={() => runAndTransition(app.api.selectAll)}
|
|
|
>
|
|
|
+ <TablerIcon className="tl-menu-icon" name="circle-dotted"/>
|
|
|
{t('whiteboard/select-all')}
|
|
|
- <KeyboardShortcut action="editor/select-parent" />
|
|
|
- </ReactContextMenu.Item>
|
|
|
+ <KeyboardShortcut action="editor/select-parent"/>
|
|
|
+ </LSUI.ContextMenuItem>
|
|
|
{app.selectedShapes?.size > 1 && (
|
|
|
- <ReactContextMenu.Item
|
|
|
+ <LSUI.ContextMenuItem
|
|
|
className="tl-menu-item"
|
|
|
onClick={() => runAndTransition(app.api.deselectAll)}
|
|
|
>
|
|
|
+ <TablerIcon className="tl-menu-icon" name="circle-dotted"/>
|
|
|
{t('whiteboard/deselect-all')}
|
|
|
- </ReactContextMenu.Item>
|
|
|
+ </LSUI.ContextMenuItem>
|
|
|
)}
|
|
|
{!app.readOnly &&
|
|
|
app.selectedShapes?.size > 0 &&
|
|
|
app.selectedShapesArray?.some(s => !s.props.isLocked) && (
|
|
|
- <ReactContextMenu.Item
|
|
|
+ <LSUI.ContextMenuItem
|
|
|
className="tl-menu-item"
|
|
|
onClick={() => runAndTransition(() => app.setLocked(true))}
|
|
|
>
|
|
|
- <TablerIcon className="tl-menu-icon" name="lock" />
|
|
|
+ <TablerIcon className="tl-menu-icon" name="lock"/>
|
|
|
{t('whiteboard/lock')}
|
|
|
- <KeyboardShortcut action="whiteboard/lock" />
|
|
|
- </ReactContextMenu.Item>
|
|
|
+ <KeyboardShortcut action="whiteboard/lock"/>
|
|
|
+ </LSUI.ContextMenuItem>
|
|
|
)}
|
|
|
{!app.readOnly &&
|
|
|
app.selectedShapes?.size > 0 &&
|
|
|
app.selectedShapesArray?.some(s => s.props.isLocked) && (
|
|
|
- <ReactContextMenu.Item
|
|
|
+ <LSUI.ContextMenuItem
|
|
|
className="tl-menu-item"
|
|
|
onClick={() => runAndTransition(() => app.setLocked(false))}
|
|
|
>
|
|
|
- <TablerIcon className="tl-menu-icon" name="lock-open" />
|
|
|
+ <TablerIcon className="tl-menu-icon" name="lock-open"/>
|
|
|
{t('whiteboard/unlock')}
|
|
|
- <KeyboardShortcut action="whiteboard/unlock" />
|
|
|
- </ReactContextMenu.Item>
|
|
|
+ <KeyboardShortcut action="whiteboard/unlock"/>
|
|
|
+ </LSUI.ContextMenuItem>
|
|
|
)}
|
|
|
{app.selectedShapes?.size > 0 &&
|
|
|
!app.readOnly &&
|
|
|
app.selectedShapesArray?.some(s => !s.props.isLocked) && (
|
|
|
<>
|
|
|
- <ReactContextMenu.Item
|
|
|
+ <LSUI.ContextMenuItem
|
|
|
className="tl-menu-item"
|
|
|
onClick={() => runAndTransition(app.api.deleteShapes)}
|
|
|
>
|
|
|
- <TablerIcon className="tl-menu-icon" name="backspace" />
|
|
|
+ <TablerIcon className="tl-menu-icon" name="backspace"/>
|
|
|
{t('whiteboard/delete')}
|
|
|
- <KeyboardShortcut action="editor/delete" />
|
|
|
- </ReactContextMenu.Item>
|
|
|
+ <KeyboardShortcut action="editor/delete"/>
|
|
|
+ </LSUI.ContextMenuItem>
|
|
|
{app.selectedShapes?.size > 1 && !app.readOnly && (
|
|
|
<>
|
|
|
- <ReactContextMenu.Separator className="menu-separator" />
|
|
|
- <ReactContextMenu.Item
|
|
|
+ <LSUI.ContextMenuSeparator className="menu-separator"/>
|
|
|
+ <LSUI.ContextMenuItem
|
|
|
className="tl-menu-item"
|
|
|
onClick={() => runAndTransition(app.flipHorizontal)}
|
|
|
>
|
|
|
- <TablerIcon className="tl-menu-icon" name="flip-horizontal" />
|
|
|
+ <TablerIcon className="tl-menu-icon"
|
|
|
+ name="flip-horizontal"/>
|
|
|
{t('whiteboard/flip-horizontally')}
|
|
|
- </ReactContextMenu.Item>
|
|
|
- <ReactContextMenu.Item
|
|
|
+ </LSUI.ContextMenuItem>
|
|
|
+ <LSUI.ContextMenuItem
|
|
|
className="tl-menu-item"
|
|
|
onClick={() => runAndTransition(app.flipVertical)}
|
|
|
>
|
|
|
- <TablerIcon className="tl-menu-icon" name="flip-vertical" />
|
|
|
+ <TablerIcon className="tl-menu-icon"
|
|
|
+ name="flip-vertical"/>
|
|
|
{t('whiteboard/flip-vertically')}
|
|
|
- </ReactContextMenu.Item>
|
|
|
+ </LSUI.ContextMenuItem>
|
|
|
</>
|
|
|
)}
|
|
|
{!app.readOnly && (
|
|
|
<>
|
|
|
- <ReactContextMenu.Separator className="menu-separator" />
|
|
|
- <ReactContextMenu.Item
|
|
|
+ <LSUI.ContextMenuSeparator className="menu-separator"/>
|
|
|
+ <LSUI.ContextMenuItem
|
|
|
className="tl-menu-item"
|
|
|
onClick={() => runAndTransition(app.bringToFront)}
|
|
|
>
|
|
|
+ <TablerIcon className="tl-menu-icon" name="circle-dotted"/>
|
|
|
{t('whiteboard/move-to-front')}
|
|
|
- <KeyboardShortcut action="whiteboard/bring-to-front" />
|
|
|
- </ReactContextMenu.Item>
|
|
|
- <ReactContextMenu.Item
|
|
|
+ <KeyboardShortcut action="whiteboard/bring-to-front"/>
|
|
|
+ </LSUI.ContextMenuItem>
|
|
|
+ <LSUI.ContextMenuItem
|
|
|
className="tl-menu-item"
|
|
|
onClick={() => runAndTransition(app.sendToBack)}
|
|
|
>
|
|
|
+ <TablerIcon className="tl-menu-icon" name="circle-dotted"/>
|
|
|
{t('whiteboard/move-to-back')}
|
|
|
- <KeyboardShortcut action="whiteboard/send-to-back" />
|
|
|
- </ReactContextMenu.Item>
|
|
|
+ <KeyboardShortcut action="whiteboard/send-to-back"/>
|
|
|
+ </LSUI.ContextMenuItem>
|
|
|
</>
|
|
|
)}
|
|
|
|
|
|
{developerMode && (
|
|
|
- <ReactContextMenu.Item
|
|
|
+ <LSUI.ContextMenuItem
|
|
|
className="tl-menu-item"
|
|
|
onClick={() => {
|
|
|
if (app.selectedShapesArray.length === 1) {
|
|
|
@@ -350,12 +360,12 @@ export const ContextMenu = observer(function ContextMenu({
|
|
|
}}
|
|
|
>
|
|
|
{t('whiteboard/dev-print-shape-props')}
|
|
|
- </ReactContextMenu.Item>
|
|
|
+ </LSUI.ContextMenuItem>
|
|
|
)}
|
|
|
</>
|
|
|
)}
|
|
|
</div>
|
|
|
- </ReactContextMenu.Content>
|
|
|
- </ReactContextMenu.Root>
|
|
|
+ </LSUI.ContextMenuContent>
|
|
|
+ </LSUI.ContextMenu>
|
|
|
)
|
|
|
})
|