Menu updates / fix flip / add export / remove Shape menu (#3115)
This PR: - adds the export all menu items to the main menu - removes the export all menu items from the dotcom menus - removes the shape menu and reverts several changes from https://github.com/tldraw/tldraw/pull/2782. This was not properly reviewed (I thought it was a PR about hiding / showing menu items). - fixes a bug with exporting (exporting JSON was not working when the user had no selected shapes) - fixes a bug that would prevent "flip shapes" from appearing in the menu - prevents export / copy actions from running if there are no shapes on the page - allows export / copy actions to default to all shapes on the page if no shapes are selected These changes have not been released in the dotcom yet. There's will be some thrash in the APIs. # Menu philosophy In the menu, the **edit** submenu relates to undo/redo, plus the user's current selection. Menu items that relate to specific to certain shapes are hidden when not available. Menu items that relate to all shapes are disabled when not available. <img width="640" alt="image" src="https://github.com/tldraw/tldraw/assets/23072548/e467e6bb-d958-4a9a-ac19-1dada52dcfa6"> ### Change Type - [x] `major` — Bug fix ### Test - Select no shapes (arrange / flip should not be visible) - Select one geo shape (arrange / flip should not be visible) - Select two geo shapes (arrange / flip should be visible) - Select one draw shape (arrange / flip should not be visible) ### Release Notes - Revert some changes in the menu.
This commit is contained in:
parent
f1b4f807d8
commit
60cc0dcce3
17 changed files with 389 additions and 401 deletions
|
@ -1,10 +1,4 @@
|
|||
import {
|
||||
ExportFileContentSubMenu,
|
||||
TldrawUiMenuGroup,
|
||||
TldrawUiMenuItem,
|
||||
TldrawUiMenuSubmenu,
|
||||
useActions,
|
||||
} from 'tldraw'
|
||||
import { TldrawUiMenuGroup, TldrawUiMenuItem, TldrawUiMenuSubmenu, useActions } from 'tldraw'
|
||||
import {
|
||||
FORK_PROJECT_ACTION,
|
||||
LEAVE_SHARED_PROJECT_ACTION,
|
||||
|
@ -21,7 +15,6 @@ export function LocalFileMenu() {
|
|||
<TldrawUiMenuItem {...actions[NEW_PROJECT_ACTION]} />
|
||||
<TldrawUiMenuItem {...actions[OPEN_FILE_ACTION]} />
|
||||
<TldrawUiMenuItem {...actions[SAVE_FILE_COPY_ACTION]} />
|
||||
<ExportFileContentSubMenu />
|
||||
</TldrawUiMenuGroup>
|
||||
<TldrawUiMenuGroup id="share">
|
||||
<TldrawUiMenuItem {...actions[SHARE_PROJECT_ACTION]} />
|
||||
|
@ -37,7 +30,6 @@ export function MultiplayerFileMenu() {
|
|||
<TldrawUiMenuSubmenu id="file" label="menu.file">
|
||||
<TldrawUiMenuGroup id="file-actions">
|
||||
<TldrawUiMenuItem {...actions[SAVE_FILE_COPY_ACTION]} />
|
||||
<ExportFileContentSubMenu />
|
||||
</TldrawUiMenuGroup>
|
||||
<TldrawUiMenuGroup id="share">
|
||||
<TldrawUiMenuItem {...actions[FORK_PROJECT_ACTION]} />
|
||||
|
|
|
@ -11,7 +11,6 @@ import {
|
|||
Editor,
|
||||
ExtrasGroup,
|
||||
PreferencesGroup,
|
||||
ShapeSubmenu,
|
||||
TLComponents,
|
||||
Tldraw,
|
||||
TldrawUiMenuGroup,
|
||||
|
@ -49,7 +48,6 @@ const components: TLComponents = {
|
|||
<DefaultMainMenu>
|
||||
<LocalFileMenu />
|
||||
<EditSubmenu />
|
||||
<ShapeSubmenu />
|
||||
<ViewSubmenu />
|
||||
<ExtrasGroup />
|
||||
<PreferencesGroup />
|
||||
|
|
|
@ -12,7 +12,6 @@ import {
|
|||
ExtrasGroup,
|
||||
OfflineIndicator,
|
||||
PreferencesGroup,
|
||||
ShapeSubmenu,
|
||||
TLComponents,
|
||||
Tldraw,
|
||||
TldrawUiMenuGroup,
|
||||
|
@ -69,7 +68,6 @@ const components: TLComponents = {
|
|||
<DefaultMainMenu>
|
||||
<MultiplayerFileMenu />
|
||||
<EditSubmenu />
|
||||
<ShapeSubmenu />
|
||||
<ViewSubmenu />
|
||||
<ExtrasGroup />
|
||||
<PreferencesGroup />
|
||||
|
|
|
@ -212,6 +212,13 @@ test.describe('Actions on shapes', () => {
|
|||
test('Operations on shapes', async () => {
|
||||
await setupPageWithShapes(page)
|
||||
|
||||
// needs shapes on the canvas
|
||||
await page.keyboard.press('Control+Shift+c')
|
||||
expect(await page.evaluate(() => __tldraw_ui_event)).toMatchObject({
|
||||
name: 'copy-as',
|
||||
data: { format: 'svg', source: 'kbd' },
|
||||
})
|
||||
|
||||
// select-all — Cmd+A
|
||||
await page.keyboard.press('Control+a')
|
||||
expect(await page.evaluate(() => __tldraw_ui_event)).toMatchObject({
|
||||
|
@ -353,14 +360,6 @@ test.describe('Actions on shapes', () => {
|
|||
// name: 'open-menu',
|
||||
// data: { source: 'dialog' },
|
||||
// })
|
||||
|
||||
/* --------------------- Export --------------------- */
|
||||
|
||||
await page.keyboard.press('Control+Shift+c')
|
||||
expect(await page.evaluate(() => __tldraw_ui_event)).toMatchObject({
|
||||
name: 'copy-as',
|
||||
data: { format: 'svg', source: 'kbd' },
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
|
|
|
@ -37,11 +37,11 @@
|
|||
"action.export-as-svg.short": "SVG",
|
||||
"action.export-as-svg": "Export as SVG",
|
||||
"action.export-all-as-json.short": "JSON",
|
||||
"action.export-all-as-json": "Export all as JSON",
|
||||
"action.export-all-as-json": "Export as JSON",
|
||||
"action.export-all-as-png.short": "PNG",
|
||||
"action.export-all-as-png": "Export all as PNG",
|
||||
"action.export-all-as-png": "Export as PNG",
|
||||
"action.export-all-as-svg.short": "SVG",
|
||||
"action.export-all-as-svg": "Export all as SVG",
|
||||
"action.export-all-as-svg": "Export as SVG",
|
||||
"action.fit-frame-to-content": "Fit to content",
|
||||
"action.flip-horizontal": "Flip horizontally",
|
||||
"action.flip-vertical": "Flip vertically",
|
||||
|
@ -225,7 +225,6 @@
|
|||
"menu.title": "Menu",
|
||||
"menu.copy-as": "Copy as",
|
||||
"menu.edit": "Edit",
|
||||
"menu.shape": "Shape",
|
||||
"menu.export-as": "Export as",
|
||||
"menu.file": "File",
|
||||
"menu.language": "Language",
|
||||
|
@ -234,7 +233,7 @@
|
|||
"context-menu.arrange": "Arrange",
|
||||
"context-menu.copy-as": "Copy as",
|
||||
"context-menu.export-as": "Export as",
|
||||
"context-menu.export-all-as": "Export all as",
|
||||
"context-menu.export-all-as": "Export",
|
||||
"context-menu.move-to-page": "Move to page",
|
||||
"context-menu.reorder": "Reorder",
|
||||
"page-menu.title": "Pages",
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -201,12 +201,14 @@ export {
|
|||
ArrangeMenuSubmenu,
|
||||
ClipboardMenuGroup,
|
||||
ConversionsMenuGroup,
|
||||
ConvertToBookmarkMenuItem,
|
||||
ConvertToEmbedMenuItem,
|
||||
CopyAsMenuGroup,
|
||||
CopyMenuItem,
|
||||
CutMenuItem,
|
||||
DeleteMenuItem,
|
||||
DuplicateMenuItem,
|
||||
EditLinkMenuItem,
|
||||
EmbedsGroup,
|
||||
FitFrameToContentMenuItem,
|
||||
GroupMenuItem,
|
||||
MoveToPageMenu,
|
||||
|
@ -214,7 +216,7 @@ export {
|
|||
PrintItem,
|
||||
RemoveFrameMenuItem,
|
||||
ReorderMenuSubmenu,
|
||||
SetSelectionGroup,
|
||||
SelectAllMenuItem,
|
||||
ToggleAutoSizeMenuItem,
|
||||
ToggleDarkModeItem,
|
||||
ToggleDebugModeItem,
|
||||
|
@ -243,11 +245,8 @@ export {
|
|||
EditSubmenu,
|
||||
ExportFileContentSubMenu,
|
||||
ExtrasGroup,
|
||||
LockGroup,
|
||||
MiscMenuGroup,
|
||||
MultiShapeMenuGroup,
|
||||
PreferencesGroup,
|
||||
ShapeSubmenu,
|
||||
UndoRedoGroup,
|
||||
ViewSubmenu,
|
||||
} from './lib/ui/components/MainMenu/DefaultMainMenuContent'
|
||||
|
|
|
@ -3,14 +3,15 @@ import {
|
|||
ArrangeMenuSubmenu,
|
||||
ClipboardMenuGroup,
|
||||
ConversionsMenuGroup,
|
||||
ConvertToBookmarkMenuItem,
|
||||
ConvertToEmbedMenuItem,
|
||||
EditLinkMenuItem,
|
||||
EmbedsGroup,
|
||||
FitFrameToContentMenuItem,
|
||||
GroupMenuItem,
|
||||
MoveToPageMenu,
|
||||
RemoveFrameMenuItem,
|
||||
ReorderMenuSubmenu,
|
||||
SetSelectionGroup,
|
||||
SelectAllMenuItem,
|
||||
ToggleAutoSizeMenuItem,
|
||||
ToggleLockMenuItem,
|
||||
UngroupMenuItem,
|
||||
|
@ -31,16 +32,17 @@ export function DefaultContextMenuContent() {
|
|||
|
||||
return (
|
||||
<>
|
||||
<TldrawUiMenuGroup id="selection">
|
||||
<ToggleAutoSizeMenuItem />
|
||||
<EditLinkMenuItem />
|
||||
<TldrawUiMenuGroup id="misc">
|
||||
<GroupMenuItem />
|
||||
<UngroupMenuItem />
|
||||
<EditLinkMenuItem />
|
||||
<ToggleAutoSizeMenuItem />
|
||||
<RemoveFrameMenuItem />
|
||||
<FitFrameToContentMenuItem />
|
||||
<ConvertToEmbedMenuItem />
|
||||
<ConvertToBookmarkMenuItem />
|
||||
<ToggleLockMenuItem />
|
||||
</TldrawUiMenuGroup>
|
||||
<EmbedsGroup />
|
||||
<TldrawUiMenuGroup id="modify">
|
||||
<ArrangeMenuSubmenu />
|
||||
<ReorderMenuSubmenu />
|
||||
|
@ -48,7 +50,9 @@ export function DefaultContextMenuContent() {
|
|||
</TldrawUiMenuGroup>
|
||||
<ClipboardMenuGroup />
|
||||
<ConversionsMenuGroup />
|
||||
<SetSelectionGroup />
|
||||
<TldrawUiMenuGroup id="select-all">
|
||||
<SelectAllMenuItem />
|
||||
</TldrawUiMenuGroup>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,20 +1,19 @@
|
|||
import { track, useEditor } from '@tldraw/editor'
|
||||
import { LANGUAGES, useEditor, useValue } from '@tldraw/editor'
|
||||
import { useUiEvents } from '../context/events'
|
||||
import { useLanguages } from '../hooks/useTranslation/useLanguages'
|
||||
import { TldrawUiMenuCheckboxItem } from './primitives/menus/TldrawUiMenuCheckboxItem'
|
||||
import { TldrawUiMenuGroup } from './primitives/menus/TldrawUiMenuGroup'
|
||||
import { TldrawUiMenuSubmenu } from './primitives/menus/TldrawUiMenuSubmenu'
|
||||
|
||||
/** @public */
|
||||
export const LanguageMenu = track(function LanguageMenu() {
|
||||
export function LanguageMenu() {
|
||||
const editor = useEditor()
|
||||
const trackEvent = useUiEvents()
|
||||
const { languages, currentLanguage } = useLanguages()
|
||||
const currentLanguage = useValue('locale', () => editor.user.getLocale(), [editor])
|
||||
|
||||
return (
|
||||
<TldrawUiMenuSubmenu id="help menu language" label="menu.language">
|
||||
<TldrawUiMenuGroup id="languages">
|
||||
{languages.map(({ locale, label }) => (
|
||||
{LANGUAGES.map(({ locale, label }) => (
|
||||
<TldrawUiMenuCheckboxItem
|
||||
id={`language-${locale}`}
|
||||
key={locale}
|
||||
|
@ -30,4 +29,4 @@ export const LanguageMenu = track(function LanguageMenu() {
|
|||
</TldrawUiMenuGroup>
|
||||
</TldrawUiMenuSubmenu>
|
||||
)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -5,12 +5,13 @@ import { LanguageMenu } from '../LanguageMenu'
|
|||
import {
|
||||
ClipboardMenuGroup,
|
||||
ConversionsMenuGroup,
|
||||
ConvertToBookmarkMenuItem,
|
||||
ConvertToEmbedMenuItem,
|
||||
EditLinkMenuItem,
|
||||
EmbedsGroup,
|
||||
FitFrameToContentMenuItem,
|
||||
GroupMenuItem,
|
||||
RemoveFrameMenuItem,
|
||||
SetSelectionGroup,
|
||||
SelectAllMenuItem,
|
||||
ToggleAutoSizeMenuItem,
|
||||
ToggleDarkModeItem,
|
||||
ToggleDebugModeItem,
|
||||
|
@ -38,8 +39,8 @@ export function DefaultMainMenuContent() {
|
|||
return (
|
||||
<>
|
||||
<EditSubmenu />
|
||||
<ShapeSubmenu />
|
||||
<ViewSubmenu />
|
||||
<ExportFileContentSubMenu />
|
||||
<ExtrasGroup />
|
||||
<PreferencesGroup />
|
||||
</>
|
||||
|
@ -78,28 +79,12 @@ export function EditSubmenu() {
|
|||
<TldrawUiMenuSubmenu id="edit" label="menu.edit" disabled={!selectToolActive}>
|
||||
<UndoRedoGroup />
|
||||
<ClipboardMenuGroup />
|
||||
<SetSelectionGroup />
|
||||
</TldrawUiMenuSubmenu>
|
||||
)
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export function ShapeSubmenu() {
|
||||
const editor = useEditor()
|
||||
|
||||
const selectToolActive = useValue(
|
||||
'isSelectToolActive',
|
||||
() => editor.getCurrentToolId() === 'select',
|
||||
[editor]
|
||||
)
|
||||
|
||||
return (
|
||||
<TldrawUiMenuSubmenu id="shape" label="menu.shape" disabled={!selectToolActive}>
|
||||
<ConversionsMenuGroup />
|
||||
<MultiShapeMenuGroup />
|
||||
<MiscMenuGroup />
|
||||
<EmbedsGroup />
|
||||
<LockGroup />
|
||||
<TldrawUiMenuGroup id="select-all">
|
||||
<SelectAllMenuItem />
|
||||
</TldrawUiMenuGroup>
|
||||
</TldrawUiMenuSubmenu>
|
||||
)
|
||||
}
|
||||
|
@ -108,8 +93,14 @@ export function ShapeSubmenu() {
|
|||
export function MiscMenuGroup() {
|
||||
return (
|
||||
<TldrawUiMenuGroup id="misc">
|
||||
<ToggleAutoSizeMenuItem />
|
||||
<GroupMenuItem />
|
||||
<UngroupMenuItem />
|
||||
<EditLinkMenuItem />
|
||||
<ToggleAutoSizeMenuItem />
|
||||
<RemoveFrameMenuItem />
|
||||
<FitFrameToContentMenuItem />
|
||||
<ConvertToEmbedMenuItem />
|
||||
<ConvertToBookmarkMenuItem />
|
||||
</TldrawUiMenuGroup>
|
||||
)
|
||||
}
|
||||
|
@ -124,18 +115,6 @@ export function LockGroup() {
|
|||
)
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export function MultiShapeMenuGroup() {
|
||||
return (
|
||||
<TldrawUiMenuGroup id="multi-shape">
|
||||
<GroupMenuItem />
|
||||
<UngroupMenuItem />
|
||||
<RemoveFrameMenuItem />
|
||||
<FitFrameToContentMenuItem />
|
||||
</TldrawUiMenuGroup>
|
||||
)
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export function UndoRedoGroup() {
|
||||
const actions = useActions()
|
||||
|
|
|
@ -31,36 +31,40 @@ import { TldrawUiMenuSubmenu } from './primitives/menus/TldrawUiMenuSubmenu'
|
|||
export function ToggleAutoSizeMenuItem() {
|
||||
const actions = useActions()
|
||||
const shouldDisplay = useShowAutoSizeToggle()
|
||||
|
||||
return <TldrawUiMenuItem {...actions['toggle-auto-size']} disabled={!shouldDisplay} />
|
||||
if (!shouldDisplay) return null
|
||||
return <TldrawUiMenuItem {...actions['toggle-auto-size']} />
|
||||
}
|
||||
/** @public */
|
||||
export function EditLinkMenuItem() {
|
||||
const actions = useActions()
|
||||
const shouldDisplay = useHasLinkShapeSelected()
|
||||
if (!shouldDisplay) return null
|
||||
|
||||
return <TldrawUiMenuItem {...actions['edit-link']} disabled={!shouldDisplay} />
|
||||
return <TldrawUiMenuItem {...actions['edit-link']} />
|
||||
}
|
||||
/** @public */
|
||||
export function DuplicateMenuItem() {
|
||||
const actions = useActions()
|
||||
const shouldDisplay = useUnlockedSelectedShapesCount(1)
|
||||
if (!shouldDisplay) return null
|
||||
|
||||
return <TldrawUiMenuItem {...actions['duplicate']} disabled={!shouldDisplay} />
|
||||
return <TldrawUiMenuItem {...actions['duplicate']} />
|
||||
}
|
||||
/** @public */
|
||||
export function GroupMenuItem() {
|
||||
const actions = useActions()
|
||||
const shouldDisplay = useAllowGroup()
|
||||
if (!shouldDisplay) return null
|
||||
|
||||
return <TldrawUiMenuItem {...actions['group']} disabled={!shouldDisplay} />
|
||||
return <TldrawUiMenuItem {...actions['group']} />
|
||||
}
|
||||
/** @public */
|
||||
export function UngroupMenuItem() {
|
||||
const actions = useActions()
|
||||
const shouldDisplay = useAllowUngroup()
|
||||
if (!shouldDisplay) return null
|
||||
|
||||
return <TldrawUiMenuItem {...actions['ungroup']} disabled={!shouldDisplay} />
|
||||
return <TldrawUiMenuItem {...actions['ungroup']} />
|
||||
}
|
||||
/** @public */
|
||||
export function RemoveFrameMenuItem() {
|
||||
|
@ -75,8 +79,9 @@ export function RemoveFrameMenuItem() {
|
|||
},
|
||||
[editor]
|
||||
)
|
||||
if (!shouldDisplay) return null
|
||||
|
||||
return <TldrawUiMenuItem {...actions['remove-frame']} disabled={!shouldDisplay} />
|
||||
return <TldrawUiMenuItem {...actions['remove-frame']} />
|
||||
}
|
||||
/** @public */
|
||||
export function FitFrameToContentMenuItem() {
|
||||
|
@ -94,8 +99,9 @@ export function FitFrameToContentMenuItem() {
|
|||
},
|
||||
[editor]
|
||||
)
|
||||
if (!shouldDisplay) return null
|
||||
|
||||
return <TldrawUiMenuItem {...actions['fit-frame-to-content']} disabled={!shouldDisplay} />
|
||||
return <TldrawUiMenuItem {...actions['fit-frame-to-content']} />
|
||||
}
|
||||
/** @public */
|
||||
export function ToggleLockMenuItem() {
|
||||
|
@ -104,8 +110,9 @@ export function ToggleLockMenuItem() {
|
|||
const shouldDisplay = useValue('selected shapes', () => editor.getSelectedShapes().length > 0, [
|
||||
editor,
|
||||
])
|
||||
if (!shouldDisplay) return null
|
||||
|
||||
return <TldrawUiMenuItem {...actions['toggle-lock']} disabled={!shouldDisplay} />
|
||||
return <TldrawUiMenuItem {...actions['toggle-lock']} />
|
||||
}
|
||||
/** @public */
|
||||
export function ToggleTransparentBgMenuItem() {
|
||||
|
@ -172,43 +179,51 @@ export function ZoomToSelectionMenuItem() {
|
|||
}
|
||||
|
||||
/* -------------------- Clipboard ------------------- */
|
||||
|
||||
/** @public */
|
||||
export function ClipboardMenuGroup() {
|
||||
return (
|
||||
<TldrawUiMenuGroup id="clipboard">
|
||||
<CutMenuItem />
|
||||
<CopyMenuItem />
|
||||
<PasteMenuItem />
|
||||
<DuplicateMenuItem />
|
||||
<DeleteMenuItem />
|
||||
</TldrawUiMenuGroup>
|
||||
)
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export function CopyAsMenuGroup() {
|
||||
const editor = useEditor()
|
||||
const actions = useActions()
|
||||
const atLeastOneShapeOnPage = useValue(
|
||||
'atLeastOneShapeOnPage',
|
||||
() => editor.getCurrentPageShapeIds().size > 0,
|
||||
[]
|
||||
[editor]
|
||||
)
|
||||
|
||||
return (
|
||||
<TldrawUiMenuGroup id="clipboard">
|
||||
<CutMenuItem />
|
||||
<CopyMenuItem />
|
||||
<TldrawUiMenuSubmenu
|
||||
id="copy-as"
|
||||
label="context-menu.copy-as"
|
||||
size="small"
|
||||
disabled={!atLeastOneShapeOnPage}
|
||||
>
|
||||
<TldrawUiMenuGroup id="copy-as-group">
|
||||
<TldrawUiMenuItem {...actions['copy-as-svg']} />
|
||||
{Boolean(window.navigator.clipboard?.write) && (
|
||||
<TldrawUiMenuItem {...actions['copy-as-png']} />
|
||||
)}
|
||||
<TldrawUiMenuItem {...actions['copy-as-json']} />
|
||||
</TldrawUiMenuGroup>
|
||||
<TldrawUiMenuGroup id="copy-as-bg">
|
||||
<ToggleTransparentBgMenuItem />
|
||||
</TldrawUiMenuGroup>
|
||||
</TldrawUiMenuSubmenu>
|
||||
<DuplicateMenuItem />
|
||||
<PasteMenuItem />
|
||||
<DeleteMenuItem />
|
||||
</TldrawUiMenuGroup>
|
||||
<TldrawUiMenuSubmenu
|
||||
id="copy-as"
|
||||
label="context-menu.copy-as"
|
||||
size="small"
|
||||
disabled={!atLeastOneShapeOnPage}
|
||||
>
|
||||
<TldrawUiMenuGroup id="copy-as-group">
|
||||
<TldrawUiMenuItem {...actions['copy-as-svg']} />
|
||||
{Boolean(window.navigator.clipboard?.write) && (
|
||||
<TldrawUiMenuItem {...actions['copy-as-png']} />
|
||||
)}
|
||||
<TldrawUiMenuItem {...actions['copy-as-json']} />
|
||||
</TldrawUiMenuGroup>
|
||||
<TldrawUiMenuGroup id="copy-as-bg">
|
||||
<ToggleTransparentBgMenuItem />
|
||||
</TldrawUiMenuGroup>
|
||||
</TldrawUiMenuSubmenu>
|
||||
)
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export function CutMenuItem() {
|
||||
const actions = useActions()
|
||||
|
@ -216,6 +231,7 @@ export function CutMenuItem() {
|
|||
|
||||
return <TldrawUiMenuItem {...actions['cut']} disabled={!shouldDisplay} />
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export function CopyMenuItem() {
|
||||
const actions = useActions()
|
||||
|
@ -223,6 +239,7 @@ export function CopyMenuItem() {
|
|||
|
||||
return <TldrawUiMenuItem {...actions['copy']} disabled={!shouldDisplay} />
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export function PasteMenuItem() {
|
||||
const actions = useActions()
|
||||
|
@ -232,19 +249,23 @@ export function PasteMenuItem() {
|
|||
}
|
||||
|
||||
/* ------------------- Conversions ------------------ */
|
||||
|
||||
/** @public */
|
||||
export function ConversionsMenuGroup() {
|
||||
const editor = useEditor()
|
||||
const actions = useActions()
|
||||
const shouldDisplay = useUnlockedSelectedShapesCount(1)
|
||||
const atLeastOneShapeOnPage = useValue(
|
||||
'atLeastOneShapeOnPage',
|
||||
() => editor.getCurrentPageShapeIds().size > 0,
|
||||
[editor]
|
||||
)
|
||||
|
||||
if (!atLeastOneShapeOnPage) return null
|
||||
|
||||
return (
|
||||
<TldrawUiMenuGroup id="conversions">
|
||||
<TldrawUiMenuSubmenu
|
||||
id="export-as"
|
||||
label="context-menu.export-as"
|
||||
size="small"
|
||||
disabled={!shouldDisplay}
|
||||
>
|
||||
<CopyAsMenuGroup />
|
||||
<TldrawUiMenuSubmenu id="export-as" label="context-menu.export-as" size="small">
|
||||
<TldrawUiMenuGroup id="export-as-group">
|
||||
<TldrawUiMenuItem {...actions['export-as-svg']} />
|
||||
<TldrawUiMenuItem {...actions['export-as-png']} />
|
||||
|
@ -260,7 +281,7 @@ export function ConversionsMenuGroup() {
|
|||
|
||||
/* ------------------ Set Selection ----------------- */
|
||||
/** @public */
|
||||
export function SetSelectionGroup() {
|
||||
export function SelectAllMenuItem() {
|
||||
const actions = useActions()
|
||||
const editor = useEditor()
|
||||
const atLeastOneShapeOnPage = useValue(
|
||||
|
@ -269,11 +290,7 @@ export function SetSelectionGroup() {
|
|||
[editor]
|
||||
)
|
||||
|
||||
return (
|
||||
<TldrawUiMenuGroup id="set-selection-group">
|
||||
<TldrawUiMenuItem {...actions['select-all']} disabled={!atLeastOneShapeOnPage} />
|
||||
</TldrawUiMenuGroup>
|
||||
)
|
||||
return <TldrawUiMenuItem {...actions['select-all']} disabled={!atLeastOneShapeOnPage} />
|
||||
}
|
||||
|
||||
/* ------------------ Delete Group ------------------ */
|
||||
|
@ -313,7 +330,7 @@ export function ArrangeMenuSubmenu() {
|
|||
<TldrawUiMenuItem {...actions['stretch-vertical']} />
|
||||
</TldrawUiMenuGroup>
|
||||
)}
|
||||
{onlyFlippableShapeSelected && (
|
||||
{(twoSelected || onlyFlippableShapeSelected) && (
|
||||
<TldrawUiMenuGroup id="flip">
|
||||
<TldrawUiMenuItem {...actions['flip-horizontal']} />
|
||||
<TldrawUiMenuItem {...actions['flip-vertical']} />
|
||||
|
@ -423,8 +440,9 @@ export function MoveToPageMenu() {
|
|||
</TldrawUiMenuSubmenu>
|
||||
)
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export function EmbedsGroup() {
|
||||
export function ConvertToBookmarkMenuItem() {
|
||||
const editor = useEditor()
|
||||
const actions = useActions()
|
||||
|
||||
|
@ -442,6 +460,15 @@ export function EmbedsGroup() {
|
|||
[editor]
|
||||
)
|
||||
|
||||
if (!oneEmbedSelected) return null
|
||||
return <TldrawUiMenuItem {...actions['convert-to-bookmark']} />
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export function ConvertToEmbedMenuItem() {
|
||||
const editor = useEditor()
|
||||
const actions = useActions()
|
||||
|
||||
const oneEmbeddableBookmarkSelected = useValue(
|
||||
'oneEmbeddableBookmarkSelected',
|
||||
() => {
|
||||
|
@ -457,17 +484,9 @@ export function EmbedsGroup() {
|
|||
[editor]
|
||||
)
|
||||
|
||||
return (
|
||||
<TldrawUiMenuGroup id="embeds">
|
||||
{/* XXX this doesn't exist?? */}
|
||||
{/* <TldrawUiMenuItem {...actions['edit-embed']} disabled={!oneEmbedSelected} /> */}
|
||||
<TldrawUiMenuItem {...actions['convert-to-bookmark']} disabled={!oneEmbedSelected} />
|
||||
<TldrawUiMenuItem
|
||||
{...actions['convert-to-embed']}
|
||||
disabled={!oneEmbeddableBookmarkSelected}
|
||||
/>
|
||||
</TldrawUiMenuGroup>
|
||||
)
|
||||
if (!oneEmbeddableBookmarkSelected) return null
|
||||
|
||||
return <TldrawUiMenuItem {...actions['convert-to-embed']} />
|
||||
}
|
||||
|
||||
/* ------------------- Preferences ------------------ */
|
||||
|
|
|
@ -174,8 +174,11 @@ export function ActionsProvider({ overrides, children }: ActionsProviderProps) {
|
|||
},
|
||||
readonlyOk: true,
|
||||
onSelect(source) {
|
||||
let ids = editor.getSelectedShapeIds()
|
||||
if (ids.length === 0) ids = Array.from(editor.getCurrentPageShapeIds().values())
|
||||
if (ids.length === 0) return
|
||||
trackEvent('export-as', { format: 'svg', source })
|
||||
exportAs(editor.getSelectedShapeIds(), 'svg', getExportName(editor, defaultDocumentName))
|
||||
exportAs(ids, 'svg', getExportName(editor, defaultDocumentName))
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -187,8 +190,11 @@ export function ActionsProvider({ overrides, children }: ActionsProviderProps) {
|
|||
},
|
||||
readonlyOk: true,
|
||||
onSelect(source) {
|
||||
let ids = editor.getSelectedShapeIds()
|
||||
if (ids.length === 0) ids = Array.from(editor.getCurrentPageShapeIds().values())
|
||||
if (ids.length === 0) return
|
||||
trackEvent('export-as', { format: 'png', source })
|
||||
exportAs(editor.getSelectedShapeIds(), 'png', getExportName(editor, defaultDocumentName))
|
||||
exportAs(ids, 'png', getExportName(editor, defaultDocumentName))
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -200,8 +206,11 @@ export function ActionsProvider({ overrides, children }: ActionsProviderProps) {
|
|||
},
|
||||
readonlyOk: true,
|
||||
onSelect(source) {
|
||||
let ids = editor.getSelectedShapeIds()
|
||||
if (ids.length === 0) ids = Array.from(editor.getCurrentPageShapeIds().values())
|
||||
if (ids.length === 0) return
|
||||
trackEvent('export-as', { format: 'json', source })
|
||||
exportAs(editor.getSelectedShapeIds(), 'json', getExportName(editor, defaultDocumentName))
|
||||
exportAs(ids, 'json', getExportName(editor, defaultDocumentName))
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -213,6 +222,9 @@ export function ActionsProvider({ overrides, children }: ActionsProviderProps) {
|
|||
},
|
||||
readonlyOk: true,
|
||||
onSelect(source) {
|
||||
let ids = editor.getSelectedShapeIds()
|
||||
if (ids.length === 0) ids = Array.from(editor.getCurrentPageShapeIds().values())
|
||||
if (ids.length === 0) return
|
||||
trackEvent('export-all-as', { format: 'svg', source })
|
||||
exportAs(
|
||||
Array.from(editor.getCurrentPageShapeIds()),
|
||||
|
@ -230,12 +242,10 @@ export function ActionsProvider({ overrides, children }: ActionsProviderProps) {
|
|||
},
|
||||
readonlyOk: true,
|
||||
onSelect(source) {
|
||||
const ids = Array.from(editor.getCurrentPageShapeIds().values())
|
||||
if (ids.length === 0) return
|
||||
trackEvent('export-all-as', { format: 'png', source })
|
||||
exportAs(
|
||||
Array.from(editor.getCurrentPageShapeIds()),
|
||||
'png',
|
||||
getExportName(editor, defaultDocumentName)
|
||||
)
|
||||
exportAs(ids, 'png', getExportName(editor, defaultDocumentName))
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -247,12 +257,10 @@ export function ActionsProvider({ overrides, children }: ActionsProviderProps) {
|
|||
},
|
||||
readonlyOk: true,
|
||||
onSelect(source) {
|
||||
const ids = Array.from(editor.getCurrentPageShapeIds().values())
|
||||
if (ids.length === 0) return
|
||||
trackEvent('export-all-as', { format: 'json', source })
|
||||
exportAs(
|
||||
Array.from(editor.getCurrentPageShapeIds()),
|
||||
'json',
|
||||
getExportName(editor, defaultDocumentName)
|
||||
)
|
||||
exportAs(ids, 'json', getExportName(editor, defaultDocumentName))
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -265,8 +273,11 @@ export function ActionsProvider({ overrides, children }: ActionsProviderProps) {
|
|||
kbd: '$!c',
|
||||
readonlyOk: true,
|
||||
onSelect(source) {
|
||||
let ids = editor.getSelectedShapeIds()
|
||||
if (ids.length === 0) ids = Array.from(editor.getCurrentPageShapeIds().values())
|
||||
if (ids.length === 0) return
|
||||
trackEvent('copy-as', { format: 'svg', source })
|
||||
copyAs(editor.getSelectedShapeIds(), 'svg')
|
||||
copyAs(ids, 'svg')
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -278,8 +289,11 @@ export function ActionsProvider({ overrides, children }: ActionsProviderProps) {
|
|||
},
|
||||
readonlyOk: true,
|
||||
onSelect(source) {
|
||||
let ids = editor.getSelectedShapeIds()
|
||||
if (ids.length === 0) ids = Array.from(editor.getCurrentPageShapeIds().values())
|
||||
if (ids.length === 0) return
|
||||
trackEvent('copy-as', { format: 'png', source })
|
||||
copyAs(editor.getSelectedShapeIds(), 'png')
|
||||
copyAs(ids, 'png')
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -291,8 +305,11 @@ export function ActionsProvider({ overrides, children }: ActionsProviderProps) {
|
|||
},
|
||||
readonlyOk: true,
|
||||
onSelect(source) {
|
||||
let ids = editor.getSelectedShapeIds()
|
||||
if (ids.length === 0) ids = Array.from(editor.getCurrentPageShapeIds().values())
|
||||
if (ids.length === 0) return
|
||||
trackEvent('copy-as', { format: 'json', source })
|
||||
copyAs(editor.getSelectedShapeIds(), 'json')
|
||||
copyAs(ids, 'json')
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
|
@ -188,16 +188,13 @@ export function useOnlyFlippableShape() {
|
|||
return useValue(
|
||||
'onlyFlippableShape',
|
||||
() => {
|
||||
const selectedShapes = editor.getSelectedShapes()
|
||||
const shape = editor.getOnlySelectedShape()
|
||||
return (
|
||||
selectedShapes.length === 1 &&
|
||||
selectedShapes.every(
|
||||
(shape) =>
|
||||
editor.isShapeOfType<TLGroupShape>(shape, 'group') ||
|
||||
editor.isShapeOfType<TLArrowShape>(shape, 'arrow') ||
|
||||
editor.isShapeOfType<TLLineShape>(shape, 'line') ||
|
||||
editor.isShapeOfType<TLDrawShape>(shape, 'draw')
|
||||
)
|
||||
shape &&
|
||||
(editor.isShapeOfType<TLGroupShape>(shape, 'group') ||
|
||||
editor.isShapeOfType<TLArrowShape>(shape, 'arrow') ||
|
||||
editor.isShapeOfType<TLLineShape>(shape, 'line') ||
|
||||
editor.isShapeOfType<TLDrawShape>(shape, 'draw'))
|
||||
)
|
||||
},
|
||||
[editor]
|
||||
|
|
|
@ -229,7 +229,6 @@ export type TLUiTranslationKey =
|
|||
| 'menu.title'
|
||||
| 'menu.copy-as'
|
||||
| 'menu.edit'
|
||||
| 'menu.shape'
|
||||
| 'menu.export-as'
|
||||
| 'menu.file'
|
||||
| 'menu.language'
|
||||
|
|
|
@ -41,11 +41,11 @@ export const DEFAULT_TRANSLATION = {
|
|||
'action.export-as-svg.short': 'SVG',
|
||||
'action.export-as-svg': 'Export as SVG',
|
||||
'action.export-all-as-json.short': 'JSON',
|
||||
'action.export-all-as-json': 'Export all as JSON',
|
||||
'action.export-all-as-json': 'Export as JSON',
|
||||
'action.export-all-as-png.short': 'PNG',
|
||||
'action.export-all-as-png': 'Export all as PNG',
|
||||
'action.export-all-as-png': 'Export as PNG',
|
||||
'action.export-all-as-svg.short': 'SVG',
|
||||
'action.export-all-as-svg': 'Export all as SVG',
|
||||
'action.export-all-as-svg': 'Export as SVG',
|
||||
'action.fit-frame-to-content': 'Fit to content',
|
||||
'action.flip-horizontal': 'Flip horizontally',
|
||||
'action.flip-vertical': 'Flip vertically',
|
||||
|
@ -229,7 +229,6 @@ export const DEFAULT_TRANSLATION = {
|
|||
'menu.title': 'Menu',
|
||||
'menu.copy-as': 'Copy as',
|
||||
'menu.edit': 'Edit',
|
||||
'menu.shape': 'Shape',
|
||||
'menu.export-as': 'Export as',
|
||||
'menu.file': 'File',
|
||||
'menu.language': 'Language',
|
||||
|
@ -238,7 +237,7 @@ export const DEFAULT_TRANSLATION = {
|
|||
'context-menu.arrange': 'Arrange',
|
||||
'context-menu.copy-as': 'Copy as',
|
||||
'context-menu.export-as': 'Export as',
|
||||
'context-menu.export-all-as': 'Export all as',
|
||||
'context-menu.export-all-as': 'Export',
|
||||
'context-menu.move-to-page': 'Move to page',
|
||||
'context-menu.reorder': 'Reorder',
|
||||
'page-menu.title': 'Pages',
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
import { LANGUAGES, TLLanguage, useEditor } from '@tldraw/editor'
|
||||
|
||||
/** @internal */
|
||||
export function useLanguages() {
|
||||
const editor = useEditor()
|
||||
return {
|
||||
languages: LANGUAGES as readonly TLLanguage[],
|
||||
currentLanguage: editor.user.getLocale(),
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue