menu: rework File menu / ensure Export menu is present (#2783)

<img width="428" alt="Screenshot 2024-02-16 at 16 46 28"
src="https://github.com/tldraw/tldraw/assets/469604/334cd0db-d9d5-4993-8012-c6985173edfb">


- re-orders to be the normative New / Open / Save order — we shouldn't
be messing with this conventional ordering
- removes the "Don't ask again" from New/Open dialogs because they're
non-undoable and not what _anybody_ should ever select. we shouldn't
offer users a loaded footgun! :P
- makes File menu be part of the default menu — it's presence is
glaringly missing for regular development
- along with that, make the pieces of that menu available as lego pieces
to use - it can't just be `DefaultMainMenuContent`, all or nothing,
forcing downstream users to import everything from scratch
- finally, adds the Export menu as initially intended by this PR!

@steveruizok let's discuss if you have some notes on this and we can
talk about the shape of things here.

### Change Type

- [x] `patch` — Bug fix

### Release Notes

- Composable UI: makes File items be more granularly accessible / usable
- Menu: show Export under the File menu.
This commit is contained in:
Mime Čuvalo 2024-02-26 15:01:56 +00:00 committed by GitHub
parent f19b12c42e
commit fb852459db
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 441 additions and 175 deletions

View file

@ -1,4 +1,5 @@
import {
ExportFileContentSubMenu,
TldrawUiMenuGroup,
TldrawUiMenuItem,
TldrawUiMenuSubmenu,
@ -17,9 +18,10 @@ export function LocalFileMenu() {
return (
<TldrawUiMenuSubmenu id="file" label="menu.file">
<TldrawUiMenuGroup id="file-actions">
<TldrawUiMenuItem {...actions[SAVE_FILE_COPY_ACTION]} />
<TldrawUiMenuItem {...actions[OPEN_FILE_ACTION]} />
<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]} />
@ -35,6 +37,7 @@ 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]} />

View file

@ -6,12 +6,16 @@ import {
DefaultKeyboardShortcutsDialog,
DefaultKeyboardShortcutsDialogContent,
DefaultMainMenu,
DefaultMainMenuContent,
EditSubmenu,
Editor,
ExtrasGroup,
ObjectSubmenu,
PreferencesGroup,
TLComponents,
Tldraw,
TldrawUiMenuGroup,
TldrawUiMenuItem,
ViewSubmenu,
useActions,
} from '@tldraw/tldraw'
import { useCallback } from 'react'
@ -44,7 +48,11 @@ const components: TLComponents = {
MainMenu: () => (
<DefaultMainMenu>
<LocalFileMenu />
<DefaultMainMenuContent />
<EditSubmenu />
<ObjectSubmenu />
<ViewSubmenu />
<ExtrasGroup />
<PreferencesGroup />
<Links />
</DefaultMainMenu>
),

View file

@ -6,13 +6,17 @@ import {
DefaultKeyboardShortcutsDialog,
DefaultKeyboardShortcutsDialogContent,
DefaultMainMenu,
DefaultMainMenuContent,
EditSubmenu,
Editor,
ExtrasGroup,
ObjectSubmenu,
OfflineIndicator,
PreferencesGroup,
TLComponents,
Tldraw,
TldrawUiMenuGroup,
TldrawUiMenuItem,
ViewSubmenu,
atom,
debugFlags,
lns,
@ -66,7 +70,11 @@ const components: TLComponents = {
MainMenu: () => (
<DefaultMainMenu>
<MultiplayerFileMenu />
<DefaultMainMenuContent />
<EditSubmenu />
<ObjectSubmenu />
<ViewSubmenu />
<ExtrasGroup />
<PreferencesGroup />
<Links />
</DefaultMainMenu>
),

View file

@ -1,7 +1,6 @@
import {
TLUiDialogsContextType,
TldrawUiButton,
TldrawUiButtonCheck,
TldrawUiButtonLabel,
TldrawUiDialogBody,
TldrawUiDialogCloseButton,
@ -10,34 +9,29 @@ import {
TldrawUiDialogTitle,
useTranslation,
} from '@tldraw/tldraw'
import { useState } from 'react'
import { userPreferences } from './userPreferences'
export async function shouldClearDocument(addDialog: TLUiDialogsContextType['addDialog']) {
if (userPreferences.showFileClearWarning.get()) {
const shouldContinue = await new Promise<boolean>((resolve) => {
addDialog({
component: ({ onClose }) => (
<ConfirmClearDialog
onCancel={() => {
resolve(false)
onClose()
}}
onContinue={() => {
resolve(true)
onClose()
}}
/>
),
onClose: () => {
resolve(false)
},
})
const shouldContinue = await new Promise<boolean>((resolve) => {
addDialog({
component: ({ onClose }) => (
<ConfirmClearDialog
onCancel={() => {
resolve(false)
onClose()
}}
onContinue={() => {
resolve(true)
onClose()
}}
/>
),
onClose: () => {
resolve(false)
},
})
})
return shouldContinue
}
return true
return shouldContinue
}
function ConfirmClearDialog({
@ -48,7 +42,6 @@ function ConfirmClearDialog({
onContinue: () => void
}) {
const msg = useTranslation()
const [dontShowAgain, setDontShowAgain] = useState(false)
return (
<>
<TldrawUiDialogHeader>
@ -59,28 +52,10 @@ function ConfirmClearDialog({
{msg('file-system.confirm-clear.description')}
</TldrawUiDialogBody>
<TldrawUiDialogFooter className="tlui-dialog__footer__actions">
<TldrawUiButton
type="normal"
onClick={() => setDontShowAgain(!dontShowAgain)}
style={{ marginRight: 'auto' }}
>
<TldrawUiButtonCheck checked={dontShowAgain} />
<TldrawUiButtonLabel>
{msg('file-system.confirm-clear.dont-show-again')}
</TldrawUiButtonLabel>
</TldrawUiButton>
<TldrawUiButton type="normal" onClick={onCancel}>
<TldrawUiButtonLabel>{msg('file-system.confirm-clear.cancel')}</TldrawUiButtonLabel>
</TldrawUiButton>
<TldrawUiButton
type="primary"
onClick={async () => {
if (dontShowAgain) {
userPreferences.showFileClearWarning.set(false)
}
onContinue()
}}
>
<TldrawUiButton type="primary" onClick={async () => onContinue()}>
<TldrawUiButtonLabel>{msg('file-system.confirm-clear.continue')}</TldrawUiButtonLabel>
</TldrawUiButton>
</TldrawUiDialogFooter>

View file

@ -1,7 +1,6 @@
import {
TLUiDialogsContextType,
TldrawUiButton,
TldrawUiButtonCheck,
TldrawUiButtonLabel,
TldrawUiDialogBody,
TldrawUiDialogCloseButton,
@ -10,34 +9,30 @@ import {
TldrawUiDialogTitle,
useTranslation,
} from '@tldraw/tldraw'
import { useState } from 'react'
import { userPreferences } from './userPreferences'
/** @public */
export async function shouldOverrideDocument(addDialog: TLUiDialogsContextType['addDialog']) {
if (userPreferences.showFileOpenWarning.get()) {
const shouldContinue = await new Promise<boolean>((resolve) => {
addDialog({
component: ({ onClose }) => (
<ConfirmOpenDialog
onCancel={() => {
resolve(false)
onClose()
}}
onContinue={() => {
resolve(true)
onClose()
}}
/>
),
onClose: () => {
resolve(false)
},
})
const shouldContinue = await new Promise<boolean>((resolve) => {
addDialog({
component: ({ onClose }) => (
<ConfirmOpenDialog
onCancel={() => {
resolve(false)
onClose()
}}
onContinue={() => {
resolve(true)
onClose()
}}
/>
),
onClose: () => {
resolve(false)
},
})
})
return shouldContinue
}
return true
return shouldContinue
}
function ConfirmOpenDialog({
@ -48,7 +43,6 @@ function ConfirmOpenDialog({
onContinue: () => void
}) {
const msg = useTranslation()
const [dontShowAgain, setDontShowAgain] = useState(false)
return (
<>
<TldrawUiDialogHeader>
@ -59,28 +53,10 @@ function ConfirmOpenDialog({
{msg('file-system.confirm-open.description')}
</TldrawUiDialogBody>
<TldrawUiDialogFooter className="tlui-dialog__footer__actions">
<TldrawUiButton
type="normal"
onClick={() => setDontShowAgain(!dontShowAgain)}
style={{ marginRight: 'auto' }}
>
<TldrawUiButtonCheck checked={dontShowAgain} />
<TldrawUiButtonLabel>
{msg('file-system.confirm-open.dont-show-again')}
</TldrawUiButtonLabel>
</TldrawUiButton>
<TldrawUiButton type="normal" onClick={onCancel}>
<TldrawUiButtonLabel>{msg('file-system.confirm-open.cancel')}</TldrawUiButtonLabel>
</TldrawUiButton>
<TldrawUiButton
type="primary"
onClick={async () => {
if (dontShowAgain) {
userPreferences.showFileOpenWarning.set(false)
}
onContinue()
}}
>
<TldrawUiButton type="primary" onClick={async () => onContinue()}>
<TldrawUiButtonLabel>{msg('file-system.confirm-open.open')}</TldrawUiButtonLabel>
</TldrawUiButton>
</TldrawUiDialogFooter>

View file

@ -215,6 +215,7 @@
"menu.title": "Menu",
"menu.copy-as": "Copy as",
"menu.edit": "Edit",
"menu.object": "Object",
"menu.export-as": "Export as",
"menu.file": "File",
"menu.language": "Language",

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -180,7 +180,15 @@ export {
DefaultMainMenu,
type TLUiMainMenuProps,
} from './lib/ui/components/MainMenu/DefaultMainMenu'
export { DefaultMainMenuContent } from './lib/ui/components/MainMenu/DefaultMainMenuContent'
export {
DefaultMainMenuContent,
EditSubmenu,
ExportFileContentSubMenu,
ExtrasGroup,
ObjectSubmenu,
PreferencesGroup,
ViewSubmenu,
} from './lib/ui/components/MainMenu/DefaultMainMenuContent'
export {
DefaultQuickActions,

View file

@ -3,8 +3,6 @@ import {
ArrangeMenuSubmenu,
ClipboardMenuGroup,
ConversionsMenuGroup,
DeleteGroup,
DuplicateMenuItem,
EditLinkMenuItem,
EmbedsGroup,
FitFrameToContentMenuItem,
@ -36,7 +34,6 @@ export function DefaultContextMenuContent() {
<TldrawUiMenuGroup id="selection">
<ToggleAutoSizeMenuItem />
<EditLinkMenuItem />
<DuplicateMenuItem />
<GroupMenuItem />
<UngroupMenuItem />
<RemoveFrameMenuItem />
@ -52,7 +49,6 @@ export function DefaultContextMenuContent() {
<ClipboardMenuGroup />
<ConversionsMenuGroup />
<SetSelectionGroup />
<DeleteGroup />
</>
)
}

View file

@ -5,8 +5,6 @@ import { LanguageMenu } from '../LanguageMenu'
import {
ClipboardMenuGroup,
ConversionsMenuGroup,
DeleteGroup,
DuplicateMenuItem,
EditLinkMenuItem,
EmbedsGroup,
FitFrameToContentMenuItem,
@ -23,6 +21,7 @@ import {
ToggleReduceMotionItem,
ToggleSnapModeItem,
ToggleToolLockItem,
ToggleTransparentBgMenuItem,
UngroupMenuItem,
UnlockAllMenuItem,
ZoomTo100MenuItem,
@ -38,6 +37,7 @@ export function DefaultMainMenuContent() {
return (
<>
<EditSubmenu />
<ObjectSubmenu />
<ViewSubmenu />
<ExtrasGroup />
<PreferencesGroup />
@ -45,7 +45,26 @@ export function DefaultMainMenuContent() {
)
}
function EditSubmenu() {
/** @public */
export function ExportFileContentSubMenu() {
const actions = useActions()
return (
<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']} />
<TldrawUiMenuItem {...actions['export-as-json']} />
</TldrawUiMenuGroup>
<TldrawUiMenuGroup id="export-as-bg">
<ToggleTransparentBgMenuItem />
</TldrawUiMenuGroup>
</TldrawUiMenuSubmenu>
)
}
/** @public */
export function EditSubmenu() {
const editor = useEditor()
const selectToolActive = useValue(
@ -54,38 +73,70 @@ function EditSubmenu() {
[editor]
)
if (!selectToolActive) return null
return (
<TldrawUiMenuSubmenu id="edit" label="menu.edit">
<TldrawUiMenuSubmenu id="edit" label="menu.edit" disabled={!selectToolActive}>
<UndoRedoGroup />
<ClipboardMenuGroup />
<ConversionsMenuGroup />
<SetSelectionGroup />
<SelectionMenuGroup />
<EmbedsGroup />
<DeleteGroup />
</TldrawUiMenuSubmenu>
)
}
function SelectionMenuGroup() {
/** @public */
export function ObjectSubmenu() {
const editor = useEditor()
const selectToolActive = useValue(
'isSelectToolActive',
() => editor.getCurrentToolId() === 'select',
[editor]
)
return (
<TldrawUiMenuGroup id="selection">
<TldrawUiMenuSubmenu id="object" label="menu.object" disabled={!selectToolActive}>
<ConversionsMenuGroup />
<MultiShapeMenuGroup />
<MiscMenuGroup />
<EmbedsGroup />
<LockGroup />
</TldrawUiMenuSubmenu>
)
}
/** @public */
export function MiscMenuGroup() {
return (
<TldrawUiMenuGroup id="misc">
<ToggleAutoSizeMenuItem />
<EditLinkMenuItem />
<DuplicateMenuItem />
<GroupMenuItem />
<UngroupMenuItem />
<RemoveFrameMenuItem />
<FitFrameToContentMenuItem />
</TldrawUiMenuGroup>
)
}
/** @public */
export function LockGroup() {
return (
<TldrawUiMenuGroup id="lock">
<ToggleLockMenuItem />
<UnlockAllMenuItem />
</TldrawUiMenuGroup>
)
}
function UndoRedoGroup() {
/** @public */
export function MultiShapeMenuGroup() {
return (
<TldrawUiMenuGroup id="multi-shape">
<GroupMenuItem />
<UngroupMenuItem />
<RemoveFrameMenuItem />
<FitFrameToContentMenuItem />
</TldrawUiMenuGroup>
)
}
/** @public */
export function UndoRedoGroup() {
const actions = useActions()
const canUndo = useCanUndo()
const canRedo = useCanRedo()
@ -97,7 +148,8 @@ function UndoRedoGroup() {
)
}
function ViewSubmenu() {
/** @public */
export function ViewSubmenu() {
const actions = useActions()
return (
<TldrawUiMenuSubmenu id="view" label="menu.view">
@ -112,7 +164,8 @@ function ViewSubmenu() {
)
}
function ExtrasGroup() {
/** @public */
export function ExtrasGroup() {
const actions = useActions()
return (
<TldrawUiMenuGroup id="extras">
@ -124,7 +177,8 @@ function ExtrasGroup() {
/* ------------------- Preferences ------------------ */
function PreferencesGroup() {
/** @public */
export function PreferencesGroup() {
return (
<TldrawUiMenuGroup id="preferences">
<TldrawUiMenuSubmenu id="preferences" label="menu.preferences">

View file

@ -31,36 +31,36 @@ import { TldrawUiMenuSubmenu } from './primitives/menus/TldrawUiMenuSubmenu'
export function ToggleAutoSizeMenuItem() {
const actions = useActions()
const shouldDisplay = useShowAutoSizeToggle()
if (!shouldDisplay) return null
return <TldrawUiMenuItem {...actions['toggle-auto-size']} />
return <TldrawUiMenuItem {...actions['toggle-auto-size']} disabled={!shouldDisplay} />
}
export function EditLinkMenuItem() {
const actions = useActions()
const shouldDisplay = useHasLinkShapeSelected()
if (!shouldDisplay) return null
return <TldrawUiMenuItem {...actions['edit-link']} />
return <TldrawUiMenuItem {...actions['edit-link']} disabled={!shouldDisplay} />
}
export function DuplicateMenuItem() {
const actions = useActions()
const shouldDisplay = useUnlockedSelectedShapesCount(1)
if (!shouldDisplay) return null
return <TldrawUiMenuItem {...actions['duplicate']} />
return <TldrawUiMenuItem {...actions['duplicate']} disabled={!shouldDisplay} />
}
export function GroupMenuItem() {
const actions = useActions()
const shouldDisplay = useAllowGroup()
if (!shouldDisplay) return null
return <TldrawUiMenuItem {...actions['group']} />
return <TldrawUiMenuItem {...actions['group']} disabled={!shouldDisplay} />
}
export function UngroupMenuItem() {
const actions = useActions()
const shouldDisplay = useAllowUngroup()
if (!shouldDisplay) return null
return <TldrawUiMenuItem {...actions['ungroup']} />
return <TldrawUiMenuItem {...actions['ungroup']} disabled={!shouldDisplay} />
}
export function RemoveFrameMenuItem() {
@ -75,8 +75,8 @@ export function RemoveFrameMenuItem() {
},
[editor]
)
if (!shouldDisplay) return null
return <TldrawUiMenuItem {...actions['remove-frame']} />
return <TldrawUiMenuItem {...actions['remove-frame']} disabled={!shouldDisplay} />
}
export function FitFrameToContentMenuItem() {
@ -94,8 +94,8 @@ export function FitFrameToContentMenuItem() {
},
[editor]
)
if (!shouldDisplay) return null
return <TldrawUiMenuItem {...actions['fit-frame-to-content']} />
return <TldrawUiMenuItem {...actions['fit-frame-to-content']} disabled={!shouldDisplay} />
}
export function ToggleLockMenuItem() {
@ -104,8 +104,8 @@ export function ToggleLockMenuItem() {
const shouldDisplay = useValue('selected shapes', () => editor.getSelectedShapes().length > 0, [
editor,
])
if (!shouldDisplay) return null
return <TldrawUiMenuItem {...actions['toggle-lock']} />
return <TldrawUiMenuItem {...actions['toggle-lock']} disabled={!shouldDisplay} />
}
export function ToggleTransparentBgMenuItem() {
@ -125,8 +125,8 @@ export function UnlockAllMenuItem() {
const shouldDisplay = useValue('any shapes', () => editor.getCurrentPageShapeIds().size > 0, [
editor,
])
if (!shouldDisplay) return null
return <TldrawUiMenuItem {...actions['unlock-all']} />
return <TldrawUiMenuItem {...actions['unlock-all']} disabled={!shouldDisplay} />
}
/* ---------------------- Zoom ---------------------- */
@ -174,11 +174,38 @@ export function ZoomToSelectionMenuItem() {
/* -------------------- Clipboard ------------------- */
export function ClipboardMenuGroup() {
const editor = useEditor()
const actions = useActions()
const atLeastOneShapeOnPage = useValue(
'atLeastOneShapeOnPage',
() => editor.getCurrentPageShapeIds().size > 0,
[]
)
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>
)
}
@ -186,22 +213,22 @@ export function ClipboardMenuGroup() {
export function CutMenuItem() {
const actions = useActions()
const shouldDisplay = useUnlockedSelectedShapesCount(1)
if (!shouldDisplay) return null
return <TldrawUiMenuItem {...actions['cut']} />
return <TldrawUiMenuItem {...actions['cut']} disabled={!shouldDisplay} />
}
export function CopyMenuItem() {
const actions = useActions()
const shouldDisplay = useAnySelectedShapesCount(1)
if (!shouldDisplay) return null
return <TldrawUiMenuItem {...actions['copy']} />
return <TldrawUiMenuItem {...actions['copy']} disabled={!shouldDisplay} />
}
export function PasteMenuItem() {
const actions = useActions()
const shouldDisplay = showMenuPaste
if (!shouldDisplay) return null
return <TldrawUiMenuItem {...actions['paste']} />
return <TldrawUiMenuItem {...actions['paste']} disabled={!shouldDisplay} />
}
/* ------------------- Conversions ------------------ */
@ -214,23 +241,15 @@ export function ConversionsMenuGroup() {
() => editor.getCurrentPageShapeIds().size > 0,
[]
)
if (!atLeastOneShapeOnPage) return null
return (
<TldrawUiMenuGroup id="conversions">
<TldrawUiMenuSubmenu id="copy-as" label="context-menu.copy-as" size="small">
<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>
<TldrawUiMenuSubmenu id="export-as" label="context-menu.export-as" size="small">
<TldrawUiMenuSubmenu
id="export-as"
label="context-menu.export-as"
size="small"
disabled={!atLeastOneShapeOnPage}
>
<TldrawUiMenuGroup id="export-as-group">
<TldrawUiMenuItem {...actions['export-as-svg']} />
<TldrawUiMenuItem {...actions['export-as-png']} />
@ -254,25 +273,21 @@ export function SetSelectionGroup() {
() => editor.getCurrentPageShapeIds().size > 0,
[editor]
)
if (!atLeastOneShapeOnPage) return null
return (
<TldrawUiMenuGroup id="set-selection-group">
<TldrawUiMenuItem {...actions['select-all']} />
<TldrawUiMenuItem {...actions['select-all']} disabled={!atLeastOneShapeOnPage} />
</TldrawUiMenuGroup>
)
}
/* ------------------ Delete Group ------------------ */
export function DeleteGroup() {
export function DeleteMenuItem() {
const actions = useActions()
const oneSelected = useUnlockedSelectedShapesCount(1)
if (!oneSelected) return null
return (
<TldrawUiMenuGroup id="delete-group">
<TldrawUiMenuItem {...actions['delete']} />
</TldrawUiMenuGroup>
)
return <TldrawUiMenuItem {...actions['delete']} disabled={!oneSelected} />
}
/* --------------------- Modify --------------------- */
@ -449,9 +464,13 @@ export function EmbedsGroup() {
return (
<TldrawUiMenuGroup id="embeds">
{oneEmbedSelected && <TldrawUiMenuItem {...actions['edit-embed']} />}
{oneEmbedSelected && <TldrawUiMenuItem {...actions['convert-to-bookmark']} />}
{oneEmbeddableBookmarkSelected && <TldrawUiMenuItem {...actions['convert-to-embed']} />}
{/* 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>
)
}

View file

@ -120,7 +120,7 @@ export function TldrawUiDropdownMenuSubTrigger({
disabled,
}: TLUiDropdownMenuSubTriggerProps) {
return (
<_DropdownMenu.SubTrigger dir="ltr" asChild>
<_DropdownMenu.SubTrigger dir="ltr" asChild disabled={disabled}>
<TldrawUiButton
type="menu"
className="tlui-menu__submenu__trigger"

View file

@ -219,6 +219,7 @@ export type TLUiTranslationKey =
| 'menu.title'
| 'menu.copy-as'
| 'menu.edit'
| 'menu.object'
| 'menu.export-as'
| 'menu.file'
| 'menu.language'

View file

@ -219,6 +219,7 @@ export const DEFAULT_TRANSLATION = {
'menu.title': 'Menu',
'menu.copy-as': 'Copy as',
'menu.edit': 'Edit',
'menu.object': 'Object',
'menu.export-as': 'Export as',
'menu.file': 'File',
'menu.language': 'Language',