UI components round two (#2847)
This PR: - replaces the `shareZone` prop with `SharePanel` component - replaces the `topZone` prop with `TopPanel` components - replaces the `Button` component with `TldrawUiButton` and subcomponents - adds `TldrawUi` prefix to our primitives - fixes a couple of bugs with the components ### Change Type - [x] `major` — Breaking change
This commit is contained in:
parent
5d87804a76
commit
7ece89a357
83 changed files with 3122 additions and 2826 deletions
|
@ -67,6 +67,13 @@ const components: TLComponents = {
|
||||||
</DefaultDebugMenu>
|
</DefaultDebugMenu>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
SharePanel: () => {
|
||||||
|
return (
|
||||||
|
<div className="tlui-share-zone" draggable={false}>
|
||||||
|
<ShareMenu />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export function LocalEditor() {
|
export function LocalEditor() {
|
||||||
|
@ -88,11 +95,6 @@ export function LocalEditor() {
|
||||||
overrides={[sharingUiOverrides, fileSystemUiOverrides]}
|
overrides={[sharingUiOverrides, fileSystemUiOverrides]}
|
||||||
onUiEvent={handleUiEvent}
|
onUiEvent={handleUiEvent}
|
||||||
components={components}
|
components={components}
|
||||||
shareZone={
|
|
||||||
<div className="tlui-share-zone" draggable={false}>
|
|
||||||
<ShareMenu />
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
inferDarkMode
|
inferDarkMode
|
||||||
>
|
>
|
||||||
<LocalMigration />
|
<LocalMigration />
|
||||||
|
|
|
@ -13,8 +13,10 @@ import {
|
||||||
Tldraw,
|
Tldraw,
|
||||||
TldrawUiMenuGroup,
|
TldrawUiMenuGroup,
|
||||||
TldrawUiMenuItem,
|
TldrawUiMenuItem,
|
||||||
|
atom,
|
||||||
lns,
|
lns,
|
||||||
useActions,
|
useActions,
|
||||||
|
useValue,
|
||||||
} from '@tldraw/tldraw'
|
} from '@tldraw/tldraw'
|
||||||
import { useCallback, useEffect } from 'react'
|
import { useCallback, useEffect } from 'react'
|
||||||
import { useRemoteSyncClient } from '../hooks/useRemoteSyncClient'
|
import { useRemoteSyncClient } from '../hooks/useRemoteSyncClient'
|
||||||
|
@ -39,6 +41,8 @@ import { SneakyOnDropOverride } from './SneakyOnDropOverride'
|
||||||
import { StoreErrorScreen } from './StoreErrorScreen'
|
import { StoreErrorScreen } from './StoreErrorScreen'
|
||||||
import { ThemeUpdater } from './ThemeUpdater/ThemeUpdater'
|
import { ThemeUpdater } from './ThemeUpdater/ThemeUpdater'
|
||||||
|
|
||||||
|
const shittyOfflineAtom = atom('shitty offline atom', false)
|
||||||
|
|
||||||
const components: TLComponents = {
|
const components: TLComponents = {
|
||||||
ErrorFallback: ({ error }) => {
|
ErrorFallback: ({ error }) => {
|
||||||
throw error
|
throw error
|
||||||
|
@ -78,6 +82,19 @@ const components: TLComponents = {
|
||||||
</DefaultKeyboardShortcutsDialog>
|
</DefaultKeyboardShortcutsDialog>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
TopPanel: () => {
|
||||||
|
const isOffline = useValue('offline', () => shittyOfflineAtom.get(), [])
|
||||||
|
if (!isOffline) return null
|
||||||
|
return <OfflineIndicator />
|
||||||
|
},
|
||||||
|
SharePanel: () => {
|
||||||
|
return (
|
||||||
|
<div className="tlui-share-zone" draggable={false}>
|
||||||
|
<PeopleMenu />
|
||||||
|
<ShareMenu />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export function MultiplayerEditor({
|
export function MultiplayerEditor({
|
||||||
|
@ -96,6 +113,12 @@ export function MultiplayerEditor({
|
||||||
roomId,
|
roomId,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const isOffline =
|
||||||
|
storeWithStatus.status === 'synced-remote' && storeWithStatus.connectionStatus === 'offline'
|
||||||
|
useEffect(() => {
|
||||||
|
shittyOfflineAtom.set(isOffline)
|
||||||
|
}, [isOffline])
|
||||||
|
|
||||||
const isEmbedded = useIsEmbedded(roomSlug)
|
const isEmbedded = useIsEmbedded(roomSlug)
|
||||||
const sharingUiOverrides = useSharing()
|
const sharingUiOverrides = useSharing()
|
||||||
const fileSystemUiOverrides = useFileSystem({ isMultiplayer: true })
|
const fileSystemUiOverrides = useFileSystem({ isMultiplayer: true })
|
||||||
|
@ -118,9 +141,6 @@ export function MultiplayerEditor({
|
||||||
return <EmbeddedInIFrameWarning />
|
return <EmbeddedInIFrameWarning />
|
||||||
}
|
}
|
||||||
|
|
||||||
const isOffline =
|
|
||||||
storeWithStatus.status === 'synced-remote' && storeWithStatus.connectionStatus === 'offline'
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="tldraw__editor">
|
<div className="tldraw__editor">
|
||||||
<Tldraw
|
<Tldraw
|
||||||
|
@ -131,13 +151,6 @@ export function MultiplayerEditor({
|
||||||
initialState={isReadOnly ? 'hand' : 'select'}
|
initialState={isReadOnly ? 'hand' : 'select'}
|
||||||
onUiEvent={handleUiEvent}
|
onUiEvent={handleUiEvent}
|
||||||
components={components}
|
components={components}
|
||||||
topZone={isOffline && <OfflineIndicator />}
|
|
||||||
shareZone={
|
|
||||||
<div className="tlui-share-zone" draggable={false}>
|
|
||||||
<PeopleMenu />
|
|
||||||
<ShareMenu />
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
autoFocus
|
autoFocus
|
||||||
inferDarkMode
|
inferDarkMode
|
||||||
>
|
>
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
import * as Popover from '@radix-ui/react-popover'
|
import * as Popover from '@radix-ui/react-popover'
|
||||||
import {
|
import {
|
||||||
Button,
|
TldrawUiButton,
|
||||||
|
TldrawUiButtonIcon,
|
||||||
|
TldrawUiButtonLabel,
|
||||||
track,
|
track,
|
||||||
useContainer,
|
useContainer,
|
||||||
useEditor,
|
useEditor,
|
||||||
|
@ -73,13 +75,16 @@ export const PeopleMenu = track(function PeopleMenu({
|
||||||
)}
|
)}
|
||||||
{!hideShareMenu && (
|
{!hideShareMenu && (
|
||||||
<div className="tlui-people-menu__section">
|
<div className="tlui-people-menu__section">
|
||||||
<Button
|
<TldrawUiButton
|
||||||
type="menu"
|
type="menu"
|
||||||
data-wd="people-menu.invite"
|
data-testid="people-menu.invite"
|
||||||
label={'people-menu.invite'}
|
|
||||||
icon="plus"
|
|
||||||
onClick={() => editor.addOpenMenu('share menu')}
|
onClick={() => editor.addOpenMenu('share menu')}
|
||||||
/>
|
>
|
||||||
|
<TldrawUiButtonLabel>
|
||||||
|
{msg('people-menu.invite')}
|
||||||
|
<TldrawUiButtonIcon icon="plus" />
|
||||||
|
</TldrawUiButtonLabel>
|
||||||
|
</TldrawUiButton>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import {
|
import {
|
||||||
Button,
|
TldrawUiButton,
|
||||||
Icon,
|
TldrawUiButtonIcon,
|
||||||
|
TldrawUiIcon,
|
||||||
track,
|
track,
|
||||||
useEditor,
|
useEditor,
|
||||||
usePresence,
|
usePresence,
|
||||||
|
@ -34,16 +35,16 @@ export const PeopleMenuItem = track(function PeopleMenuItem({ userId }: { userId
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="tlui-people-menu__item tlui-buttons__horizontal">
|
<div className="tlui-people-menu__item tlui-buttons__horizontal">
|
||||||
<Button
|
<TldrawUiButton
|
||||||
type="menu"
|
type="menu"
|
||||||
className="tlui-people-menu__item__button"
|
className="tlui-people-menu__item__button"
|
||||||
onClick={() => editor.animateToUser(userId)}
|
onClick={() => editor.animateToUser(userId)}
|
||||||
onDoubleClick={handleFollowClick}
|
onDoubleClick={handleFollowClick}
|
||||||
>
|
>
|
||||||
<Icon icon="color" color={presence.color} />
|
<TldrawUiIcon icon="color" color={presence.color} />
|
||||||
<div className="tlui-people-menu__name">{presence.userName ?? 'New User'}</div>
|
<div className="tlui-people-menu__name">{presence.userName ?? 'New User'}</div>
|
||||||
</Button>
|
</TldrawUiButton>
|
||||||
<Button
|
<TldrawUiButton
|
||||||
type="icon"
|
type="icon"
|
||||||
className="tlui-people-menu__item__follow"
|
className="tlui-people-menu__item__follow"
|
||||||
title={
|
title={
|
||||||
|
@ -53,11 +54,14 @@ export const PeopleMenuItem = track(function PeopleMenuItem({ userId }: { userId
|
||||||
? msg('people-menu.following')
|
? msg('people-menu.following')
|
||||||
: msg('people-menu.follow')
|
: msg('people-menu.follow')
|
||||||
}
|
}
|
||||||
icon={theyAreFollowingYou ? 'leading' : youAreFollowingThem ? 'following' : 'follow'}
|
|
||||||
onClick={handleFollowClick}
|
onClick={handleFollowClick}
|
||||||
disabled={theyAreFollowingYou}
|
disabled={theyAreFollowingYou}
|
||||||
data-active={youAreFollowingThem || theyAreFollowingYou}
|
data-active={youAreFollowingThem || theyAreFollowingYou}
|
||||||
|
>
|
||||||
|
<TldrawUiButtonIcon
|
||||||
|
icon={theyAreFollowingYou ? 'leading' : youAreFollowingThem ? 'following' : 'follow'}
|
||||||
/>
|
/>
|
||||||
|
</TldrawUiButton>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import * as Popover from '@radix-ui/react-popover'
|
import * as Popover from '@radix-ui/react-popover'
|
||||||
import {
|
import {
|
||||||
Button,
|
TldrawUiButton,
|
||||||
|
TldrawUiButtonIcon,
|
||||||
USER_COLORS,
|
USER_COLORS,
|
||||||
track,
|
track,
|
||||||
useContainer,
|
useContainer,
|
||||||
|
@ -88,13 +89,14 @@ export const UserPresenceColorPicker = track(function UserPresenceColorPicker()
|
||||||
return (
|
return (
|
||||||
<Popover.Root onOpenChange={handleOpenChange} open={isOpen}>
|
<Popover.Root onOpenChange={handleOpenChange} open={isOpen}>
|
||||||
<Popover.Trigger dir="ltr" asChild>
|
<Popover.Trigger dir="ltr" asChild>
|
||||||
<Button
|
<TldrawUiButton
|
||||||
type="icon"
|
type="icon"
|
||||||
className="tlui-people-menu__user__color"
|
className="tlui-people-menu__user__color"
|
||||||
icon="color"
|
|
||||||
style={{ color: editor.user.getColor() }}
|
style={{ color: editor.user.getColor() }}
|
||||||
title={msg('people-menu.change-color')}
|
title={msg('people-menu.change-color')}
|
||||||
/>
|
>
|
||||||
|
<TldrawUiButtonIcon icon="color" />
|
||||||
|
</TldrawUiButton>
|
||||||
</Popover.Trigger>
|
</Popover.Trigger>
|
||||||
<Popover.Portal container={container}>
|
<Popover.Portal container={container}>
|
||||||
<Popover.Content
|
<Popover.Content
|
||||||
|
@ -106,11 +108,11 @@ export const UserPresenceColorPicker = track(function UserPresenceColorPicker()
|
||||||
>
|
>
|
||||||
<div className={'tlui-buttons__grid'}>
|
<div className={'tlui-buttons__grid'}>
|
||||||
{USER_COLORS.map((item: string) => (
|
{USER_COLORS.map((item: string) => (
|
||||||
<Button
|
<TldrawUiButton
|
||||||
type="icon"
|
type="icon"
|
||||||
key={item}
|
key={item}
|
||||||
data-id={item}
|
data-id={item}
|
||||||
data-wd={item}
|
data-testid={item}
|
||||||
aria-label={item}
|
aria-label={item}
|
||||||
data-state={value === item ? 'hinted' : undefined}
|
data-state={value === item ? 'hinted' : undefined}
|
||||||
title={item}
|
title={item}
|
||||||
|
@ -120,8 +122,9 @@ export const UserPresenceColorPicker = track(function UserPresenceColorPicker()
|
||||||
onPointerDown={handleButtonPointerDown}
|
onPointerDown={handleButtonPointerDown}
|
||||||
onPointerUp={handleButtonPointerUp}
|
onPointerUp={handleButtonPointerUp}
|
||||||
onClick={handleButtonClick}
|
onClick={handleButtonClick}
|
||||||
icon={'color'}
|
>
|
||||||
/>
|
<TldrawUiButtonIcon icon="color" />
|
||||||
|
</TldrawUiButton>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</Popover.Content>
|
</Popover.Content>
|
||||||
|
|
|
@ -1,4 +1,12 @@
|
||||||
import { Button, Input, useEditor, useTranslation, useUiEvents, useValue } from '@tldraw/tldraw'
|
import {
|
||||||
|
TldrawUiButton,
|
||||||
|
TldrawUiButtonIcon,
|
||||||
|
TldrawUiInput,
|
||||||
|
useEditor,
|
||||||
|
useTranslation,
|
||||||
|
useUiEvents,
|
||||||
|
useValue,
|
||||||
|
} from '@tldraw/tldraw'
|
||||||
import { useCallback, useRef, useState } from 'react'
|
import { useCallback, useRef, useState } from 'react'
|
||||||
import { UI_OVERRIDE_TODO_EVENT } from '../../utils/useHandleUiEvent'
|
import { UI_OVERRIDE_TODO_EVENT } from '../../utils/useHandleUiEvent'
|
||||||
import { UserPresenceColorPicker } from './UserPresenceColorPicker'
|
import { UserPresenceColorPicker } from './UserPresenceColorPicker'
|
||||||
|
@ -36,7 +44,7 @@ export function UserPresenceEditor() {
|
||||||
<div className="tlui-people-menu__user">
|
<div className="tlui-people-menu__user">
|
||||||
<UserPresenceColorPicker />
|
<UserPresenceColorPicker />
|
||||||
{isEditingName ? (
|
{isEditingName ? (
|
||||||
<Input
|
<TldrawUiInput
|
||||||
className="tlui-people-menu__user__input"
|
className="tlui-people-menu__user__input"
|
||||||
defaultValue={userName}
|
defaultValue={userName}
|
||||||
onValueChange={handleValueChange}
|
onValueChange={handleValueChange}
|
||||||
|
@ -62,14 +70,15 @@ export function UserPresenceEditor() {
|
||||||
) : null}
|
) : null}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
<Button
|
<TldrawUiButton
|
||||||
type="icon"
|
type="icon"
|
||||||
className="tlui-people-menu__user__edit"
|
className="tlui-people-menu__user__edit"
|
||||||
data-wd="people-menu.change-name"
|
data-testid="people-menu.change-name"
|
||||||
title={msg('people-menu.change-name')}
|
title={msg('people-menu.change-name')}
|
||||||
icon={isEditingName ? 'check' : 'edit'}
|
|
||||||
onClick={toggleEditingName}
|
onClick={toggleEditingName}
|
||||||
/>
|
>
|
||||||
|
<TldrawUiButtonIcon icon={isEditingName ? 'check' : 'edit'} />
|
||||||
|
</TldrawUiButton>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,6 +54,13 @@ const components: TLComponents = {
|
||||||
</DefaultKeyboardShortcutsDialog>
|
</DefaultKeyboardShortcutsDialog>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
SharePanel: () => {
|
||||||
|
return (
|
||||||
|
<div className="tlui-share-zone" draggable={false}>
|
||||||
|
<ExportMenu />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
type SnapshotEditorProps = {
|
type SnapshotEditorProps = {
|
||||||
|
@ -79,11 +86,6 @@ export function SnapshotsEditor(props: SnapshotEditorProps) {
|
||||||
editor.updateInstanceState({ isReadonly: true })
|
editor.updateInstanceState({ isReadonly: true })
|
||||||
}}
|
}}
|
||||||
components={components}
|
components={components}
|
||||||
shareZone={
|
|
||||||
<div className="tlui-share-zone" draggable={false}>
|
|
||||||
<ExportMenu />
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
renderDebugMenuItems={() => <DebugMenuItems />}
|
renderDebugMenuItems={() => <DebugMenuItems />}
|
||||||
autoFocus
|
autoFocus
|
||||||
inferDarkMode
|
inferDarkMode
|
||||||
|
|
|
@ -1,4 +1,10 @@
|
||||||
import { Button, LegacyTldrawDocument, useEditor, useValue } from '@tldraw/tldraw'
|
import {
|
||||||
|
LegacyTldrawDocument,
|
||||||
|
TldrawUiButton,
|
||||||
|
TldrawUiButtonLabel,
|
||||||
|
useEditor,
|
||||||
|
useValue,
|
||||||
|
} from '@tldraw/tldraw'
|
||||||
|
|
||||||
export function MigrationAnnouncement({
|
export function MigrationAnnouncement({
|
||||||
onClose,
|
onClose,
|
||||||
|
@ -107,16 +113,16 @@ export function MigrationAnnouncement({
|
||||||
marginTop: 8,
|
marginTop: 8,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Button
|
<TldrawUiButton
|
||||||
type="normal"
|
type="normal"
|
||||||
style={{ fontSize: 14, marginRight: 'auto' }}
|
style={{ fontSize: 14, marginRight: 'auto' }}
|
||||||
onClick={downloadFile}
|
onClick={downloadFile}
|
||||||
>
|
>
|
||||||
Download original
|
<TldrawUiButtonLabel>Download original</TldrawUiButtonLabel>
|
||||||
</Button>
|
</TldrawUiButton>
|
||||||
<Button style={{ fontSize: 14 }} type="primary" onClick={onClose}>
|
<TldrawUiButton style={{ fontSize: 14 }} type="primary" onClick={onClose}>
|
||||||
Continue
|
<TldrawUiButtonLabel>Continue</TldrawUiButtonLabel>
|
||||||
</Button>
|
</TldrawUiButton>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
import {
|
import {
|
||||||
Button,
|
|
||||||
DialogBody,
|
|
||||||
DialogCloseButton,
|
|
||||||
DialogFooter,
|
|
||||||
DialogHeader,
|
|
||||||
DialogTitle,
|
|
||||||
TLUiDialogsContextType,
|
TLUiDialogsContextType,
|
||||||
|
TldrawUiButton,
|
||||||
|
TldrawUiButtonCheck,
|
||||||
|
TldrawUiButtonLabel,
|
||||||
|
TldrawUiDialogBody,
|
||||||
|
TldrawUiDialogCloseButton,
|
||||||
|
TldrawUiDialogFooter,
|
||||||
|
TldrawUiDialogHeader,
|
||||||
|
TldrawUiDialogTitle,
|
||||||
useTranslation,
|
useTranslation,
|
||||||
} from '@tldraw/tldraw'
|
} from '@tldraw/tldraw'
|
||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
|
@ -49,26 +51,28 @@ function ConfirmClearDialog({
|
||||||
const [dontShowAgain, setDontShowAgain] = useState(false)
|
const [dontShowAgain, setDontShowAgain] = useState(false)
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<DialogHeader>
|
<TldrawUiDialogHeader>
|
||||||
<DialogTitle>{msg('file-system.confirm-clear.title')}</DialogTitle>
|
<TldrawUiDialogTitle>{msg('file-system.confirm-clear.title')}</TldrawUiDialogTitle>
|
||||||
<DialogCloseButton />
|
<TldrawUiDialogCloseButton />
|
||||||
</DialogHeader>
|
</TldrawUiDialogHeader>
|
||||||
<DialogBody style={{ maxWidth: 350 }}>
|
<TldrawUiDialogBody style={{ maxWidth: 350 }}>
|
||||||
{msg('file-system.confirm-clear.description')}
|
{msg('file-system.confirm-clear.description')}
|
||||||
</DialogBody>
|
</TldrawUiDialogBody>
|
||||||
<DialogFooter className="tlui-dialog__footer__actions">
|
<TldrawUiDialogFooter className="tlui-dialog__footer__actions">
|
||||||
<Button
|
<TldrawUiButton
|
||||||
type="normal"
|
type="normal"
|
||||||
onClick={() => setDontShowAgain(!dontShowAgain)}
|
onClick={() => setDontShowAgain(!dontShowAgain)}
|
||||||
iconLeft={dontShowAgain ? 'checkbox-checked' : 'checkbox-empty'}
|
|
||||||
style={{ marginRight: 'auto' }}
|
style={{ marginRight: 'auto' }}
|
||||||
>
|
>
|
||||||
|
<TldrawUiButtonCheck checked={dontShowAgain} />
|
||||||
|
<TldrawUiButtonLabel>
|
||||||
{msg('file-system.confirm-clear.dont-show-again')}
|
{msg('file-system.confirm-clear.dont-show-again')}
|
||||||
</Button>
|
</TldrawUiButtonLabel>
|
||||||
<Button type="normal" onClick={onCancel}>
|
</TldrawUiButton>
|
||||||
{msg('file-system.confirm-clear.cancel')}
|
<TldrawUiButton type="normal" onClick={onCancel}>
|
||||||
</Button>
|
<TldrawUiButtonLabel>{msg('file-system.confirm-clear.cancel')}</TldrawUiButtonLabel>
|
||||||
<Button
|
</TldrawUiButton>
|
||||||
|
<TldrawUiButton
|
||||||
type="primary"
|
type="primary"
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
if (dontShowAgain) {
|
if (dontShowAgain) {
|
||||||
|
@ -77,9 +81,9 @@ function ConfirmClearDialog({
|
||||||
onContinue()
|
onContinue()
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{msg('file-system.confirm-clear.continue')}
|
<TldrawUiButtonLabel>{msg('file-system.confirm-clear.continue')}</TldrawUiButtonLabel>
|
||||||
</Button>
|
</TldrawUiButton>
|
||||||
</DialogFooter>
|
</TldrawUiDialogFooter>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
import {
|
import {
|
||||||
Button,
|
|
||||||
DialogBody,
|
|
||||||
DialogCloseButton,
|
|
||||||
DialogFooter,
|
|
||||||
DialogHeader,
|
|
||||||
DialogTitle,
|
|
||||||
TLUiDialogsContextType,
|
TLUiDialogsContextType,
|
||||||
|
TldrawUiButton,
|
||||||
|
TldrawUiButtonCheck,
|
||||||
|
TldrawUiButtonLabel,
|
||||||
|
TldrawUiDialogBody,
|
||||||
|
TldrawUiDialogCloseButton,
|
||||||
|
TldrawUiDialogFooter,
|
||||||
|
TldrawUiDialogHeader,
|
||||||
|
TldrawUiDialogTitle,
|
||||||
useLocalStorageState,
|
useLocalStorageState,
|
||||||
useTranslation,
|
useTranslation,
|
||||||
} from '@tldraw/tldraw'
|
} from '@tldraw/tldraw'
|
||||||
|
@ -50,24 +52,26 @@ function ConfirmLeaveDialog({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<DialogHeader>
|
<TldrawUiDialogHeader>
|
||||||
<DialogTitle>{msg('sharing.confirm-leave.title')}</DialogTitle>
|
<TldrawUiDialogTitle>{msg('sharing.confirm-leave.title')}</TldrawUiDialogTitle>
|
||||||
<DialogCloseButton />
|
<TldrawUiDialogCloseButton />
|
||||||
</DialogHeader>
|
</TldrawUiDialogHeader>
|
||||||
<DialogBody style={{ maxWidth: 350 }}>{msg('sharing.confirm-leave.description')}</DialogBody>
|
<TldrawUiDialogBody style={{ maxWidth: 350 }}>
|
||||||
<DialogFooter className="tlui-dialog__footer__actions">
|
{msg('sharing.confirm-leave.description')}
|
||||||
<Button
|
</TldrawUiDialogBody>
|
||||||
|
<TldrawUiDialogFooter className="tlui-dialog__footer__actions">
|
||||||
|
<TldrawUiButton
|
||||||
type="normal"
|
type="normal"
|
||||||
onClick={() => setDontShowAgain(!dontShowAgain)}
|
|
||||||
iconLeft={dontShowAgain ? 'checkbox-checked' : 'checkbox-empty'}
|
|
||||||
style={{ marginRight: 'auto' }}
|
style={{ marginRight: 'auto' }}
|
||||||
|
onClick={() => setDontShowAgain(!dontShowAgain)}
|
||||||
>
|
>
|
||||||
{msg('sharing.confirm-leave.dont-show-again')}
|
<TldrawUiButtonCheck checked={dontShowAgain} />
|
||||||
</Button>
|
<TldrawUiButtonLabel>{msg('sharing.confirm-leave.dont-show-again')}</TldrawUiButtonLabel>
|
||||||
<Button type="normal" onClick={onCancel}>
|
</TldrawUiButton>
|
||||||
{msg('sharing.confirm-leave.cancel')}
|
<TldrawUiButton type="normal" onClick={onCancel}>
|
||||||
</Button>
|
<TldrawUiButtonLabel>{msg('sharing.confirm-leave.cancel')}</TldrawUiButtonLabel>
|
||||||
<Button
|
</TldrawUiButton>
|
||||||
|
<TldrawUiButton
|
||||||
type="primary"
|
type="primary"
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
if (dontShowAgain) {
|
if (dontShowAgain) {
|
||||||
|
@ -76,9 +80,9 @@ function ConfirmLeaveDialog({
|
||||||
onContinue()
|
onContinue()
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{msg('sharing.confirm-leave.leave')}
|
<TldrawUiButtonLabel>{msg('sharing.confirm-leave.leave')}</TldrawUiButtonLabel>
|
||||||
</Button>
|
</TldrawUiButton>
|
||||||
</DialogFooter>
|
</TldrawUiDialogFooter>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
import {
|
import {
|
||||||
Button,
|
|
||||||
DialogBody,
|
|
||||||
DialogCloseButton,
|
|
||||||
DialogFooter,
|
|
||||||
DialogHeader,
|
|
||||||
DialogTitle,
|
|
||||||
TLUiDialogsContextType,
|
TLUiDialogsContextType,
|
||||||
|
TldrawUiButton,
|
||||||
|
TldrawUiButtonCheck,
|
||||||
|
TldrawUiButtonLabel,
|
||||||
|
TldrawUiDialogBody,
|
||||||
|
TldrawUiDialogCloseButton,
|
||||||
|
TldrawUiDialogFooter,
|
||||||
|
TldrawUiDialogHeader,
|
||||||
|
TldrawUiDialogTitle,
|
||||||
useTranslation,
|
useTranslation,
|
||||||
} from '@tldraw/tldraw'
|
} from '@tldraw/tldraw'
|
||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
|
@ -49,26 +51,28 @@ function ConfirmOpenDialog({
|
||||||
const [dontShowAgain, setDontShowAgain] = useState(false)
|
const [dontShowAgain, setDontShowAgain] = useState(false)
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<DialogHeader>
|
<TldrawUiDialogHeader>
|
||||||
<DialogTitle>{msg('file-system.confirm-open.title')}</DialogTitle>
|
<TldrawUiDialogTitle>{msg('file-system.confirm-open.title')}</TldrawUiDialogTitle>
|
||||||
<DialogCloseButton />
|
<TldrawUiDialogCloseButton />
|
||||||
</DialogHeader>
|
</TldrawUiDialogHeader>
|
||||||
<DialogBody style={{ maxWidth: 350 }}>
|
<TldrawUiDialogBody style={{ maxWidth: 350 }}>
|
||||||
{msg('file-system.confirm-open.description')}
|
{msg('file-system.confirm-open.description')}
|
||||||
</DialogBody>
|
</TldrawUiDialogBody>
|
||||||
<DialogFooter className="tlui-dialog__footer__actions">
|
<TldrawUiDialogFooter className="tlui-dialog__footer__actions">
|
||||||
<Button
|
<TldrawUiButton
|
||||||
type="normal"
|
type="normal"
|
||||||
onClick={() => setDontShowAgain(!dontShowAgain)}
|
onClick={() => setDontShowAgain(!dontShowAgain)}
|
||||||
iconLeft={dontShowAgain ? 'checkbox-checked' : 'checkbox-empty'}
|
|
||||||
style={{ marginRight: 'auto' }}
|
style={{ marginRight: 'auto' }}
|
||||||
>
|
>
|
||||||
|
<TldrawUiButtonCheck checked={dontShowAgain} />
|
||||||
|
<TldrawUiButtonLabel>
|
||||||
{msg('file-system.confirm-open.dont-show-again')}
|
{msg('file-system.confirm-open.dont-show-again')}
|
||||||
</Button>
|
</TldrawUiButtonLabel>
|
||||||
<Button type="normal" onClick={onCancel}>
|
</TldrawUiButton>
|
||||||
{msg('file-system.confirm-open.cancel')}
|
<TldrawUiButton type="normal" onClick={onCancel}>
|
||||||
</Button>
|
<TldrawUiButtonLabel>{msg('file-system.confirm-open.cancel')}</TldrawUiButtonLabel>
|
||||||
<Button
|
</TldrawUiButton>
|
||||||
|
<TldrawUiButton
|
||||||
type="primary"
|
type="primary"
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
if (dontShowAgain) {
|
if (dontShowAgain) {
|
||||||
|
@ -77,9 +81,9 @@ function ConfirmOpenDialog({
|
||||||
onContinue()
|
onContinue()
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{msg('file-system.confirm-open.open')}
|
<TldrawUiButtonLabel>{msg('file-system.confirm-open.open')}</TldrawUiButtonLabel>
|
||||||
</Button>
|
</TldrawUiButton>
|
||||||
</DialogFooter>
|
</TldrawUiDialogFooter>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import {
|
import {
|
||||||
DefaultSizeStyle,
|
DefaultSizeStyle,
|
||||||
Icon,
|
|
||||||
SharedStyleMap,
|
SharedStyleMap,
|
||||||
Tldraw,
|
Tldraw,
|
||||||
|
TldrawUiIcon,
|
||||||
TLEditorComponents,
|
TLEditorComponents,
|
||||||
track,
|
track,
|
||||||
useEditor,
|
useEditor,
|
||||||
|
@ -85,7 +85,7 @@ const ContextToolbarComponent = track(() => {
|
||||||
editor.setStyleForSelectedShapes(DefaultSizeStyle, value, { squashing: false })
|
editor.setStyleForSelectedShapes(DefaultSizeStyle, value, { squashing: false })
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Icon icon={icon} />
|
<TldrawUiIcon icon={icon} />
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import {
|
import {
|
||||||
Button,
|
|
||||||
DefaultQuickActions,
|
DefaultQuickActions,
|
||||||
DefaultQuickActionsContent,
|
DefaultQuickActionsContent,
|
||||||
TLComponents,
|
TLComponents,
|
||||||
Tldraw,
|
Tldraw,
|
||||||
|
TldrawUiMenuItem,
|
||||||
} from '@tldraw/tldraw'
|
} from '@tldraw/tldraw'
|
||||||
import '@tldraw/tldraw/tldraw.css'
|
import '@tldraw/tldraw/tldraw.css'
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ function CustomQuickActions() {
|
||||||
return (
|
return (
|
||||||
<DefaultQuickActions>
|
<DefaultQuickActions>
|
||||||
<DefaultQuickActionsContent />
|
<DefaultQuickActionsContent />
|
||||||
<Button type="icon" icon="code" smallIcon />
|
<TldrawUiMenuItem id="code" icon="code" onSelect={() => window.alert('code')} />
|
||||||
</DefaultQuickActions>
|
</DefaultQuickActions>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
import {
|
import {
|
||||||
Button,
|
|
||||||
DefaultColorStyle,
|
DefaultColorStyle,
|
||||||
DefaultStylePanel,
|
DefaultStylePanel,
|
||||||
DefaultStylePanelContent,
|
DefaultStylePanelContent,
|
||||||
TLComponents,
|
TLComponents,
|
||||||
TLUiStylePanelProps,
|
TLUiStylePanelProps,
|
||||||
Tldraw,
|
Tldraw,
|
||||||
|
TldrawUiButton,
|
||||||
|
TldrawUiButtonLabel,
|
||||||
useEditor,
|
useEditor,
|
||||||
} from '@tldraw/tldraw'
|
} from '@tldraw/tldraw'
|
||||||
import '@tldraw/tldraw/tldraw.css'
|
import '@tldraw/tldraw/tldraw.css'
|
||||||
|
@ -17,22 +18,22 @@ function CustomStylePanel(props: TLUiStylePanelProps) {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DefaultStylePanel {...props}>
|
<DefaultStylePanel {...props}>
|
||||||
<Button
|
<TldrawUiButton
|
||||||
type="menu"
|
type="menu"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
editor.setStyleForSelectedShapes(DefaultColorStyle, 'red', { squashing: true })
|
editor.setStyleForSelectedShapes(DefaultColorStyle, 'red', { squashing: true })
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Red
|
<TldrawUiButtonLabel>Red</TldrawUiButtonLabel>
|
||||||
</Button>
|
</TldrawUiButton>
|
||||||
<Button
|
<TldrawUiButton
|
||||||
type="menu"
|
type="menu"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
editor.setStyleForSelectedShapes(DefaultColorStyle, 'green', { squashing: true })
|
editor.setStyleForSelectedShapes(DefaultColorStyle, 'green', { squashing: true })
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Green
|
<TldrawUiButtonLabel>Green</TldrawUiButtonLabel>
|
||||||
</Button>
|
</TldrawUiButton>
|
||||||
<DefaultStylePanelContent relevantStyles={props.relevantStyles} />
|
<DefaultStylePanelContent relevantStyles={props.relevantStyles} />
|
||||||
</DefaultStylePanel>
|
</DefaultStylePanel>
|
||||||
)
|
)
|
||||||
|
|
|
@ -17,6 +17,9 @@ const components: Required<TLUiComponents> = {
|
||||||
QuickActions: null,
|
QuickActions: null,
|
||||||
HelperButtons: null,
|
HelperButtons: null,
|
||||||
DebugMenu: null,
|
DebugMenu: null,
|
||||||
|
SharePanel: null,
|
||||||
|
MenuPanel: null,
|
||||||
|
TopPanel: null,
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function UiComponentsHiddenExample() {
|
export default function UiComponentsHiddenExample() {
|
||||||
|
|
|
@ -1,13 +1,18 @@
|
||||||
import { Tldraw } from '@tldraw/tldraw'
|
import { TLComponents, Tldraw } from '@tldraw/tldraw'
|
||||||
import '@tldraw/tldraw/tldraw.css'
|
import '@tldraw/tldraw/tldraw.css'
|
||||||
|
|
||||||
// There's a guide at the bottom of this file!
|
// There's a guide at the bottom of this file!
|
||||||
|
|
||||||
|
const components: TLComponents = {
|
||||||
|
SharePanel: CustomShareZone,
|
||||||
|
TopPanel: CustomTopZone,
|
||||||
|
}
|
||||||
|
|
||||||
// [1]
|
// [1]
|
||||||
export default function Example() {
|
export default function Example() {
|
||||||
return (
|
return (
|
||||||
<div className="tldraw__editor">
|
<div className="tldraw__editor">
|
||||||
<Tldraw topZone={<CustomTopZone />} shareZone={<CustomShareZone />} />
|
<Tldraw components={components} />
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -46,8 +51,8 @@ function CustomShareZone() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
This example shows how to pass in a custom component to the share zone and top zone.
|
This example shows how to pass in a custom component to the share panel and top panel.
|
||||||
The share zone is in the top right corner above the style menu, the top zone is in
|
The share panel is in the top right corner above the style menu, the top panel is in
|
||||||
the top center.
|
the top center.
|
||||||
|
|
||||||
[1]
|
[1]
|
||||||
|
|
|
@ -28,6 +28,7 @@ import { JSX as JSX_2 } from 'react/jsx-runtime';
|
||||||
import { LANGUAGES } from '@tldraw/editor';
|
import { LANGUAGES } from '@tldraw/editor';
|
||||||
import { Mat } from '@tldraw/editor';
|
import { Mat } from '@tldraw/editor';
|
||||||
import { MatModel } from '@tldraw/editor';
|
import { MatModel } from '@tldraw/editor';
|
||||||
|
import { MemoExoticComponent } from 'react';
|
||||||
import { MigrationFailureReason } from '@tldraw/editor';
|
import { MigrationFailureReason } from '@tldraw/editor';
|
||||||
import { Migrations } from '@tldraw/editor';
|
import { Migrations } from '@tldraw/editor';
|
||||||
import { NamedExoticComponent } from 'react';
|
import { NamedExoticComponent } from 'react';
|
||||||
|
@ -49,6 +50,7 @@ import { ShapeUtil } from '@tldraw/editor';
|
||||||
import { SharedStyle } from '@tldraw/editor';
|
import { SharedStyle } from '@tldraw/editor';
|
||||||
import { StateNode } from '@tldraw/editor';
|
import { StateNode } from '@tldraw/editor';
|
||||||
import { StoreSnapshot } from '@tldraw/editor';
|
import { StoreSnapshot } from '@tldraw/editor';
|
||||||
|
import { StyleProp } from '@tldraw/editor';
|
||||||
import { SvgExportContext } from '@tldraw/editor';
|
import { SvgExportContext } from '@tldraw/editor';
|
||||||
import { T } from '@tldraw/editor';
|
import { T } from '@tldraw/editor';
|
||||||
import { TLAnyShapeUtilConstructor } from '@tldraw/editor';
|
import { TLAnyShapeUtilConstructor } from '@tldraw/editor';
|
||||||
|
@ -265,9 +267,6 @@ export function BreakPointProvider({ forceMobile, children, }: {
|
||||||
// @internal (undocumented)
|
// @internal (undocumented)
|
||||||
export function buildFromV1Document(editor: Editor, document: LegacyTldrawDocument): void;
|
export function buildFromV1Document(editor: Editor, document: LegacyTldrawDocument): void;
|
||||||
|
|
||||||
// @public (undocumented)
|
|
||||||
export const Button: React_3.ForwardRefExoticComponent<TLUiButtonProps & React_3.RefAttributes<HTMLButtonElement>>;
|
|
||||||
|
|
||||||
// @public
|
// @public
|
||||||
export function containBoxSize(originalSize: BoxWidthHeight, containBoxSize: BoxWidthHeight): BoxWidthHeight;
|
export function containBoxSize(originalSize: BoxWidthHeight, containBoxSize: BoxWidthHeight): BoxWidthHeight;
|
||||||
|
|
||||||
|
@ -360,21 +359,6 @@ export const DefaultZoomMenu: NamedExoticComponent<TLUiZoomMenuProps>;
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
export function DefaultZoomMenuContent(): JSX_2.Element;
|
export function DefaultZoomMenuContent(): JSX_2.Element;
|
||||||
|
|
||||||
// @public (undocumented)
|
|
||||||
export function DialogBody({ className, children, style }: TLUiDialogBodyProps): JSX_2.Element;
|
|
||||||
|
|
||||||
// @public (undocumented)
|
|
||||||
export function DialogCloseButton(): JSX_2.Element;
|
|
||||||
|
|
||||||
// @public (undocumented)
|
|
||||||
export function DialogFooter({ className, children }: TLUiDialogFooterProps): JSX_2.Element;
|
|
||||||
|
|
||||||
// @public (undocumented)
|
|
||||||
export function DialogHeader({ className, children }: TLUiDialogHeaderProps): JSX_2.Element;
|
|
||||||
|
|
||||||
// @public (undocumented)
|
|
||||||
export function DialogTitle({ className, children }: TLUiDialogTitleProps): JSX_2.Element;
|
|
||||||
|
|
||||||
// @public
|
// @public
|
||||||
export function downsizeImage(blob: Blob, width: number, height: number, opts?: {
|
export function downsizeImage(blob: Blob, width: number, height: number, opts?: {
|
||||||
type?: string | undefined;
|
type?: string | undefined;
|
||||||
|
@ -439,36 +423,6 @@ export class DrawShapeUtil extends ShapeUtil<TLDrawShape> {
|
||||||
static type: "draw";
|
static type: "draw";
|
||||||
}
|
}
|
||||||
|
|
||||||
// @public (undocumented)
|
|
||||||
export function DropdownMenuCheckboxItem({ children, onSelect, ...rest }: TLUiDropdownMenuCheckboxItemProps): JSX_2.Element;
|
|
||||||
|
|
||||||
// @public (undocumented)
|
|
||||||
export function DropdownMenuContent({ side, align, sideOffset, alignOffset, children, }: TLUiDropdownMenuContentProps): JSX_2.Element;
|
|
||||||
|
|
||||||
// @public (undocumented)
|
|
||||||
export function DropdownMenuGroup({ children, size }: TLUiDropdownMenuGroupProps): JSX_2.Element;
|
|
||||||
|
|
||||||
// @public (undocumented)
|
|
||||||
export function DropdownMenuIndicator(): JSX_2.Element;
|
|
||||||
|
|
||||||
// @public (undocumented)
|
|
||||||
export function DropdownMenuItem({ noClose, ...props }: TLUiDropdownMenuItemProps): JSX_2.Element;
|
|
||||||
|
|
||||||
// @public (undocumented)
|
|
||||||
export function DropdownMenuRadioItem({ children, ...rest }: TLUiDropdownMenuRadioItemProps): JSX_2.Element;
|
|
||||||
|
|
||||||
// @public (undocumented)
|
|
||||||
export function DropdownMenuRoot({ id, children, modal, debugOpen, }: TLUiDropdownMenuRootProps): JSX_2.Element;
|
|
||||||
|
|
||||||
// @public (undocumented)
|
|
||||||
export function DropdownMenuSub({ id, children }: TLUiDropdownMenuSubProps): JSX_2.Element;
|
|
||||||
|
|
||||||
// @public (undocumented)
|
|
||||||
export function DropdownMenuSubTrigger({ label, title, disabled, }: TLUiDropdownMenuSubTriggerProps): JSX_2.Element;
|
|
||||||
|
|
||||||
// @public (undocumented)
|
|
||||||
export function DropdownMenuTrigger({ children, ...rest }: TLUiDropdownMenuTriggerProps): JSX_2.Element;
|
|
||||||
|
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
export class EmbedShapeUtil extends BaseBoxShapeUtil<TLEmbedShape> {
|
export class EmbedShapeUtil extends BaseBoxShapeUtil<TLEmbedShape> {
|
||||||
// (undocumented)
|
// (undocumented)
|
||||||
|
@ -815,9 +769,6 @@ export class HighlightShapeUtil extends ShapeUtil<TLHighlightShape> {
|
||||||
static type: "highlight";
|
static type: "highlight";
|
||||||
}
|
}
|
||||||
|
|
||||||
// @public (undocumented)
|
|
||||||
export const Icon: NamedExoticComponent<TLUiIconProps>;
|
|
||||||
|
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
export class ImageShapeUtil extends BaseBoxShapeUtil<TLImageShape> {
|
export class ImageShapeUtil extends BaseBoxShapeUtil<TLImageShape> {
|
||||||
// (undocumented)
|
// (undocumented)
|
||||||
|
@ -856,9 +807,6 @@ export class ImageShapeUtil extends BaseBoxShapeUtil<TLImageShape> {
|
||||||
static type: "image";
|
static type: "image";
|
||||||
}
|
}
|
||||||
|
|
||||||
// @public (undocumented)
|
|
||||||
export const Input: React_3.ForwardRefExoticComponent<TLUiInputProps & React_3.RefAttributes<HTMLInputElement>>;
|
|
||||||
|
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
export function isGifAnimated(file: Blob): Promise<boolean>;
|
export function isGifAnimated(file: Blob): Promise<boolean>;
|
||||||
|
|
||||||
|
@ -1059,15 +1007,6 @@ export function parseTldrawJsonFile({ json, schema, }: {
|
||||||
json: string;
|
json: string;
|
||||||
}): Result<TLStore, TldrawFileParseError>;
|
}): Result<TLStore, TldrawFileParseError>;
|
||||||
|
|
||||||
// @public (undocumented)
|
|
||||||
export function Popover({ id, children, onOpenChange, open }: TLUiPopoverProps): JSX_2.Element;
|
|
||||||
|
|
||||||
// @public (undocumented)
|
|
||||||
export function PopoverContent({ side, children, align, sideOffset, alignOffset, }: TLUiPopoverContentProps): JSX_2.Element;
|
|
||||||
|
|
||||||
// @public (undocumented)
|
|
||||||
export function PopoverTrigger({ children, ...rest }: TLUiPopoverTriggerProps): JSX_2.Element;
|
|
||||||
|
|
||||||
// @public
|
// @public
|
||||||
export function removeFrame(editor: Editor, ids: TLShapeId[]): void;
|
export function removeFrame(editor: Editor, ids: TLShapeId[]): void;
|
||||||
|
|
||||||
|
@ -1292,13 +1231,25 @@ export interface TldrawUiBaseProps {
|
||||||
components?: TLUiComponents;
|
components?: TLUiComponents;
|
||||||
hideUi?: boolean;
|
hideUi?: boolean;
|
||||||
renderDebugMenuItems?: () => React_2.ReactNode;
|
renderDebugMenuItems?: () => React_2.ReactNode;
|
||||||
shareZone?: ReactNode;
|
|
||||||
// @internal
|
|
||||||
topZone?: ReactNode;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
export function TldrawUiComponentsProvider({ overrides, children, }: ComponentsContextProviderProps): JSX_2.Element;
|
export const TldrawUiButton: React_3.ForwardRefExoticComponent<TLUiButtonProps & React_3.RefAttributes<HTMLButtonElement>>;
|
||||||
|
|
||||||
|
// @public (undocumented)
|
||||||
|
export function TldrawUiButtonCheck({ checked }: TLUiButtonCheckProps): JSX_2.Element;
|
||||||
|
|
||||||
|
// @public (undocumented)
|
||||||
|
export function TldrawUiButtonIcon({ icon, small, invertIcon }: TLUiButtonIconProps): JSX_2.Element;
|
||||||
|
|
||||||
|
// @public (undocumented)
|
||||||
|
export function TldrawUiButtonLabel({ children }: TLUiButtonLabelProps): JSX_2.Element;
|
||||||
|
|
||||||
|
// @public (undocumented)
|
||||||
|
export const TldrawUiButtonPicker: MemoExoticComponent<(<T extends string>(props: TLUiButtonPickerProps<T>) => JSX_2.Element)>;
|
||||||
|
|
||||||
|
// @public (undocumented)
|
||||||
|
export function TldrawUiComponentsProvider({ overrides, children, }: TLUiComponentsProviderProps): JSX_2.Element;
|
||||||
|
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
export function TldrawUiContextProvider({ overrides, components, assetUrls, onUiEvent, forceMobile, children, }: TldrawUiContextProviderProps): JSX_2.Element;
|
export function TldrawUiContextProvider({ overrides, components, assetUrls, onUiEvent, forceMobile, children, }: TldrawUiContextProviderProps): JSX_2.Element;
|
||||||
|
@ -1313,6 +1264,57 @@ export interface TldrawUiContextProviderProps {
|
||||||
overrides?: TLUiOverrides | TLUiOverrides[];
|
overrides?: TLUiOverrides | TLUiOverrides[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @public (undocumented)
|
||||||
|
export function TldrawUiDialogBody({ className, children, style }: TLUiDialogBodyProps): JSX_2.Element;
|
||||||
|
|
||||||
|
// @public (undocumented)
|
||||||
|
export function TldrawUiDialogCloseButton(): JSX_2.Element;
|
||||||
|
|
||||||
|
// @public (undocumented)
|
||||||
|
export function TldrawUiDialogFooter({ className, children }: TLUiDialogFooterProps): JSX_2.Element;
|
||||||
|
|
||||||
|
// @public (undocumented)
|
||||||
|
export function TldrawUiDialogHeader({ className, children }: TLUiDialogHeaderProps): JSX_2.Element;
|
||||||
|
|
||||||
|
// @public (undocumented)
|
||||||
|
export function TldrawUiDialogTitle({ className, children }: TLUiDialogTitleProps): JSX_2.Element;
|
||||||
|
|
||||||
|
// @public (undocumented)
|
||||||
|
export function TldrawUiDropdownMenuCheckboxItem({ children, onSelect, ...rest }: TLUiDropdownMenuCheckboxItemProps): JSX_2.Element;
|
||||||
|
|
||||||
|
// @public (undocumented)
|
||||||
|
export function TldrawUiDropdownMenuContent({ side, align, sideOffset, alignOffset, children, }: TLUiDropdownMenuContentProps): JSX_2.Element;
|
||||||
|
|
||||||
|
// @public (undocumented)
|
||||||
|
export function TldrawUiDropdownMenuGroup({ children, size, }: TLUiDropdownMenuGroupProps): JSX_2.Element;
|
||||||
|
|
||||||
|
// @public (undocumented)
|
||||||
|
export function TldrawUiDropdownMenuIndicator(): JSX_2.Element;
|
||||||
|
|
||||||
|
// @public (undocumented)
|
||||||
|
export function TldrawUiDropdownMenuItem({ noClose, children }: TLUiDropdownMenuItemProps): JSX_2.Element;
|
||||||
|
|
||||||
|
// @public (undocumented)
|
||||||
|
export function TldrawUiDropdownMenuRoot({ id, children, modal, debugOpen, }: TLUiDropdownMenuRootProps): JSX_2.Element;
|
||||||
|
|
||||||
|
// @public (undocumented)
|
||||||
|
export function TldrawUiDropdownMenuSub({ id, children }: TLUiDropdownMenuSubProps): JSX_2.Element;
|
||||||
|
|
||||||
|
// @public (undocumented)
|
||||||
|
export function TldrawUiDropdownMenuSubTrigger({ label, title, disabled, }: TLUiDropdownMenuSubTriggerProps): JSX_2.Element;
|
||||||
|
|
||||||
|
// @public (undocumented)
|
||||||
|
export function TldrawUiDropdownMenuTrigger({ children, ...rest }: TLUiDropdownMenuTriggerProps): JSX_2.Element;
|
||||||
|
|
||||||
|
// @public (undocumented)
|
||||||
|
export const TldrawUiIcon: NamedExoticComponent<TLUiIconProps>;
|
||||||
|
|
||||||
|
// @public (undocumented)
|
||||||
|
export const TldrawUiInput: React_3.ForwardRefExoticComponent<TLUiInputProps & React_3.RefAttributes<HTMLInputElement>>;
|
||||||
|
|
||||||
|
// @public (undocumented)
|
||||||
|
export function TldrawUiKbd({ children }: TLUiKbdProps): JSX_2.Element | null;
|
||||||
|
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
export function TldrawUiMenuCheckboxItem<TranslationKey extends string = string, IconType extends string = string>({ id, kbd, label, readonlyOk, onSelect, disabled, checked, }: TLUiMenuCheckboxItemProps<TranslationKey, IconType>): JSX_2.Element | null;
|
export function TldrawUiMenuCheckboxItem<TranslationKey extends string = string, IconType extends string = string>({ id, kbd, label, readonlyOk, onSelect, disabled, checked, }: TLUiMenuCheckboxItemProps<TranslationKey, IconType>): JSX_2.Element | null;
|
||||||
|
|
||||||
|
@ -1328,9 +1330,21 @@ export function TldrawUiMenuItem<TranslationKey extends string = string, IconTyp
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
export function TldrawUiMenuSubmenu<Translation extends string = string>({ id, disabled, label, size, children, }: TLUiMenuSubmenuProps<Translation>): any;
|
export function TldrawUiMenuSubmenu<Translation extends string = string>({ id, disabled, label, size, children, }: TLUiMenuSubmenuProps<Translation>): any;
|
||||||
|
|
||||||
|
// @public (undocumented)
|
||||||
|
export function TldrawUiPopover({ id, children, onOpenChange, open }: TLUiPopoverProps): JSX_2.Element;
|
||||||
|
|
||||||
|
// @public (undocumented)
|
||||||
|
export function TldrawUiPopoverContent({ side, children, align, sideOffset, alignOffset, }: TLUiPopoverContentProps): JSX_2.Element;
|
||||||
|
|
||||||
|
// @public (undocumented)
|
||||||
|
export function TldrawUiPopoverTrigger({ children }: TLUiPopoverTriggerProps): JSX_2.Element;
|
||||||
|
|
||||||
// @public
|
// @public
|
||||||
export type TldrawUiProps = TldrawUiBaseProps & TldrawUiContextProviderProps;
|
export type TldrawUiProps = TldrawUiBaseProps & TldrawUiContextProviderProps;
|
||||||
|
|
||||||
|
// @internal (undocumented)
|
||||||
|
export const TldrawUiSlider: NamedExoticComponent<TLUiSliderProps>;
|
||||||
|
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
export interface TLUiActionItem<TransationKey extends string = string, IconType extends string = string> {
|
export interface TLUiActionItem<TransationKey extends string = string, IconType extends string = string> {
|
||||||
// (undocumented)
|
// (undocumented)
|
||||||
|
@ -1364,29 +1378,44 @@ export type TLUiActionsMenuProps = {
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
export type TLUiAssetUrlOverrides = RecursivePartial<TLUiAssetUrls>;
|
export type TLUiAssetUrlOverrides = RecursivePartial<TLUiAssetUrls>;
|
||||||
|
|
||||||
|
// @public (undocumented)
|
||||||
|
export type TLUiButtonCheckProps = {
|
||||||
|
checked: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
// @public (undocumented)
|
||||||
|
export type TLUiButtonIconProps = {
|
||||||
|
icon: string;
|
||||||
|
small?: boolean;
|
||||||
|
invertIcon?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
// @public (undocumented)
|
||||||
|
export type TLUiButtonLabelProps = {
|
||||||
|
children?: any;
|
||||||
|
};
|
||||||
|
|
||||||
|
// @public (undocumented)
|
||||||
|
export interface TLUiButtonPickerProps<T extends string> {
|
||||||
|
// (undocumented)
|
||||||
|
items: StyleValuesForUi<T>;
|
||||||
|
// (undocumented)
|
||||||
|
onValueChange: (style: StyleProp<T>, value: T, squashing: boolean) => void;
|
||||||
|
// (undocumented)
|
||||||
|
style: StyleProp<T>;
|
||||||
|
// (undocumented)
|
||||||
|
title: string;
|
||||||
|
// (undocumented)
|
||||||
|
uiType: string;
|
||||||
|
// (undocumented)
|
||||||
|
value: SharedStyle<T>;
|
||||||
|
}
|
||||||
|
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
export interface TLUiButtonProps extends React_3.HTMLAttributes<HTMLButtonElement> {
|
export interface TLUiButtonProps extends React_3.HTMLAttributes<HTMLButtonElement> {
|
||||||
// (undocumented)
|
// (undocumented)
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
// (undocumented)
|
// (undocumented)
|
||||||
icon?: Exclude<string, TLUiIconType> | TLUiIconType;
|
|
||||||
// (undocumented)
|
|
||||||
iconLeft?: Exclude<string, TLUiIconType> | TLUiIconType;
|
|
||||||
// (undocumented)
|
|
||||||
invertIcon?: boolean;
|
|
||||||
// (undocumented)
|
|
||||||
isChecked?: boolean;
|
|
||||||
// (undocumented)
|
|
||||||
kbd?: string;
|
|
||||||
// (undocumented)
|
|
||||||
label?: Exclude<string, TLUiTranslationKey> | TLUiTranslationKey;
|
|
||||||
// (undocumented)
|
|
||||||
loading?: boolean;
|
|
||||||
// (undocumented)
|
|
||||||
smallIcon?: boolean;
|
|
||||||
// (undocumented)
|
|
||||||
spinner?: boolean;
|
|
||||||
// (undocumented)
|
|
||||||
type: 'danger' | 'help' | 'icon' | 'low' | 'menu' | 'normal' | 'primary' | 'tool';
|
type: 'danger' | 'help' | 'icon' | 'low' | 'menu' | 'normal' | 'primary' | 'tool';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1395,6 +1424,12 @@ export type TLUiComponents = Partial<{
|
||||||
[K in keyof BaseTLUiComponents]: BaseTLUiComponents[K] | null;
|
[K in keyof BaseTLUiComponents]: BaseTLUiComponents[K] | null;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
// @public (undocumented)
|
||||||
|
export type TLUiComponentsProviderProps = {
|
||||||
|
overrides?: TLUiComponents;
|
||||||
|
children: any;
|
||||||
|
};
|
||||||
|
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
export interface TLUiContextMenuProps {
|
export interface TLUiContextMenuProps {
|
||||||
// (undocumented)
|
// (undocumented)
|
||||||
|
@ -1491,23 +1526,11 @@ export type TLUiDropdownMenuGroupProps = {
|
||||||
};
|
};
|
||||||
|
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
export interface TLUiDropdownMenuItemProps extends TLUiButtonProps {
|
export interface TLUiDropdownMenuItemProps {
|
||||||
// (undocumented)
|
|
||||||
noClose?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
// @public (undocumented)
|
|
||||||
export interface TLUiDropdownMenuRadioItemProps {
|
|
||||||
// (undocumented)
|
|
||||||
checked?: boolean;
|
|
||||||
// (undocumented)
|
// (undocumented)
|
||||||
children: any;
|
children: any;
|
||||||
// (undocumented)
|
// (undocumented)
|
||||||
disabled?: boolean;
|
noClose?: boolean;
|
||||||
// (undocumented)
|
|
||||||
onSelect?: (e: Event) => void;
|
|
||||||
// (undocumented)
|
|
||||||
title: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
|
@ -1533,7 +1556,7 @@ export type TLUiDropdownMenuSubTriggerProps = {
|
||||||
};
|
};
|
||||||
|
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
export interface TLUiDropdownMenuTriggerProps extends TLUiButtonProps {
|
export interface TLUiDropdownMenuTriggerProps {
|
||||||
// (undocumented)
|
// (undocumented)
|
||||||
children?: any;
|
children?: any;
|
||||||
}
|
}
|
||||||
|
@ -1772,6 +1795,12 @@ export interface TLUiInputProps {
|
||||||
value?: string;
|
value?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @public (undocumented)
|
||||||
|
export interface TLUiKbdProps {
|
||||||
|
// (undocumented)
|
||||||
|
children: string;
|
||||||
|
}
|
||||||
|
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
export type TLUiKeyboardShortcutsDialogProps = TLUiDialogProps & {
|
export type TLUiKeyboardShortcutsDialogProps = TLUiDialogProps & {
|
||||||
children?: any;
|
children?: any;
|
||||||
|
@ -1867,7 +1896,7 @@ export type TLUiPopoverProps = {
|
||||||
};
|
};
|
||||||
|
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
export interface TLUiPopoverTriggerProps extends TLUiButtonProps {
|
export interface TLUiPopoverTriggerProps {
|
||||||
// (undocumented)
|
// (undocumented)
|
||||||
children?: React_2.ReactNode;
|
children?: React_2.ReactNode;
|
||||||
}
|
}
|
||||||
|
@ -1877,6 +1906,22 @@ export type TLUiQuickActionsProps = {
|
||||||
children?: any;
|
children?: any;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// @internal (undocumented)
|
||||||
|
export interface TLUiSliderProps {
|
||||||
|
// (undocumented)
|
||||||
|
'data-testid'?: string;
|
||||||
|
// (undocumented)
|
||||||
|
label: string;
|
||||||
|
// (undocumented)
|
||||||
|
onValueChange: (value: number, emphemeral: boolean) => void;
|
||||||
|
// (undocumented)
|
||||||
|
steps: number;
|
||||||
|
// (undocumented)
|
||||||
|
title: string;
|
||||||
|
// (undocumented)
|
||||||
|
value: null | number;
|
||||||
|
}
|
||||||
|
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
export type TLUiStylePanelContentProps = {
|
export type TLUiStylePanelContentProps = {
|
||||||
relevantStyles: ReturnType<typeof useRelevantStyles>;
|
relevantStyles: ReturnType<typeof useRelevantStyles>;
|
||||||
|
@ -2080,6 +2125,9 @@ export function useTldrawUiComponents(): Partial<{
|
||||||
QuickActions: ComponentType<TLUiQuickActionsProps> | null;
|
QuickActions: ComponentType<TLUiQuickActionsProps> | null;
|
||||||
HelperButtons: ComponentType<TLUiHelperButtonsProps> | null;
|
HelperButtons: ComponentType<TLUiHelperButtonsProps> | null;
|
||||||
DebugMenu: ComponentType | null;
|
DebugMenu: ComponentType | null;
|
||||||
|
MenuPanel: ComponentType | null;
|
||||||
|
TopPanel: ComponentType | null;
|
||||||
|
SharePanel: ComponentType | null;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -42,9 +42,6 @@ export { TldrawUi, type TldrawUiBaseProps, type TldrawUiProps } from './lib/ui/T
|
||||||
export { setDefaultUiAssetUrls, type TLUiAssetUrlOverrides } from './lib/ui/assetUrls'
|
export { setDefaultUiAssetUrls, type TLUiAssetUrlOverrides } from './lib/ui/assetUrls'
|
||||||
export { OfflineIndicator } from './lib/ui/components/OfflineIndicator/OfflineIndicator'
|
export { OfflineIndicator } from './lib/ui/components/OfflineIndicator/OfflineIndicator'
|
||||||
export { Spinner } from './lib/ui/components/Spinner'
|
export { Spinner } from './lib/ui/components/Spinner'
|
||||||
export { Button, type TLUiButtonProps } from './lib/ui/components/primitives/Button'
|
|
||||||
export { Icon, type TLUiIconProps } from './lib/ui/components/primitives/Icon'
|
|
||||||
export { Input, type TLUiInputProps } from './lib/ui/components/primitives/Input'
|
|
||||||
export {
|
export {
|
||||||
TldrawUiContextProvider,
|
TldrawUiContextProvider,
|
||||||
type TldrawUiContextProviderProps,
|
type TldrawUiContextProviderProps,
|
||||||
|
@ -99,7 +96,7 @@ export {
|
||||||
export { type TLUiTranslationKey } from './lib/ui/hooks/useTranslation/TLUiTranslationKey'
|
export { type TLUiTranslationKey } from './lib/ui/hooks/useTranslation/TLUiTranslationKey'
|
||||||
export { type TLUiTranslation } from './lib/ui/hooks/useTranslation/translations'
|
export { type TLUiTranslation } from './lib/ui/hooks/useTranslation/translations'
|
||||||
export {
|
export {
|
||||||
useTranslation as useTranslation,
|
useTranslation,
|
||||||
type TLUiTranslationContextType,
|
type TLUiTranslationContextType,
|
||||||
} from './lib/ui/hooks/useTranslation/useTranslation'
|
} from './lib/ui/hooks/useTranslation/useTranslation'
|
||||||
export { type TLUiIconType } from './lib/ui/icon-types'
|
export { type TLUiIconType } from './lib/ui/icon-types'
|
||||||
|
@ -137,35 +134,13 @@ export { DefaultMinimap } from './lib/ui/components/Minimap/DefaultMinimap'
|
||||||
// Helper to unwrap label from action items
|
// Helper to unwrap label from action items
|
||||||
export { unwrapLabel } from './lib/ui/context/actions'
|
export { unwrapLabel } from './lib/ui/context/actions'
|
||||||
|
|
||||||
// General UI components for building menus
|
|
||||||
export {
|
|
||||||
TldrawUiMenuCheckboxItem,
|
|
||||||
type TLUiMenuCheckboxItemProps,
|
|
||||||
} from './lib/ui/components/menus/TldrawUiMenuCheckboxItem'
|
|
||||||
export {
|
|
||||||
TldrawUiMenuContextProvider,
|
|
||||||
type TLUiMenuContextProviderProps,
|
|
||||||
} from './lib/ui/components/menus/TldrawUiMenuContext'
|
|
||||||
export {
|
|
||||||
TldrawUiMenuGroup,
|
|
||||||
type TLUiMenuGroupProps,
|
|
||||||
} from './lib/ui/components/menus/TldrawUiMenuGroup'
|
|
||||||
export {
|
|
||||||
TldrawUiMenuItem,
|
|
||||||
type TLUiMenuItemProps,
|
|
||||||
} from './lib/ui/components/menus/TldrawUiMenuItem'
|
|
||||||
export {
|
|
||||||
TldrawUiMenuSubmenu,
|
|
||||||
type TLUiMenuSubmenuProps,
|
|
||||||
} from './lib/ui/components/menus/TldrawUiMenuSubmenu'
|
|
||||||
|
|
||||||
export {
|
export {
|
||||||
TldrawUiComponentsProvider,
|
TldrawUiComponentsProvider,
|
||||||
useTldrawUiComponents,
|
useTldrawUiComponents,
|
||||||
type TLUiComponents,
|
type TLUiComponents,
|
||||||
|
type TLUiComponentsProviderProps,
|
||||||
} from './lib/ui/context/components'
|
} from './lib/ui/context/components'
|
||||||
|
|
||||||
// Menus / UI elements that can be customized
|
|
||||||
export { DefaultPageMenu } from './lib/ui/components/PageMenu/DefaultPageMenu'
|
export { DefaultPageMenu } from './lib/ui/components/PageMenu/DefaultPageMenu'
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
@ -236,45 +211,108 @@ export { DefaultToolbar } from './lib/ui/components/Toolbar/DefaultToolbar'
|
||||||
|
|
||||||
export { type TLComponents } from './lib/Tldraw'
|
export { type TLComponents } from './lib/Tldraw'
|
||||||
|
|
||||||
|
/* ------------------- Primitives ------------------- */
|
||||||
|
|
||||||
|
// Button
|
||||||
export {
|
export {
|
||||||
DialogBody,
|
TldrawUiButton,
|
||||||
DialogCloseButton,
|
type TLUiButtonProps,
|
||||||
DialogFooter,
|
} from './lib/ui/components/primitives/Button/TldrawUiButton'
|
||||||
DialogHeader,
|
export {
|
||||||
DialogTitle,
|
TldrawUiButtonCheck,
|
||||||
|
type TLUiButtonCheckProps,
|
||||||
|
} from './lib/ui/components/primitives/Button/TldrawUiButtonCheck'
|
||||||
|
export {
|
||||||
|
TldrawUiButtonIcon,
|
||||||
|
type TLUiButtonIconProps,
|
||||||
|
} from './lib/ui/components/primitives/Button/TldrawUiButtonIcon'
|
||||||
|
export {
|
||||||
|
TldrawUiButtonLabel,
|
||||||
|
type TLUiButtonLabelProps,
|
||||||
|
} from './lib/ui/components/primitives/Button/TldrawUiButtonLabel'
|
||||||
|
|
||||||
|
// Button picker
|
||||||
|
export {
|
||||||
|
TldrawUiButtonPicker,
|
||||||
|
type TLUiButtonPickerProps,
|
||||||
|
} from './lib/ui/components/primitives/TldrawUiButtonPicker'
|
||||||
|
|
||||||
|
// Dialog
|
||||||
|
export {
|
||||||
|
TldrawUiDialogBody,
|
||||||
|
TldrawUiDialogCloseButton,
|
||||||
|
TldrawUiDialogFooter,
|
||||||
|
TldrawUiDialogHeader,
|
||||||
|
TldrawUiDialogTitle,
|
||||||
type TLUiDialogBodyProps,
|
type TLUiDialogBodyProps,
|
||||||
type TLUiDialogFooterProps,
|
type TLUiDialogFooterProps,
|
||||||
type TLUiDialogHeaderProps,
|
type TLUiDialogHeaderProps,
|
||||||
type TLUiDialogTitleProps,
|
type TLUiDialogTitleProps,
|
||||||
} from './lib/ui/components/primitives/Dialog'
|
} from './lib/ui/components/primitives/TldrawUiDialog'
|
||||||
|
|
||||||
|
// Dropdown Menu
|
||||||
export {
|
export {
|
||||||
DropdownMenuCheckboxItem,
|
TldrawUiDropdownMenuCheckboxItem,
|
||||||
DropdownMenuContent,
|
TldrawUiDropdownMenuContent,
|
||||||
DropdownMenuGroup,
|
TldrawUiDropdownMenuGroup,
|
||||||
DropdownMenuIndicator,
|
TldrawUiDropdownMenuIndicator,
|
||||||
DropdownMenuItem,
|
TldrawUiDropdownMenuItem,
|
||||||
DropdownMenuRadioItem,
|
TldrawUiDropdownMenuRoot,
|
||||||
DropdownMenuRoot,
|
TldrawUiDropdownMenuSub,
|
||||||
DropdownMenuSub,
|
TldrawUiDropdownMenuSubTrigger,
|
||||||
DropdownMenuSubTrigger,
|
TldrawUiDropdownMenuTrigger,
|
||||||
DropdownMenuTrigger,
|
|
||||||
type TLUiDropdownMenuCheckboxItemProps,
|
type TLUiDropdownMenuCheckboxItemProps,
|
||||||
type TLUiDropdownMenuContentProps,
|
type TLUiDropdownMenuContentProps,
|
||||||
type TLUiDropdownMenuGroupProps,
|
type TLUiDropdownMenuGroupProps,
|
||||||
type TLUiDropdownMenuItemProps,
|
type TLUiDropdownMenuItemProps,
|
||||||
type TLUiDropdownMenuRadioItemProps,
|
|
||||||
type TLUiDropdownMenuRootProps,
|
type TLUiDropdownMenuRootProps,
|
||||||
type TLUiDropdownMenuSubProps,
|
type TLUiDropdownMenuSubProps,
|
||||||
type TLUiDropdownMenuSubTriggerProps,
|
type TLUiDropdownMenuSubTriggerProps,
|
||||||
type TLUiDropdownMenuTriggerProps,
|
type TLUiDropdownMenuTriggerProps,
|
||||||
} from './lib/ui/components/primitives/DropdownMenu'
|
} from './lib/ui/components/primitives/TldrawUiDropdownMenu'
|
||||||
|
|
||||||
|
// Icon
|
||||||
|
export { TldrawUiIcon, type TLUiIconProps } from './lib/ui/components/primitives/TldrawUiIcon'
|
||||||
|
|
||||||
|
// Input
|
||||||
|
export { TldrawUiInput, type TLUiInputProps } from './lib/ui/components/primitives/TldrawUiInput'
|
||||||
|
|
||||||
|
// Kbd
|
||||||
|
export { TldrawUiKbd, type TLUiKbdProps } from './lib/ui/components/primitives/TldrawUiKbd'
|
||||||
|
|
||||||
|
// Popover
|
||||||
export {
|
export {
|
||||||
Popover,
|
TldrawUiPopover,
|
||||||
PopoverContent,
|
TldrawUiPopoverContent,
|
||||||
PopoverTrigger,
|
TldrawUiPopoverTrigger,
|
||||||
type TLUiPopoverContentProps,
|
type TLUiPopoverContentProps,
|
||||||
type TLUiPopoverProps,
|
type TLUiPopoverProps,
|
||||||
type TLUiPopoverTriggerProps,
|
type TLUiPopoverTriggerProps,
|
||||||
} from './lib/ui/components/primitives/Popover'
|
} from './lib/ui/components/primitives/TldrawUiPopover'
|
||||||
|
|
||||||
|
// Slider
|
||||||
|
export { TldrawUiSlider, type TLUiSliderProps } from './lib/ui/components/primitives/TldrawUiSlider'
|
||||||
|
|
||||||
|
/* ----------------- Menu Primitives ---------------- */
|
||||||
|
|
||||||
|
// General UI components for building menus
|
||||||
|
export {
|
||||||
|
TldrawUiMenuCheckboxItem,
|
||||||
|
type TLUiMenuCheckboxItemProps,
|
||||||
|
} from './lib/ui/components/primitives/menus/TldrawUiMenuCheckboxItem'
|
||||||
|
export {
|
||||||
|
TldrawUiMenuContextProvider,
|
||||||
|
type TLUiMenuContextProviderProps,
|
||||||
|
} from './lib/ui/components/primitives/menus/TldrawUiMenuContext'
|
||||||
|
export {
|
||||||
|
TldrawUiMenuGroup,
|
||||||
|
type TLUiMenuGroupProps,
|
||||||
|
} from './lib/ui/components/primitives/menus/TldrawUiMenuGroup'
|
||||||
|
export {
|
||||||
|
TldrawUiMenuItem,
|
||||||
|
type TLUiMenuItemProps,
|
||||||
|
} from './lib/ui/components/primitives/menus/TldrawUiMenuItem'
|
||||||
|
export {
|
||||||
|
TldrawUiMenuSubmenu,
|
||||||
|
type TLUiMenuSubmenuProps,
|
||||||
|
} from './lib/ui/components/primitives/menus/TldrawUiMenuSubmenu'
|
||||||
|
|
|
@ -3,6 +3,7 @@ export type StyleValuesForUi<T> = readonly {
|
||||||
readonly icon: string
|
readonly icon: string
|
||||||
}[]
|
}[]
|
||||||
|
|
||||||
|
// todo: default styles prop?
|
||||||
export const STYLES = {
|
export const STYLES = {
|
||||||
color: [
|
color: [
|
||||||
{ value: 'black', icon: 'color' },
|
{ value: 'black', icon: 'color' },
|
|
@ -75,6 +75,10 @@
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tlui-button__icon + .tlui-button__label {
|
||||||
|
margin-left: var(--space-2);
|
||||||
|
}
|
||||||
|
|
||||||
@media (hover: hover) {
|
@media (hover: hover) {
|
||||||
.tlui-button::after {
|
.tlui-button::after {
|
||||||
background-color: var(--color-muted-2);
|
background-color: var(--color-muted-2);
|
||||||
|
@ -127,46 +131,6 @@
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Icon button */
|
|
||||||
|
|
||||||
.tlui-button__icon {
|
|
||||||
height: 40px;
|
|
||||||
width: 40px;
|
|
||||||
min-height: 40px;
|
|
||||||
min-width: 40px;
|
|
||||||
padding: 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tlui-button__icon-left {
|
|
||||||
margin-right: var(--space-2);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Hinted */
|
|
||||||
|
|
||||||
.tlui-button__icon[data-state='hinted']::after {
|
|
||||||
background: var(--color-hint);
|
|
||||||
opacity: 1;
|
|
||||||
/* box-shadow: inset 0 0 0 1px var(--color-muted-1); */
|
|
||||||
}
|
|
||||||
|
|
||||||
.tlui-button__icon[data-state='hinted']:not(:disabled, :focus-visible):active::after {
|
|
||||||
background: var(--color-hint);
|
|
||||||
opacity: 1;
|
|
||||||
/* box-shadow: inset 0 0 0 1px var(--color-text-3); */
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (hover: hover) {
|
|
||||||
.tlui-button__icon::after {
|
|
||||||
inset: 4px;
|
|
||||||
border-radius: var(--radius-2);
|
|
||||||
}
|
|
||||||
|
|
||||||
.tlui-button__icon[data-state='hinted']:not(:disabled, :focus-visible):hover::after {
|
|
||||||
background: var(--color-hint);
|
|
||||||
/* box-shadow: inset 0 0 0 1px var(--color-text-3); */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Menu button */
|
/* Menu button */
|
||||||
|
|
||||||
.tlui-button__menu {
|
.tlui-button__menu {
|
||||||
|
@ -1225,11 +1189,6 @@
|
||||||
width: 128px;
|
width: 128px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tlui-page-menu__trigger > span {
|
|
||||||
flex-grow: 2;
|
|
||||||
margin-right: var(--space-4);
|
|
||||||
}
|
|
||||||
|
|
||||||
.tlui-page-menu__header {
|
.tlui-page-menu__header {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
|
@ -1373,17 +1332,29 @@
|
||||||
|
|
||||||
.tlui-page_menu__item__submenu[data-isediting='true'] {
|
.tlui-page_menu__item__submenu[data-isediting='true'] {
|
||||||
display: block;
|
display: block;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tlui-page_menu__item__submenu > .tlui-button {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tlui-page-menu__item__button .tlui-button__icon {
|
||||||
|
margin-right: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (hover: hover) {
|
@media (hover: hover) {
|
||||||
.tlui-page_menu__item__submenu {
|
.tlui-page_menu__item__submenu {
|
||||||
opacity: 0;
|
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tlui-page_menu__item__submenu:hover,
|
.tlui-page_menu__item__submenu[data-isediting='true'] > .tlui-button {
|
||||||
.tlui-page-menu__item:focus-within > .tlui-page_menu__item__submenu,
|
opacity: 0;
|
||||||
.tlui-page_menu__item__sortable:focus-within > .tlui-page_menu__item__submenu {
|
}
|
||||||
|
|
||||||
|
.tlui-page_menu__item__submenu > .tlui-button[data-state='open'],
|
||||||
|
.tlui-page_menu__item__submenu:hover > .tlui-button,
|
||||||
|
.tlui-page_menu__item__sortable:focus-within > .tlui-page_menu__item__submenu > .tlui-button {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,9 +6,9 @@ import { TLUiAssetUrlOverrides } from './assetUrls'
|
||||||
import { DebugPanel } from './components/DebugPanel'
|
import { DebugPanel } from './components/DebugPanel'
|
||||||
import { Dialogs } from './components/Dialogs'
|
import { Dialogs } from './components/Dialogs'
|
||||||
import { FollowingIndicator } from './components/FollowingIndicator'
|
import { FollowingIndicator } from './components/FollowingIndicator'
|
||||||
import { MenuZone } from './components/MenuZone'
|
|
||||||
import { ToastViewport, Toasts } from './components/Toasts'
|
import { ToastViewport, Toasts } from './components/Toasts'
|
||||||
import { Button } from './components/primitives/Button'
|
import { TldrawUiButton } from './components/primitives/Button/TldrawUiButton'
|
||||||
|
import { TldrawUiButtonIcon } from './components/primitives/Button/TldrawUiButtonIcon'
|
||||||
import { PORTRAIT_BREAKPOINT } from './constants'
|
import { PORTRAIT_BREAKPOINT } from './constants'
|
||||||
import {
|
import {
|
||||||
TldrawUiContextProvider,
|
TldrawUiContextProvider,
|
||||||
|
@ -20,6 +20,7 @@ import { TLUiComponents, useTldrawUiComponents } from './context/components'
|
||||||
import { useNativeClipboardEvents } from './hooks/useClipboardEvents'
|
import { useNativeClipboardEvents } from './hooks/useClipboardEvents'
|
||||||
import { useEditorEvents } from './hooks/useEditorEvents'
|
import { useEditorEvents } from './hooks/useEditorEvents'
|
||||||
import { useKeyboardShortcuts } from './hooks/useKeyboardShortcuts'
|
import { useKeyboardShortcuts } from './hooks/useKeyboardShortcuts'
|
||||||
|
import { useReadonly } from './hooks/useReadonly'
|
||||||
import { useRelevantStyles } from './hooks/useRevelantStyles'
|
import { useRelevantStyles } from './hooks/useRevelantStyles'
|
||||||
import { useTranslation } from './hooks/useTranslation/useTranslation'
|
import { useTranslation } from './hooks/useTranslation/useTranslation'
|
||||||
|
|
||||||
|
@ -51,17 +52,6 @@ export interface TldrawUiBaseProps {
|
||||||
*/
|
*/
|
||||||
components?: TLUiComponents
|
components?: TLUiComponents
|
||||||
|
|
||||||
/**
|
|
||||||
* A component to use for the share zone (will be deprecated)
|
|
||||||
*/
|
|
||||||
shareZone?: ReactNode
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A component to use for the top zone (will be deprecated)
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
topZone?: ReactNode
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Additional items to add to the debug menu (will be deprecated)
|
* Additional items to add to the debug menu (will be deprecated)
|
||||||
*/
|
*/
|
||||||
|
@ -75,8 +65,6 @@ export interface TldrawUiBaseProps {
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
export const TldrawUi = React.memo(function TldrawUi({
|
export const TldrawUi = React.memo(function TldrawUi({
|
||||||
shareZone,
|
|
||||||
topZone,
|
|
||||||
renderDebugMenuItems,
|
renderDebugMenuItems,
|
||||||
children,
|
children,
|
||||||
hideUi,
|
hideUi,
|
||||||
|
@ -85,12 +73,7 @@ export const TldrawUi = React.memo(function TldrawUi({
|
||||||
}: TldrawUiProps) {
|
}: TldrawUiProps) {
|
||||||
return (
|
return (
|
||||||
<TldrawUiContextProvider {...rest} components={components}>
|
<TldrawUiContextProvider {...rest} components={components}>
|
||||||
<TldrawUiInner
|
<TldrawUiInner hideUi={hideUi} renderDebugMenuItems={renderDebugMenuItems}>
|
||||||
hideUi={hideUi}
|
|
||||||
shareZone={shareZone}
|
|
||||||
topZone={topZone}
|
|
||||||
renderDebugMenuItems={renderDebugMenuItems}
|
|
||||||
>
|
|
||||||
{children}
|
{children}
|
||||||
</TldrawUiInner>
|
</TldrawUiInner>
|
||||||
</TldrawUiContextProvider>
|
</TldrawUiContextProvider>
|
||||||
|
@ -121,17 +104,24 @@ const TldrawUiInner = React.memo(function TldrawUiInner({
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
const TldrawUiContent = React.memo(function TldrawUI({ shareZone, topZone }: TldrawUiContentProps) {
|
const TldrawUiContent = React.memo(function TldrawUI() {
|
||||||
const editor = useEditor()
|
const editor = useEditor()
|
||||||
const msg = useTranslation()
|
const msg = useTranslation()
|
||||||
const breakpoint = useBreakpoint()
|
const breakpoint = useBreakpoint()
|
||||||
const isReadonlyMode = useValue('isReadonlyMode', () => editor.getInstanceState().isReadonly, [
|
const isReadonlyMode = useReadonly()
|
||||||
editor,
|
|
||||||
])
|
|
||||||
const isFocusMode = useValue('focus', () => editor.getInstanceState().isFocusMode, [editor])
|
const isFocusMode = useValue('focus', () => editor.getInstanceState().isFocusMode, [editor])
|
||||||
const isDebugMode = useValue('debug', () => editor.getInstanceState().isDebugMode, [editor])
|
const isDebugMode = useValue('debug', () => editor.getInstanceState().isDebugMode, [editor])
|
||||||
|
|
||||||
const { StylePanel, Toolbar, HelpMenu, NavigationPanel, HelperButtons } = useTldrawUiComponents()
|
const {
|
||||||
|
SharePanel,
|
||||||
|
TopPanel,
|
||||||
|
MenuPanel,
|
||||||
|
StylePanel,
|
||||||
|
Toolbar,
|
||||||
|
HelpMenu,
|
||||||
|
NavigationPanel,
|
||||||
|
HelperButtons,
|
||||||
|
} = useTldrawUiComponents()
|
||||||
|
|
||||||
useKeyboardShortcuts()
|
useKeyboardShortcuts()
|
||||||
useNativeClipboardEvents()
|
useNativeClipboardEvents()
|
||||||
|
@ -149,24 +139,25 @@ const TldrawUiContent = React.memo(function TldrawUI({ shareZone, topZone }: Tld
|
||||||
>
|
>
|
||||||
{isFocusMode ? (
|
{isFocusMode ? (
|
||||||
<div className="tlui-layout__top">
|
<div className="tlui-layout__top">
|
||||||
<Button
|
<TldrawUiButton
|
||||||
type="icon"
|
type="icon"
|
||||||
className="tlui-focus-button"
|
className="tlui-focus-button"
|
||||||
title={`${msg('focus-mode.toggle-focus-mode')}`}
|
title={msg('focus-mode.toggle-focus-mode')}
|
||||||
icon="dot"
|
|
||||||
onClick={() => toggleFocus.onSelect('menu')}
|
onClick={() => toggleFocus.onSelect('menu')}
|
||||||
/>
|
>
|
||||||
|
<TldrawUiButtonIcon icon="dot" />
|
||||||
|
</TldrawUiButton>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<div className="tlui-layout__top">
|
<div className="tlui-layout__top">
|
||||||
<div className="tlui-layout__top__left">
|
<div className="tlui-layout__top__left">
|
||||||
<MenuZone />
|
{MenuPanel && <MenuPanel />}
|
||||||
{HelperButtons && <HelperButtons />}
|
{HelperButtons && <HelperButtons />}
|
||||||
</div>
|
</div>
|
||||||
<div className="tlui-layout__top__center">{topZone}</div>
|
<div className="tlui-layout__top__center">{TopPanel && <TopPanel />}</div>
|
||||||
<div className="tlui-layout__top__right">
|
<div className="tlui-layout__top__right">
|
||||||
{shareZone}
|
{SharePanel && <SharePanel />}
|
||||||
{StylePanel && breakpoint >= PORTRAIT_BREAKPOINT.TABLET_SM && !isReadonlyMode && (
|
{StylePanel && breakpoint >= PORTRAIT_BREAKPOINT.TABLET_SM && !isReadonlyMode && (
|
||||||
<_StylePanel />
|
<_StylePanel />
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -4,8 +4,14 @@ import { PORTRAIT_BREAKPOINT } from '../../constants'
|
||||||
import { useBreakpoint } from '../../context/breakpoints'
|
import { useBreakpoint } from '../../context/breakpoints'
|
||||||
import { useReadonly } from '../../hooks/useReadonly'
|
import { useReadonly } from '../../hooks/useReadonly'
|
||||||
import { useTranslation } from '../../hooks/useTranslation/useTranslation'
|
import { useTranslation } from '../../hooks/useTranslation/useTranslation'
|
||||||
import { TldrawUiMenuContextProvider } from '../menus/TldrawUiMenuContext'
|
import { TldrawUiButton } from '../primitives/Button/TldrawUiButton'
|
||||||
import { Popover, PopoverContent, PopoverTrigger } from '../primitives/Popover'
|
import { TldrawUiButtonIcon } from '../primitives/Button/TldrawUiButtonIcon'
|
||||||
|
import {
|
||||||
|
TldrawUiPopover,
|
||||||
|
TldrawUiPopoverContent,
|
||||||
|
TldrawUiPopoverTrigger,
|
||||||
|
} from '../primitives/TldrawUiPopover'
|
||||||
|
import { TldrawUiMenuContextProvider } from '../primitives/menus/TldrawUiMenuContext'
|
||||||
import { DefaultActionsMenuContent } from './DefaultActionsMenuContent'
|
import { DefaultActionsMenuContent } from './DefaultActionsMenuContent'
|
||||||
|
|
||||||
/** @public */
|
/** @public */
|
||||||
|
@ -37,16 +43,17 @@ export const DefaultActionsMenu = memo(function DefaultActionsMenu({
|
||||||
if (isReadonlyMode && !isInAcceptableReadonlyState) return
|
if (isReadonlyMode && !isInAcceptableReadonlyState) return
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Popover id="actions-menu">
|
<TldrawUiPopover id="actions-menu">
|
||||||
<PopoverTrigger
|
<TldrawUiPopoverTrigger>
|
||||||
className="tlui-menu__trigger"
|
<TldrawUiButton
|
||||||
|
type="icon"
|
||||||
data-testid="main.action-menu"
|
data-testid="main.action-menu"
|
||||||
icon="dots-vertical"
|
|
||||||
title={msg('actions-menu.title')}
|
title={msg('actions-menu.title')}
|
||||||
type="icon" // needs to be here because the trigger also passes down type="button"
|
>
|
||||||
smallIcon
|
<TldrawUiButtonIcon icon="dots-vertical" small />
|
||||||
/>
|
</TldrawUiButton>
|
||||||
<PopoverContent
|
</TldrawUiPopoverTrigger>
|
||||||
|
<TldrawUiPopoverContent
|
||||||
side={breakpoint >= PORTRAIT_BREAKPOINT.TABLET ? 'bottom' : 'top'}
|
side={breakpoint >= PORTRAIT_BREAKPOINT.TABLET ? 'bottom' : 'top'}
|
||||||
sideOffset={6}
|
sideOffset={6}
|
||||||
>
|
>
|
||||||
|
@ -55,7 +62,7 @@ export const DefaultActionsMenu = memo(function DefaultActionsMenu({
|
||||||
{content}
|
{content}
|
||||||
</TldrawUiMenuContextProvider>
|
</TldrawUiMenuContextProvider>
|
||||||
</div>
|
</div>
|
||||||
</PopoverContent>
|
</TldrawUiPopoverContent>
|
||||||
</Popover>
|
</TldrawUiPopover>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
|
@ -9,7 +9,7 @@ import {
|
||||||
useThreeStackableItems,
|
useThreeStackableItems,
|
||||||
useUnlockedSelectedShapesCount,
|
useUnlockedSelectedShapesCount,
|
||||||
} from '../../hooks/menu-hooks'
|
} from '../../hooks/menu-hooks'
|
||||||
import { TldrawUiMenuItem } from '../menus/TldrawUiMenuItem'
|
import { TldrawUiMenuItem } from '../primitives/menus/TldrawUiMenuItem'
|
||||||
|
|
||||||
/** @public */
|
/** @public */
|
||||||
export function DefaultActionsMenuContent() {
|
export function DefaultActionsMenuContent() {
|
||||||
|
|
|
@ -2,7 +2,7 @@ import * as _ContextMenu from '@radix-ui/react-context-menu'
|
||||||
import { preventDefault, useContainer, useEditor } from '@tldraw/editor'
|
import { preventDefault, useContainer, useEditor } from '@tldraw/editor'
|
||||||
import { memo, useCallback } from 'react'
|
import { memo, useCallback } from 'react'
|
||||||
import { useMenuIsOpen } from '../../hooks/useMenuIsOpen'
|
import { useMenuIsOpen } from '../../hooks/useMenuIsOpen'
|
||||||
import { TldrawUiMenuContextProvider } from '../menus/TldrawUiMenuContext'
|
import { TldrawUiMenuContextProvider } from '../primitives/menus/TldrawUiMenuContext'
|
||||||
import { DefaultContextMenuContent } from './DefaultContextMenuContent'
|
import { DefaultContextMenuContent } from './DefaultContextMenuContent'
|
||||||
|
|
||||||
/** @public */
|
/** @public */
|
||||||
|
|
|
@ -17,7 +17,7 @@ import {
|
||||||
ToggleLockMenuItem,
|
ToggleLockMenuItem,
|
||||||
UngroupMenuItem,
|
UngroupMenuItem,
|
||||||
} from '../menu-items'
|
} from '../menu-items'
|
||||||
import { TldrawUiMenuGroup } from '../menus/TldrawUiMenuGroup'
|
import { TldrawUiMenuGroup } from '../primitives/menus/TldrawUiMenuGroup'
|
||||||
|
|
||||||
/** @public */
|
/** @public */
|
||||||
export function DefaultContextMenuContent() {
|
export function DefaultContextMenuContent() {
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
import { useTranslation } from '../../hooks/useTranslation/useTranslation'
|
import { useTranslation } from '../../hooks/useTranslation/useTranslation'
|
||||||
import { TldrawUiMenuContextProvider } from '../menus/TldrawUiMenuContext'
|
import { TldrawUiButton } from '../primitives/Button/TldrawUiButton'
|
||||||
|
import { TldrawUiButtonIcon } from '../primitives/Button/TldrawUiButtonIcon'
|
||||||
import {
|
import {
|
||||||
DropdownMenuContent,
|
TldrawUiDropdownMenuContent,
|
||||||
DropdownMenuRoot,
|
TldrawUiDropdownMenuRoot,
|
||||||
DropdownMenuTrigger,
|
TldrawUiDropdownMenuTrigger,
|
||||||
} from '../primitives/DropdownMenu'
|
} from '../primitives/TldrawUiDropdownMenu'
|
||||||
|
import { TldrawUiMenuContextProvider } from '../primitives/menus/TldrawUiMenuContext'
|
||||||
import { DefaultDebugMenuContent } from './DefaultDebugMenuContent'
|
import { DefaultDebugMenuContent } from './DefaultDebugMenuContent'
|
||||||
|
|
||||||
/** @public */
|
/** @public */
|
||||||
|
@ -18,13 +20,17 @@ export function DefaultDebugMenu({ children }: TLUiDebugMenuProps) {
|
||||||
const content = children ?? <DefaultDebugMenuContent />
|
const content = children ?? <DefaultDebugMenuContent />
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DropdownMenuRoot id="debug">
|
<TldrawUiDropdownMenuRoot id="debug">
|
||||||
<DropdownMenuTrigger type="icon" icon="dots-horizontal" title={msg('debug-panel.more')} />
|
<TldrawUiDropdownMenuTrigger>
|
||||||
<DropdownMenuContent side="top" align="end" alignOffset={0}>
|
<TldrawUiButton type="icon" title={msg('debug-menu.title')}>
|
||||||
|
<TldrawUiButtonIcon icon="dots-horizontal" />
|
||||||
|
</TldrawUiButton>
|
||||||
|
</TldrawUiDropdownMenuTrigger>
|
||||||
|
<TldrawUiDropdownMenuContent side="top" align="end" alignOffset={0}>
|
||||||
<TldrawUiMenuContextProvider type="menu" sourceId="debug-panel">
|
<TldrawUiMenuContextProvider type="menu" sourceId="debug-panel">
|
||||||
{content}
|
{content}
|
||||||
</TldrawUiMenuContextProvider>
|
</TldrawUiMenuContextProvider>
|
||||||
</DropdownMenuContent>
|
</TldrawUiDropdownMenuContent>
|
||||||
</DropdownMenuRoot>
|
</TldrawUiDropdownMenuRoot>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import { DialogTitle } from '@radix-ui/react-dialog'
|
|
||||||
import {
|
import {
|
||||||
DebugFlag,
|
DebugFlag,
|
||||||
Editor,
|
Editor,
|
||||||
|
@ -15,12 +14,20 @@ import React from 'react'
|
||||||
import { useDialogs } from '../../context/dialogs'
|
import { useDialogs } from '../../context/dialogs'
|
||||||
import { useToasts } from '../../context/toasts'
|
import { useToasts } from '../../context/toasts'
|
||||||
import { untranslated } from '../../hooks/useTranslation/useTranslation'
|
import { untranslated } from '../../hooks/useTranslation/useTranslation'
|
||||||
import { TldrawUiMenuCheckboxItem } from '../menus/TldrawUiMenuCheckboxItem'
|
import { TldrawUiButton } from '../primitives/Button/TldrawUiButton'
|
||||||
import { TldrawUiMenuGroup } from '../menus/TldrawUiMenuGroup'
|
import { TldrawUiButtonCheck } from '../primitives/Button/TldrawUiButtonCheck'
|
||||||
import { TldrawUiMenuItem } from '../menus/TldrawUiMenuItem'
|
import { TldrawUiButtonLabel } from '../primitives/Button/TldrawUiButtonLabel'
|
||||||
import { TldrawUiMenuSubmenu } from '../menus/TldrawUiMenuSubmenu'
|
import {
|
||||||
import { Button } from '../primitives/Button'
|
TldrawUiDialogBody,
|
||||||
import { DialogBody, DialogCloseButton, DialogFooter, DialogHeader } from '../primitives/Dialog'
|
TldrawUiDialogCloseButton,
|
||||||
|
TldrawUiDialogFooter,
|
||||||
|
TldrawUiDialogHeader,
|
||||||
|
TldrawUiDialogTitle,
|
||||||
|
} from '../primitives/TldrawUiDialog'
|
||||||
|
import { TldrawUiMenuCheckboxItem } from '../primitives/menus/TldrawUiMenuCheckboxItem'
|
||||||
|
import { TldrawUiMenuGroup } from '../primitives/menus/TldrawUiMenuGroup'
|
||||||
|
import { TldrawUiMenuItem } from '../primitives/menus/TldrawUiMenuItem'
|
||||||
|
import { TldrawUiMenuSubmenu } from '../primitives/menus/TldrawUiMenuSubmenu'
|
||||||
|
|
||||||
/** @public */
|
/** @public */
|
||||||
export function DefaultDebugMenuContent() {
|
export function DefaultDebugMenuContent() {
|
||||||
|
@ -225,29 +232,29 @@ function ExampleDialog({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<DialogHeader>
|
<TldrawUiDialogHeader>
|
||||||
<DialogTitle>{title}</DialogTitle>
|
<TldrawUiDialogTitle>{title}</TldrawUiDialogTitle>
|
||||||
<DialogCloseButton />
|
<TldrawUiDialogCloseButton />
|
||||||
</DialogHeader>
|
</TldrawUiDialogHeader>
|
||||||
<DialogBody style={{ maxWidth: 350 }}>{body}</DialogBody>
|
<TldrawUiDialogBody style={{ maxWidth: 350 }}>{body}</TldrawUiDialogBody>
|
||||||
<DialogFooter className="tlui-dialog__footer__actions">
|
<TldrawUiDialogFooter className="tlui-dialog__footer__actions">
|
||||||
{displayDontShowAgain && (
|
{displayDontShowAgain && (
|
||||||
<Button
|
<TldrawUiButton
|
||||||
type="normal"
|
type="normal"
|
||||||
onClick={() => setDontShowAgain(!dontShowAgain)}
|
onClick={() => setDontShowAgain(!dontShowAgain)}
|
||||||
iconLeft={dontShowAgain ? 'check' : 'checkbox-empty'}
|
|
||||||
style={{ marginRight: 'auto' }}
|
style={{ marginRight: 'auto' }}
|
||||||
>
|
>
|
||||||
{`Don't show again`}
|
<TldrawUiButtonCheck checked={dontShowAgain} />
|
||||||
</Button>
|
<TldrawUiButtonLabel>Don't show again</TldrawUiButtonLabel>
|
||||||
|
</TldrawUiButton>
|
||||||
)}
|
)}
|
||||||
<Button type="normal" onClick={onCancel}>
|
<TldrawUiButton type="normal" onClick={onCancel}>
|
||||||
{cancel}
|
<TldrawUiButtonLabel>{cancel}</TldrawUiButtonLabel>
|
||||||
</Button>
|
</TldrawUiButton>
|
||||||
<Button type="primary" onClick={async () => onContinue()}>
|
<TldrawUiButton type="primary" onClick={async () => onContinue()}>
|
||||||
{confirm}
|
<TldrawUiButtonLabel>{confirm}</TldrawUiButtonLabel>
|
||||||
</Button>
|
</TldrawUiButton>
|
||||||
</DialogFooter>
|
</TldrawUiDialogFooter>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,9 +3,15 @@ import { T, TLBaseShape, track, useEditor } from '@tldraw/editor'
|
||||||
import { useCallback, useEffect, useRef, useState } from 'react'
|
import { useCallback, useEffect, useRef, useState } from 'react'
|
||||||
import { TLUiDialogProps } from '../context/dialogs'
|
import { TLUiDialogProps } from '../context/dialogs'
|
||||||
import { useTranslation } from '../hooks/useTranslation/useTranslation'
|
import { useTranslation } from '../hooks/useTranslation/useTranslation'
|
||||||
import { Button } from './primitives/Button'
|
import { TldrawUiButton } from './primitives/Button/TldrawUiButton'
|
||||||
import { DialogBody, DialogCloseButton, DialogFooter, DialogHeader } from './primitives/Dialog'
|
import { TldrawUiButtonLabel } from './primitives/Button/TldrawUiButtonLabel'
|
||||||
import { Input } from './primitives/Input'
|
import {
|
||||||
|
TldrawUiDialogBody,
|
||||||
|
TldrawUiDialogCloseButton,
|
||||||
|
TldrawUiDialogFooter,
|
||||||
|
TldrawUiDialogHeader,
|
||||||
|
} from './primitives/TldrawUiDialog'
|
||||||
|
import { TldrawUiInput } from './primitives/TldrawUiInput'
|
||||||
|
|
||||||
// A url can either be invalid, or valid with a protocol, or valid without a protocol.
|
// A url can either be invalid, or valid with a protocol, or valid without a protocol.
|
||||||
// For example, "aol.com" would be valid with a protocol ()
|
// For example, "aol.com" would be valid with a protocol ()
|
||||||
|
@ -134,13 +140,13 @@ export const EditLinkDialogInner = track(function EditLinkDialogInner({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<DialogHeader>
|
<TldrawUiDialogHeader>
|
||||||
<DialogTitle>{msg('edit-link-title')}</DialogTitle>
|
<DialogTitle>{msg('edit-link-title')}</DialogTitle>
|
||||||
<DialogCloseButton />
|
<TldrawUiDialogCloseButton />
|
||||||
</DialogHeader>
|
</TldrawUiDialogHeader>
|
||||||
<DialogBody>
|
<TldrawUiDialogBody>
|
||||||
<div className="tlui-edit-link-dialog">
|
<div className="tlui-edit-link-dialog">
|
||||||
<Input
|
<TldrawUiInput
|
||||||
ref={rInput}
|
ref={rInput}
|
||||||
className="tlui-edit-link-dialog__input"
|
className="tlui-edit-link-dialog__input"
|
||||||
label="edit-link-url"
|
label="edit-link-url"
|
||||||
|
@ -152,26 +158,26 @@ export const EditLinkDialogInner = track(function EditLinkDialogInner({
|
||||||
/>
|
/>
|
||||||
<div>{urlInputState.valid ? msg('edit-link-detail') : msg('edit-link-invalid-url')}</div>
|
<div>{urlInputState.valid ? msg('edit-link-detail') : msg('edit-link-invalid-url')}</div>
|
||||||
</div>
|
</div>
|
||||||
</DialogBody>
|
</TldrawUiDialogBody>
|
||||||
<DialogFooter className="tlui-dialog__footer__actions">
|
<TldrawUiDialogFooter className="tlui-dialog__footer__actions">
|
||||||
<Button type="normal" onClick={handleCancel} onTouchEnd={handleCancel}>
|
<TldrawUiButton type="normal" onClick={handleCancel} onTouchEnd={handleCancel}>
|
||||||
{msg('edit-link-cancel')}
|
<TldrawUiButtonLabel>{msg('edit-link-cancel')}</TldrawUiButtonLabel>
|
||||||
</Button>
|
</TldrawUiButton>
|
||||||
{isRemoving ? (
|
{isRemoving ? (
|
||||||
<Button type={'danger'} onTouchEnd={handleClear} onClick={handleClear}>
|
<TldrawUiButton type={'danger'} onTouchEnd={handleClear} onClick={handleClear}>
|
||||||
{msg('edit-link-clear')}
|
<TldrawUiButtonLabel>{msg('edit-link-clear')}</TldrawUiButtonLabel>
|
||||||
</Button>
|
</TldrawUiButton>
|
||||||
) : (
|
) : (
|
||||||
<Button
|
<TldrawUiButton
|
||||||
type="primary"
|
type="primary"
|
||||||
disabled={!urlInputState.valid}
|
disabled={!urlInputState.valid}
|
||||||
onTouchEnd={handleComplete}
|
onTouchEnd={handleComplete}
|
||||||
onClick={handleComplete}
|
onClick={handleComplete}
|
||||||
>
|
>
|
||||||
{msg('edit-link-save')}
|
<TldrawUiButtonLabel>{msg('edit-link-save')}</TldrawUiButtonLabel>
|
||||||
</Button>
|
</TldrawUiButton>
|
||||||
)}
|
)}
|
||||||
</DialogFooter>
|
</TldrawUiDialogFooter>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
|
@ -5,10 +5,16 @@ import { TLEmbedResult, getEmbedInfo } from '../../utils/embeds/embeds'
|
||||||
import { useAssetUrls } from '../context/asset-urls'
|
import { useAssetUrls } from '../context/asset-urls'
|
||||||
import { TLUiDialogProps } from '../context/dialogs'
|
import { TLUiDialogProps } from '../context/dialogs'
|
||||||
import { untranslated, useTranslation } from '../hooks/useTranslation/useTranslation'
|
import { untranslated, useTranslation } from '../hooks/useTranslation/useTranslation'
|
||||||
import { Button } from './primitives/Button'
|
import { TldrawUiButton } from './primitives/Button/TldrawUiButton'
|
||||||
import { DialogBody, DialogCloseButton, DialogFooter, DialogHeader } from './primitives/Dialog'
|
import { TldrawUiButtonLabel } from './primitives/Button/TldrawUiButtonLabel'
|
||||||
import { Icon } from './primitives/Icon'
|
import {
|
||||||
import { Input } from './primitives/Input'
|
TldrawUiDialogBody,
|
||||||
|
TldrawUiDialogCloseButton,
|
||||||
|
TldrawUiDialogFooter,
|
||||||
|
TldrawUiDialogHeader,
|
||||||
|
} from './primitives/TldrawUiDialog'
|
||||||
|
import { TldrawUiIcon } from './primitives/TldrawUiIcon'
|
||||||
|
import { TldrawUiInput } from './primitives/TldrawUiInput'
|
||||||
|
|
||||||
export const EmbedDialog = track(function EmbedDialog({ onClose }: TLUiDialogProps) {
|
export const EmbedDialog = track(function EmbedDialog({ onClose }: TLUiDialogProps) {
|
||||||
const editor = useEditor()
|
const editor = useEditor()
|
||||||
|
@ -30,18 +36,18 @@ export const EmbedDialog = track(function EmbedDialog({ onClose }: TLUiDialogPro
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<DialogHeader>
|
<TldrawUiDialogHeader>
|
||||||
<DialogTitle>
|
<DialogTitle>
|
||||||
{embedDefinition
|
{embedDefinition
|
||||||
? `${msg('embed-title')} — ${embedDefinition.title}`
|
? `${msg('embed-title')} — ${embedDefinition.title}`
|
||||||
: msg('embed-title')}
|
: msg('embed-title')}
|
||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
<DialogCloseButton />
|
<TldrawUiDialogCloseButton />
|
||||||
</DialogHeader>
|
</TldrawUiDialogHeader>
|
||||||
{embedDefinition ? (
|
{embedDefinition ? (
|
||||||
<>
|
<>
|
||||||
<DialogBody className="tlui-embed-dialog__enter">
|
<TldrawUiDialogBody className="tlui-embed-dialog__enter">
|
||||||
<Input
|
<TldrawUiInput
|
||||||
className="tlui-embed-dialog__input"
|
className="tlui-embed-dialog__input"
|
||||||
label="embed-url"
|
label="embed-url"
|
||||||
placeholder="http://example.com"
|
placeholder="http://example.com"
|
||||||
|
@ -77,7 +83,7 @@ export const EmbedDialog = track(function EmbedDialog({ onClose }: TLUiDialogPro
|
||||||
className="tlui-embed-dialog__instruction__link"
|
className="tlui-embed-dialog__instruction__link"
|
||||||
>
|
>
|
||||||
Learn more.
|
Learn more.
|
||||||
<Icon icon="external-link" small />
|
<TldrawUiIcon icon="external-link" small />
|
||||||
</a>
|
</a>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
@ -86,23 +92,25 @@ export const EmbedDialog = track(function EmbedDialog({ onClose }: TLUiDialogPro
|
||||||
{showError ? msg('embed-invalid-url') : '\xa0'}
|
{showError ? msg('embed-invalid-url') : '\xa0'}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</DialogBody>
|
</TldrawUiDialogBody>
|
||||||
<DialogFooter className="tlui-dialog__footer__actions">
|
<TldrawUiDialogFooter className="tlui-dialog__footer__actions">
|
||||||
<Button
|
<TldrawUiButton
|
||||||
type="normal"
|
type="normal"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setEmbedDefinition(null)
|
setEmbedDefinition(null)
|
||||||
setEmbedInfoForUrl(null)
|
setEmbedInfoForUrl(null)
|
||||||
setUrl('')
|
setUrl('')
|
||||||
}}
|
}}
|
||||||
label="embed-back"
|
>
|
||||||
/>
|
<TldrawUiButtonLabel>{msg('embed-back')}</TldrawUiButtonLabel>
|
||||||
|
</TldrawUiButton>
|
||||||
<div className="tlui-embed__spacer" />
|
<div className="tlui-embed__spacer" />
|
||||||
<Button type="normal" label="embed-cancel" onClick={onClose} />
|
<TldrawUiButton type="normal" onClick={onClose}>
|
||||||
<Button
|
<TldrawUiButtonLabel>{msg('embed-cancel')}</TldrawUiButtonLabel>
|
||||||
|
</TldrawUiButton>
|
||||||
|
<TldrawUiButton
|
||||||
type="primary"
|
type="primary"
|
||||||
disabled={!embedInfoForUrl}
|
disabled={!embedInfoForUrl}
|
||||||
label="embed-create"
|
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (!embedInfoForUrl) return
|
if (!embedInfoForUrl) return
|
||||||
|
|
||||||
|
@ -115,28 +123,26 @@ export const EmbedDialog = track(function EmbedDialog({ onClose }: TLUiDialogPro
|
||||||
|
|
||||||
onClose()
|
onClose()
|
||||||
}}
|
}}
|
||||||
/>
|
>
|
||||||
</DialogFooter>
|
<TldrawUiButtonLabel>{msg('embed-create')}</TldrawUiButtonLabel>
|
||||||
|
</TldrawUiButton>
|
||||||
|
</TldrawUiDialogFooter>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<DialogBody className="tlui-embed-dialog__list">
|
<TldrawUiDialogBody className="tlui-embed-dialog__list">
|
||||||
{EMBED_DEFINITIONS.map((def) => {
|
{EMBED_DEFINITIONS.map((def) => {
|
||||||
return (
|
return (
|
||||||
<Button
|
<TldrawUiButton type="menu" key={def.type} onClick={() => setEmbedDefinition(def)}>
|
||||||
type="menu"
|
<TldrawUiButtonLabel>{untranslated(def.title)}</TldrawUiButtonLabel>
|
||||||
key={def.type}
|
|
||||||
onClick={() => setEmbedDefinition(def)}
|
|
||||||
label={untranslated(def.title)}
|
|
||||||
>
|
|
||||||
<div
|
<div
|
||||||
className="tlui-embed-dialog__item__image"
|
className="tlui-embed-dialog__item__image"
|
||||||
style={{ backgroundImage: `url(${assetUrls.embedIcons[def.type]})` }}
|
style={{ backgroundImage: `url(${assetUrls.embedIcons[def.type]})` }}
|
||||||
/>
|
/>
|
||||||
</Button>
|
</TldrawUiButton>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
</DialogBody>
|
</TldrawUiDialogBody>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -2,12 +2,14 @@ import { memo } from 'react'
|
||||||
import { PORTRAIT_BREAKPOINT } from '../../constants'
|
import { PORTRAIT_BREAKPOINT } from '../../constants'
|
||||||
import { useBreakpoint } from '../../context/breakpoints'
|
import { useBreakpoint } from '../../context/breakpoints'
|
||||||
import { useTranslation } from '../../hooks/useTranslation/useTranslation'
|
import { useTranslation } from '../../hooks/useTranslation/useTranslation'
|
||||||
import { TldrawUiMenuContextProvider } from '../menus/TldrawUiMenuContext'
|
import { TldrawUiButton } from '../primitives/Button/TldrawUiButton'
|
||||||
|
import { TldrawUiButtonIcon } from '../primitives/Button/TldrawUiButtonIcon'
|
||||||
import {
|
import {
|
||||||
DropdownMenuContent,
|
TldrawUiDropdownMenuContent,
|
||||||
DropdownMenuRoot,
|
TldrawUiDropdownMenuRoot,
|
||||||
DropdownMenuTrigger,
|
TldrawUiDropdownMenuTrigger,
|
||||||
} from '../primitives/DropdownMenu'
|
} from '../primitives/TldrawUiDropdownMenu'
|
||||||
|
import { TldrawUiMenuContextProvider } from '../primitives/menus/TldrawUiMenuContext'
|
||||||
import { DefaultHelpMenuContent } from './DefaultHelpMenuContent'
|
import { DefaultHelpMenuContent } from './DefaultHelpMenuContent'
|
||||||
|
|
||||||
/** @public */
|
/** @public */
|
||||||
|
@ -29,19 +31,18 @@ export const DefaultHelpMenu = memo(function DefaultHelpMenu({ children }: TLUiH
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="tlui-help-menu">
|
<div className="tlui-help-menu">
|
||||||
<DropdownMenuRoot id="help menu">
|
<TldrawUiDropdownMenuRoot id="help menu">
|
||||||
<DropdownMenuTrigger
|
<TldrawUiDropdownMenuTrigger>
|
||||||
type="help"
|
<TldrawUiButton type="help" title={msg('help-menu.title')}>
|
||||||
smallIcon
|
<TldrawUiButtonIcon icon="question-mark" small />
|
||||||
title={msg('help-menu.title')}
|
</TldrawUiButton>
|
||||||
icon="question-mark"
|
</TldrawUiDropdownMenuTrigger>
|
||||||
/>
|
<TldrawUiDropdownMenuContent side="top" align="end" alignOffset={0} sideOffset={8}>
|
||||||
<DropdownMenuContent side="top" align="end" alignOffset={0} sideOffset={8}>
|
|
||||||
<TldrawUiMenuContextProvider type="menu" sourceId="help-menu">
|
<TldrawUiMenuContextProvider type="menu" sourceId="help-menu">
|
||||||
{content}
|
{content}
|
||||||
</TldrawUiMenuContextProvider>
|
</TldrawUiMenuContextProvider>
|
||||||
</DropdownMenuContent>
|
</TldrawUiDropdownMenuContent>
|
||||||
</DropdownMenuRoot>
|
</TldrawUiDropdownMenuRoot>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { useTldrawUiComponents } from '../../context/components'
|
import { useTldrawUiComponents } from '../../context/components'
|
||||||
import { useDialogs } from '../../context/dialogs'
|
import { useDialogs } from '../../context/dialogs'
|
||||||
import { LanguageMenu } from '../LanguageMenu'
|
import { LanguageMenu } from '../LanguageMenu'
|
||||||
import { TldrawUiMenuItem } from '../menus/TldrawUiMenuItem'
|
import { TldrawUiMenuItem } from '../primitives/menus/TldrawUiMenuItem'
|
||||||
|
|
||||||
/** @public */
|
/** @public */
|
||||||
export function DefaultHelpMenuContent() {
|
export function DefaultHelpMenuContent() {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { useEditor } from '@tldraw/editor'
|
import { useEditor } from '@tldraw/editor'
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
import { useActions } from '../../context/actions'
|
import { useActions } from '../../context/actions'
|
||||||
import { TldrawUiMenuItem } from '../menus/TldrawUiMenuItem'
|
import { TldrawUiMenuItem } from '../primitives/menus/TldrawUiMenuItem'
|
||||||
|
|
||||||
export function BackToContent() {
|
export function BackToContent() {
|
||||||
const editor = useEditor()
|
const editor = useEditor()
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { TldrawUiMenuContextProvider } from '../menus/TldrawUiMenuContext'
|
import { TldrawUiMenuContextProvider } from '../primitives/menus/TldrawUiMenuContext'
|
||||||
import { DefaultHelperButtonsContent } from './DefaultHelperButtonsContent'
|
import { DefaultHelperButtonsContent } from './DefaultHelperButtonsContent'
|
||||||
|
|
||||||
/** @public */
|
/** @public */
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { useEditor, useValue } from '@tldraw/editor'
|
import { useEditor, useValue } from '@tldraw/editor'
|
||||||
import { useActions } from '../../context/actions'
|
import { useActions } from '../../context/actions'
|
||||||
import { TldrawUiMenuItem } from '../menus/TldrawUiMenuItem'
|
import { TldrawUiMenuItem } from '../primitives/menus/TldrawUiMenuItem'
|
||||||
|
|
||||||
export function ExitPenMode() {
|
export function ExitPenMode() {
|
||||||
const editor = useEditor()
|
const editor = useEditor()
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { useEditor, useValue } from '@tldraw/editor'
|
import { useEditor, useValue } from '@tldraw/editor'
|
||||||
import { useActions } from '../../context/actions'
|
import { useActions } from '../../context/actions'
|
||||||
import { TldrawUiMenuItem } from '../menus/TldrawUiMenuItem'
|
import { TldrawUiMenuItem } from '../primitives/menus/TldrawUiMenuItem'
|
||||||
|
|
||||||
export function StopFollowing() {
|
export function StopFollowing() {
|
||||||
const editor = useEditor()
|
const editor = useEditor()
|
||||||
|
|
|
@ -2,8 +2,12 @@ import { DialogTitle } from '@radix-ui/react-dialog'
|
||||||
import { memo } from 'react'
|
import { memo } from 'react'
|
||||||
import { TLUiDialogProps } from '../../context/dialogs'
|
import { TLUiDialogProps } from '../../context/dialogs'
|
||||||
import { useTranslation } from '../../hooks/useTranslation/useTranslation'
|
import { useTranslation } from '../../hooks/useTranslation/useTranslation'
|
||||||
import { TldrawUiMenuContextProvider } from '../menus/TldrawUiMenuContext'
|
import {
|
||||||
import { DialogBody, DialogCloseButton, DialogHeader } from '../primitives/Dialog'
|
TldrawUiDialogBody,
|
||||||
|
TldrawUiDialogCloseButton,
|
||||||
|
TldrawUiDialogHeader,
|
||||||
|
} from '../primitives/TldrawUiDialog'
|
||||||
|
import { TldrawUiMenuContextProvider } from '../primitives/menus/TldrawUiMenuContext'
|
||||||
import { DefaultKeyboardShortcutsDialogContent } from './DefaultKeyboardShortcutsDialogContent'
|
import { DefaultKeyboardShortcutsDialogContent } from './DefaultKeyboardShortcutsDialogContent'
|
||||||
|
|
||||||
/** @public */
|
/** @public */
|
||||||
|
@ -21,15 +25,15 @@ export const DefaultKeyboardShortcutsDialog = memo(function DefaultKeyboardShort
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<DialogHeader className="tlui-shortcuts-dialog__header">
|
<TldrawUiDialogHeader className="tlui-shortcuts-dialog__header">
|
||||||
<DialogTitle>{msg('shortcuts-title')}</DialogTitle>
|
<DialogTitle>{msg('shortcuts-title')}</DialogTitle>
|
||||||
<DialogCloseButton />
|
<TldrawUiDialogCloseButton />
|
||||||
</DialogHeader>
|
</TldrawUiDialogHeader>
|
||||||
<DialogBody className="tlui-shortcuts-dialog__body">
|
<TldrawUiDialogBody className="tlui-shortcuts-dialog__body">
|
||||||
<TldrawUiMenuContextProvider type="keyboard-shortcuts" sourceId="kbd">
|
<TldrawUiMenuContextProvider type="keyboard-shortcuts" sourceId="kbd">
|
||||||
{content}
|
{content}
|
||||||
</TldrawUiMenuContextProvider>
|
</TldrawUiMenuContextProvider>
|
||||||
</DialogBody>
|
</TldrawUiDialogBody>
|
||||||
<div className="tlui-dialog__scrim" />
|
<div className="tlui-dialog__scrim" />
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { useActions } from '../../context/actions'
|
import { useActions } from '../../context/actions'
|
||||||
import { useTools } from '../../hooks/useTools'
|
import { useTools } from '../../hooks/useTools'
|
||||||
import { TldrawUiMenuGroup } from '../menus/TldrawUiMenuGroup'
|
import { TldrawUiMenuGroup } from '../primitives/menus/TldrawUiMenuGroup'
|
||||||
import { TldrawUiMenuItem } from '../menus/TldrawUiMenuItem'
|
import { TldrawUiMenuItem } from '../primitives/menus/TldrawUiMenuItem'
|
||||||
|
|
||||||
/** @public */
|
/** @public */
|
||||||
export function DefaultKeyboardShortcutsDialogContent() {
|
export function DefaultKeyboardShortcutsDialogContent() {
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import { useEditor } from '@tldraw/editor'
|
import { useEditor } from '@tldraw/editor'
|
||||||
import { useUiEvents } from '../context/events'
|
import { useUiEvents } from '../context/events'
|
||||||
import { useLanguages } from '../hooks/useTranslation/useLanguages'
|
import { useLanguages } from '../hooks/useTranslation/useLanguages'
|
||||||
import { TldrawUiMenuCheckboxItem } from './menus/TldrawUiMenuCheckboxItem'
|
import { TldrawUiMenuCheckboxItem } from './primitives/menus/TldrawUiMenuCheckboxItem'
|
||||||
import { TldrawUiMenuGroup } from './menus/TldrawUiMenuGroup'
|
import { TldrawUiMenuGroup } from './primitives/menus/TldrawUiMenuGroup'
|
||||||
import { TldrawUiMenuSubmenu } from './menus/TldrawUiMenuSubmenu'
|
import { TldrawUiMenuSubmenu } from './primitives/menus/TldrawUiMenuSubmenu'
|
||||||
|
|
||||||
export function LanguageMenu() {
|
export function LanguageMenu() {
|
||||||
const editor = useEditor()
|
const editor = useEditor()
|
||||||
|
|
|
@ -3,8 +3,9 @@ import { useContainer } from '@tldraw/editor'
|
||||||
import { memo } from 'react'
|
import { memo } from 'react'
|
||||||
import { useMenuIsOpen } from '../../hooks/useMenuIsOpen'
|
import { useMenuIsOpen } from '../../hooks/useMenuIsOpen'
|
||||||
import { useTranslation } from '../../hooks/useTranslation/useTranslation'
|
import { useTranslation } from '../../hooks/useTranslation/useTranslation'
|
||||||
import { TldrawUiMenuContextProvider } from '../menus/TldrawUiMenuContext'
|
import { TldrawUiButton } from '../primitives/Button/TldrawUiButton'
|
||||||
import { Button } from '../primitives/Button'
|
import { TldrawUiButtonIcon } from '../primitives/Button/TldrawUiButtonIcon'
|
||||||
|
import { TldrawUiMenuContextProvider } from '../primitives/menus/TldrawUiMenuContext'
|
||||||
import { DefaultMainMenuContent } from './DefaultMainMenuContent'
|
import { DefaultMainMenuContent } from './DefaultMainMenuContent'
|
||||||
|
|
||||||
/** @public */
|
/** @public */
|
||||||
|
@ -26,14 +27,9 @@ export const DefaultMainMenu = memo(function DefaultMainMenu({ children }: TLUiM
|
||||||
return (
|
return (
|
||||||
<_Dropdown.Root dir="ltr" open={isOpen} onOpenChange={onOpenChange} modal={false}>
|
<_Dropdown.Root dir="ltr" open={isOpen} onOpenChange={onOpenChange} modal={false}>
|
||||||
<_Dropdown.Trigger asChild dir="ltr">
|
<_Dropdown.Trigger asChild dir="ltr">
|
||||||
<Button
|
<TldrawUiButton type="icon" data-testid="main.menu" title={msg('menu.title')}>
|
||||||
type="icon"
|
<TldrawUiButtonIcon icon="menu" small />
|
||||||
className="tlui-menu__trigger"
|
</TldrawUiButton>
|
||||||
data-testid="main.menu"
|
|
||||||
title={msg('menu.title')}
|
|
||||||
icon="menu"
|
|
||||||
smallIcon
|
|
||||||
/>
|
|
||||||
</_Dropdown.Trigger>
|
</_Dropdown.Trigger>
|
||||||
<_Dropdown.Portal container={container}>
|
<_Dropdown.Portal container={container}>
|
||||||
<_Dropdown.Content
|
<_Dropdown.Content
|
||||||
|
|
|
@ -29,9 +29,9 @@ import {
|
||||||
ZoomToFitMenuItem,
|
ZoomToFitMenuItem,
|
||||||
ZoomToSelectionMenuItem,
|
ZoomToSelectionMenuItem,
|
||||||
} from '../menu-items'
|
} from '../menu-items'
|
||||||
import { TldrawUiMenuGroup } from '../menus/TldrawUiMenuGroup'
|
import { TldrawUiMenuGroup } from '../primitives/menus/TldrawUiMenuGroup'
|
||||||
import { TldrawUiMenuItem } from '../menus/TldrawUiMenuItem'
|
import { TldrawUiMenuItem } from '../primitives/menus/TldrawUiMenuItem'
|
||||||
import { TldrawUiMenuSubmenu } from '../menus/TldrawUiMenuSubmenu'
|
import { TldrawUiMenuSubmenu } from '../primitives/menus/TldrawUiMenuSubmenu'
|
||||||
|
|
||||||
/** @public */
|
/** @public */
|
||||||
export function DefaultMainMenuContent() {
|
export function DefaultMainMenuContent() {
|
||||||
|
|
27
packages/tldraw/src/lib/ui/components/MenuPanel.tsx
Normal file
27
packages/tldraw/src/lib/ui/components/MenuPanel.tsx
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
import { memo } from 'react'
|
||||||
|
import { useBreakpoint } from '../context/breakpoints'
|
||||||
|
import { useTldrawUiComponents } from '../context/components'
|
||||||
|
|
||||||
|
/** @public */
|
||||||
|
export const DefaultMenuPanel = memo(function MenuPanel() {
|
||||||
|
const breakpoint = useBreakpoint()
|
||||||
|
|
||||||
|
const { MainMenu, QuickActions, ActionsMenu, PageMenu } = useTldrawUiComponents()
|
||||||
|
|
||||||
|
if (!MainMenu && !PageMenu && breakpoint < 6) return null
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="tlui-menu-zone">
|
||||||
|
<div className="tlui-buttons__horizontal">
|
||||||
|
{MainMenu && <MainMenu />}
|
||||||
|
{PageMenu && <PageMenu />}
|
||||||
|
{breakpoint < 6 ? null : (
|
||||||
|
<>
|
||||||
|
{QuickActions && <QuickActions />}
|
||||||
|
{ActionsMenu && <ActionsMenu />}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})
|
|
@ -9,8 +9,13 @@ import { useCallback } from 'react'
|
||||||
import { useTldrawUiComponents } from '../context/components'
|
import { useTldrawUiComponents } from '../context/components'
|
||||||
import { useRelevantStyles } from '../hooks/useRevelantStyles'
|
import { useRelevantStyles } from '../hooks/useRevelantStyles'
|
||||||
import { useTranslation } from '../hooks/useTranslation/useTranslation'
|
import { useTranslation } from '../hooks/useTranslation/useTranslation'
|
||||||
import { Icon } from './primitives/Icon'
|
import { TldrawUiButton } from './primitives/Button/TldrawUiButton'
|
||||||
import { Popover, PopoverContent, PopoverTrigger } from './primitives/Popover'
|
import { TldrawUiButtonIcon } from './primitives/Button/TldrawUiButtonIcon'
|
||||||
|
import {
|
||||||
|
TldrawUiPopover,
|
||||||
|
TldrawUiPopoverContent,
|
||||||
|
TldrawUiPopoverTrigger,
|
||||||
|
} from './primitives/TldrawUiPopover'
|
||||||
|
|
||||||
export function MobileStylePanel() {
|
export function MobileStylePanel() {
|
||||||
const editor = useEditor()
|
const editor = useEditor()
|
||||||
|
@ -42,22 +47,24 @@ export function MobileStylePanel() {
|
||||||
if (!StylePanel) return null
|
if (!StylePanel) return null
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Popover id="style menu" onOpenChange={handleStylesOpenChange}>
|
<TldrawUiPopover id="mobile style menu" onOpenChange={handleStylesOpenChange}>
|
||||||
<PopoverTrigger
|
<TldrawUiPopoverTrigger>
|
||||||
disabled={disableStylePanel}
|
<TldrawUiButton
|
||||||
type="tool"
|
type="tool"
|
||||||
data-testid="mobile.styles"
|
|
||||||
style={{
|
|
||||||
color: disableStylePanel ? 'var(--color-muted-1)' : currentColor,
|
|
||||||
}}
|
|
||||||
title={msg('style-panel.title')}
|
title={msg('style-panel.title')}
|
||||||
|
data-testid="mobile.styles"
|
||||||
|
disabled={disableStylePanel}
|
||||||
|
style={{ color: disableStylePanel ? 'var(--color-muted-1)' : currentColor }}
|
||||||
>
|
>
|
||||||
<Icon icon={disableStylePanel ? 'blob' : color?.type === 'mixed' ? 'mixed' : 'blob'} />
|
<TldrawUiButtonIcon
|
||||||
</PopoverTrigger>
|
icon={disableStylePanel ? 'blob' : color?.type === 'mixed' ? 'mixed' : 'blob'}
|
||||||
<PopoverContent side="top" align="end">
|
/>
|
||||||
|
</TldrawUiButton>
|
||||||
|
</TldrawUiPopoverTrigger>
|
||||||
|
<TldrawUiPopoverContent side="top" align="end">
|
||||||
<_StylePanel />
|
<_StylePanel />
|
||||||
</PopoverContent>
|
</TldrawUiPopoverContent>
|
||||||
</Popover>
|
</TldrawUiPopover>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,5 +73,5 @@ function _StylePanel() {
|
||||||
const relevantStyles = useRelevantStyles()
|
const relevantStyles = useRelevantStyles()
|
||||||
|
|
||||||
if (!StylePanel) return null
|
if (!StylePanel) return null
|
||||||
return <StylePanel relevantStyles={relevantStyles} />
|
return <StylePanel relevantStyles={relevantStyles} isMobile />
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,8 +5,9 @@ import { useBreakpoint } from '../../context/breakpoints'
|
||||||
import { useTldrawUiComponents } from '../../context/components'
|
import { useTldrawUiComponents } from '../../context/components'
|
||||||
import { useLocalStorageState } from '../../hooks/useLocalStorageState'
|
import { useLocalStorageState } from '../../hooks/useLocalStorageState'
|
||||||
import { useTranslation } from '../../hooks/useTranslation/useTranslation'
|
import { useTranslation } from '../../hooks/useTranslation/useTranslation'
|
||||||
import { Button } from '../primitives/Button'
|
import { kbdStr } from '../../kbd-utils'
|
||||||
import { kbdStr } from '../primitives/shared'
|
import { TldrawUiButton } from '../primitives/Button/TldrawUiButton'
|
||||||
|
import { TldrawUiButtonIcon } from '../primitives/Button/TldrawUiButtonIcon'
|
||||||
|
|
||||||
/** @public */
|
/** @public */
|
||||||
export const DefaultNavigationPanel = memo(function DefaultNavigationPanel() {
|
export const DefaultNavigationPanel = memo(function DefaultNavigationPanel() {
|
||||||
|
@ -35,42 +36,46 @@ export const DefaultNavigationPanel = memo(function DefaultNavigationPanel() {
|
||||||
<>
|
<>
|
||||||
{ZoomMenu && <ZoomMenu />}
|
{ZoomMenu && <ZoomMenu />}
|
||||||
{Minimap && (
|
{Minimap && (
|
||||||
<Button
|
<TldrawUiButton
|
||||||
type="icon"
|
type="icon"
|
||||||
icon={collapsed ? 'chevrons-ne' : 'chevrons-sw'}
|
|
||||||
data-testid="minimap.toggle"
|
data-testid="minimap.toggle"
|
||||||
title={msg('navigation-zone.toggle-minimap')}
|
title={msg('navigation-zone.toggle-minimap')}
|
||||||
className="tlui-navigation-panel__toggle"
|
className="tlui-navigation-panel__toggle"
|
||||||
onClick={toggleMinimap}
|
onClick={toggleMinimap}
|
||||||
/>
|
>
|
||||||
|
<TldrawUiButtonIcon icon={collapsed ? 'chevrons-ne' : 'chevrons-sw'} />
|
||||||
|
</TldrawUiButton>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<Button
|
<TldrawUiButton
|
||||||
type="icon"
|
type="icon"
|
||||||
icon="minus"
|
|
||||||
data-testid="minimap.zoom-out"
|
data-testid="minimap.zoom-out"
|
||||||
title={`${msg(unwrapLabel(actions['zoom-out'].label))} ${kbdStr(actions['zoom-out'].kbd!)}`}
|
title={`${msg(unwrapLabel(actions['zoom-out'].label))} ${kbdStr(actions['zoom-out'].kbd!)}`}
|
||||||
onClick={() => actions['zoom-out'].onSelect('navigation-zone')}
|
onClick={() => actions['zoom-out'].onSelect('navigation-zone')}
|
||||||
/>
|
>
|
||||||
|
<TldrawUiButtonIcon icon="minus" />
|
||||||
|
</TldrawUiButton>
|
||||||
{ZoomMenu && <ZoomMenu />}
|
{ZoomMenu && <ZoomMenu />}
|
||||||
<Button
|
<TldrawUiButton
|
||||||
type="icon"
|
type="icon"
|
||||||
icon="plus"
|
|
||||||
data-testid="minimap.zoom-in"
|
data-testid="minimap.zoom-in"
|
||||||
title={`${msg(unwrapLabel(actions['zoom-in'].label))} ${kbdStr(actions['zoom-in'].kbd!)}`}
|
title={`${msg(unwrapLabel(actions['zoom-in'].label))} ${kbdStr(actions['zoom-in'].kbd!)}`}
|
||||||
onClick={() => actions['zoom-in'].onSelect('navigation-zone')}
|
onClick={() => actions['zoom-in'].onSelect('navigation-zone')}
|
||||||
/>
|
>
|
||||||
|
<TldrawUiButtonIcon icon="plus" />
|
||||||
|
</TldrawUiButton>
|
||||||
{Minimap && (
|
{Minimap && (
|
||||||
<Button
|
<TldrawUiButton
|
||||||
type="icon"
|
type="icon"
|
||||||
icon={collapsed ? 'chevrons-ne' : 'chevrons-sw'}
|
|
||||||
data-testid="minimap.toggle"
|
data-testid="minimap.toggle"
|
||||||
title={msg('navigation-zone.toggle-minimap')}
|
title={msg('navigation-zone.toggle-minimap')}
|
||||||
className="tlui-navigation-panel__toggle"
|
className="tlui-navigation-panel__toggle"
|
||||||
onClick={toggleMinimap}
|
onClick={toggleMinimap}
|
||||||
/>
|
>
|
||||||
|
<TldrawUiButtonIcon icon={collapsed ? 'chevrons-ne' : 'chevrons-sw'} />
|
||||||
|
</TldrawUiButton>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
import { useRef } from 'react'
|
import { useRef } from 'react'
|
||||||
import { useTranslation } from '../../hooks/useTranslation/useTranslation'
|
import { useTranslation } from '../../hooks/useTranslation/useTranslation'
|
||||||
import { Icon } from '../primitives/Icon'
|
import { TldrawUiIcon } from '../primitives/TldrawUiIcon'
|
||||||
|
|
||||||
/** @public */
|
/** @public */
|
||||||
export function OfflineIndicator() {
|
export function OfflineIndicator() {
|
||||||
|
@ -11,7 +11,7 @@ export function OfflineIndicator() {
|
||||||
return (
|
return (
|
||||||
<div className={classNames('tlui-offline-indicator')} ref={rContainer}>
|
<div className={classNames('tlui-offline-indicator')} ref={rContainer}>
|
||||||
{msg('status.offline')}
|
{msg('status.offline')}
|
||||||
<Icon aria-label="offline" icon="status-offline" small />
|
<TldrawUiIcon aria-label="offline" icon="status-offline" small />
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,9 +13,15 @@ import { useBreakpoint } from '../../context/breakpoints'
|
||||||
import { useMenuIsOpen } from '../../hooks/useMenuIsOpen'
|
import { useMenuIsOpen } from '../../hooks/useMenuIsOpen'
|
||||||
import { useReadonly } from '../../hooks/useReadonly'
|
import { useReadonly } from '../../hooks/useReadonly'
|
||||||
import { useTranslation } from '../../hooks/useTranslation/useTranslation'
|
import { useTranslation } from '../../hooks/useTranslation/useTranslation'
|
||||||
import { Button } from '../primitives/Button'
|
import { TldrawUiButton } from '../primitives/Button/TldrawUiButton'
|
||||||
import { Icon } from '../primitives/Icon'
|
import { TldrawUiButtonCheck } from '../primitives/Button/TldrawUiButtonCheck'
|
||||||
import { Popover, PopoverContent, PopoverTrigger } from '../primitives/Popover'
|
import { TldrawUiButtonIcon } from '../primitives/Button/TldrawUiButtonIcon'
|
||||||
|
import { TldrawUiButtonLabel } from '../primitives/Button/TldrawUiButtonLabel'
|
||||||
|
import {
|
||||||
|
TldrawUiPopover,
|
||||||
|
TldrawUiPopoverContent,
|
||||||
|
TldrawUiPopoverTrigger,
|
||||||
|
} from '../primitives/TldrawUiPopover'
|
||||||
import { PageItemInput } from './PageItemInput'
|
import { PageItemInput } from './PageItemInput'
|
||||||
import { PageItemSubmenu } from './PageItemSubmenu'
|
import { PageItemSubmenu } from './PageItemSubmenu'
|
||||||
import { onMovePage } from './edit-pages-shared'
|
import { onMovePage } from './edit-pages-shared'
|
||||||
|
@ -255,33 +261,30 @@ export const DefaultPageMenu = memo(function DefaultPageMenu() {
|
||||||
}, [editor, msg, isReadonlyMode])
|
}, [editor, msg, isReadonlyMode])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Popover id="pages" onOpenChange={onOpenChange} open={isOpen}>
|
<TldrawUiPopover id="pages" onOpenChange={onOpenChange} open={isOpen}>
|
||||||
<PopoverTrigger
|
<TldrawUiPopoverTrigger data-testid="main.page-menu">
|
||||||
className="tlui-page-menu__trigger tlui-menu__trigger"
|
<TldrawUiButton type="menu" title={currentPage.name} className="tlui-page-menu__trigger">
|
||||||
data-testid="main.page-menu"
|
|
||||||
icon="chevron-down"
|
|
||||||
type="menu"
|
|
||||||
title={currentPage.name}
|
|
||||||
>
|
|
||||||
<div className="tlui-page-menu__name">{currentPage.name}</div>
|
<div className="tlui-page-menu__name">{currentPage.name}</div>
|
||||||
</PopoverTrigger>
|
<TldrawUiButtonIcon icon="chevron-down" small />
|
||||||
<PopoverContent side="bottom" align="start" sideOffset={6}>
|
</TldrawUiButton>
|
||||||
|
</TldrawUiPopoverTrigger>
|
||||||
|
<TldrawUiPopoverContent side="bottom" align="start" sideOffset={6}>
|
||||||
<div className="tlui-page-menu__wrapper">
|
<div className="tlui-page-menu__wrapper">
|
||||||
<div className="tlui-page-menu__header">
|
<div className="tlui-page-menu__header">
|
||||||
<div className="tlui-page-menu__header__title">{msg('page-menu.title')}</div>
|
<div className="tlui-page-menu__header__title">{msg('page-menu.title')}</div>
|
||||||
{!isReadonlyMode && (
|
{!isReadonlyMode && (
|
||||||
<div className="tlui-buttons__horizontal">
|
<div className="tlui-buttons__horizontal">
|
||||||
<Button
|
<TldrawUiButton
|
||||||
type="icon"
|
type="icon"
|
||||||
data-testid="page-menu.edit"
|
data-testid="page-menu.edit"
|
||||||
title={msg(isEditing ? 'page-menu.edit-done' : 'page-menu.edit-start')}
|
title={msg(isEditing ? 'page-menu.edit-done' : 'page-menu.edit-start')}
|
||||||
icon={isEditing ? 'check' : 'edit'}
|
|
||||||
onClick={toggleEditing}
|
onClick={toggleEditing}
|
||||||
/>
|
>
|
||||||
<Button
|
<TldrawUiButtonIcon icon={isEditing ? 'check' : 'edit'} />
|
||||||
|
</TldrawUiButton>
|
||||||
|
<TldrawUiButton
|
||||||
type="icon"
|
type="icon"
|
||||||
data-testid="page-menu.create"
|
data-testid="page-menu.create"
|
||||||
icon="plus"
|
|
||||||
title={msg(
|
title={msg(
|
||||||
maxPageCountReached
|
maxPageCountReached
|
||||||
? 'page-menu.max-page-count-reached'
|
? 'page-menu.max-page-count-reached'
|
||||||
|
@ -289,7 +292,9 @@ export const DefaultPageMenu = memo(function DefaultPageMenu() {
|
||||||
)}
|
)}
|
||||||
disabled={maxPageCountReached}
|
disabled={maxPageCountReached}
|
||||||
onClick={handleCreatePageClick}
|
onClick={handleCreatePageClick}
|
||||||
/>
|
>
|
||||||
|
<TldrawUiButtonIcon icon="plus" />
|
||||||
|
</TldrawUiButton>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
@ -314,24 +319,25 @@ export const DefaultPageMenu = memo(function DefaultPageMenu() {
|
||||||
transform: `translate(0px, ${position.y + position.offsetY}px)`,
|
transform: `translate(0px, ${position.y + position.offsetY}px)`,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Button
|
<TldrawUiButton
|
||||||
type="icon"
|
type="icon"
|
||||||
tabIndex={-1}
|
tabIndex={-1}
|
||||||
className="tlui-page_menu__item__sortable__handle"
|
className="tlui-page_menu__item__sortable__handle"
|
||||||
icon="drag-handle-dots"
|
|
||||||
onPointerDown={handlePointerDown}
|
onPointerDown={handlePointerDown}
|
||||||
onPointerUp={handlePointerUp}
|
onPointerUp={handlePointerUp}
|
||||||
onPointerMove={handlePointerMove}
|
onPointerMove={handlePointerMove}
|
||||||
onKeyDown={handleKeyDown}
|
onKeyDown={handleKeyDown}
|
||||||
data-id={page.id}
|
data-id={page.id}
|
||||||
data-index={index}
|
data-index={index}
|
||||||
/>
|
>
|
||||||
|
<TldrawUiButtonIcon icon="drag-handle-dots" />
|
||||||
|
</TldrawUiButton>
|
||||||
{breakpoint < PORTRAIT_BREAKPOINT.TABLET_SM && isCoarsePointer ? (
|
{breakpoint < PORTRAIT_BREAKPOINT.TABLET_SM && isCoarsePointer ? (
|
||||||
// sigh, this is a workaround for iOS Safari
|
// sigh, this is a workaround for iOS Safari
|
||||||
// because the device and the radix popover seem
|
// because the device and the radix popover seem
|
||||||
// to be fighting over scroll position. Nothing
|
// to be fighting over scroll position. Nothing
|
||||||
// else seems to work!
|
// else seems to work!
|
||||||
<Button
|
<TldrawUiButton
|
||||||
type="normal"
|
type="normal"
|
||||||
className="tlui-page-menu__item__button"
|
className="tlui-page-menu__item__button"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
@ -341,10 +347,10 @@ export const DefaultPageMenu = memo(function DefaultPageMenu() {
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
onDoubleClick={toggleEditing}
|
onDoubleClick={toggleEditing}
|
||||||
isChecked={page.id === currentPage.id}
|
|
||||||
>
|
>
|
||||||
<span>{page.name}</span>
|
<TldrawUiButtonCheck checked={page.id === currentPage.id} />
|
||||||
</Button>
|
<TldrawUiButtonLabel>{page.name}</TldrawUiButtonLabel>
|
||||||
|
</TldrawUiButton>
|
||||||
) : (
|
) : (
|
||||||
<div
|
<div
|
||||||
className="tlui-page_menu__item__sortable__title"
|
className="tlui-page_menu__item__sortable__title"
|
||||||
|
@ -369,19 +375,16 @@ export const DefaultPageMenu = memo(function DefaultPageMenu() {
|
||||||
data-testid={`page-menu-item-${page.id}`}
|
data-testid={`page-menu-item-${page.id}`}
|
||||||
className="tlui-page-menu__item"
|
className="tlui-page-menu__item"
|
||||||
>
|
>
|
||||||
<Button
|
<TldrawUiButton
|
||||||
type="normal"
|
type="normal"
|
||||||
className="tlui-page-menu__item__button tlui-page-menu__item__button__checkbox"
|
className="tlui-page-menu__item__button"
|
||||||
onClick={() => editor.setCurrentPage(page.id)}
|
onClick={() => editor.setCurrentPage(page.id)}
|
||||||
onDoubleClick={toggleEditing}
|
onDoubleClick={toggleEditing}
|
||||||
isChecked={page.id === currentPage.id}
|
|
||||||
title={msg('page-menu.go-to-page')}
|
title={msg('page-menu.go-to-page')}
|
||||||
>
|
>
|
||||||
<div className="tlui-page-menu__item__button__check">
|
<TldrawUiButtonCheck checked={page.id === currentPage.id} />
|
||||||
{page.id === currentPage.id && <Icon icon="check" />}
|
<TldrawUiButtonLabel>{page.name}</TldrawUiButtonLabel>
|
||||||
</div>
|
</TldrawUiButton>
|
||||||
<span>{page.name}</span>
|
|
||||||
</Button>
|
|
||||||
{!isReadonlyMode && (
|
{!isReadonlyMode && (
|
||||||
<div className="tlui-page_menu__item__submenu">
|
<div className="tlui-page_menu__item__submenu">
|
||||||
<PageItemSubmenu
|
<PageItemSubmenu
|
||||||
|
@ -409,7 +412,7 @@ export const DefaultPageMenu = memo(function DefaultPageMenu() {
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</PopoverContent>
|
</TldrawUiPopoverContent>
|
||||||
</Popover>
|
</TldrawUiPopover>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { TLPageId, useEditor } from '@tldraw/editor'
|
import { TLPageId, useEditor } from '@tldraw/editor'
|
||||||
import { useCallback, useRef } from 'react'
|
import { useCallback, useRef } from 'react'
|
||||||
import { Input } from '../primitives/Input'
|
import { TldrawUiInput } from '../primitives/TldrawUiInput'
|
||||||
|
|
||||||
export const PageItemInput = function PageItemInput({
|
export const PageItemInput = function PageItemInput({
|
||||||
name,
|
name,
|
||||||
|
@ -31,7 +31,7 @@ export const PageItemInput = function PageItemInput({
|
||||||
)
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Input
|
<TldrawUiInput
|
||||||
className="tlui-page-menu__item__input"
|
className="tlui-page-menu__item__input"
|
||||||
ref={(el) => (rInput.current = el)}
|
ref={(el) => (rInput.current = el)}
|
||||||
defaultValue={name}
|
defaultValue={name}
|
||||||
|
|
|
@ -1,14 +1,16 @@
|
||||||
import { MAX_PAGES, PageRecordType, TLPageId, track, useEditor } from '@tldraw/editor'
|
import { MAX_PAGES, PageRecordType, TLPageId, track, useEditor } from '@tldraw/editor'
|
||||||
import { useCallback } from 'react'
|
import { useCallback } from 'react'
|
||||||
import { useTranslation } from '../../hooks/useTranslation/useTranslation'
|
import { useTranslation } from '../../hooks/useTranslation/useTranslation'
|
||||||
import { TldrawUiMenuContextProvider } from '../menus/TldrawUiMenuContext'
|
import { TldrawUiButton } from '../primitives/Button/TldrawUiButton'
|
||||||
import { TldrawUiMenuGroup } from '../menus/TldrawUiMenuGroup'
|
import { TldrawUiButtonIcon } from '../primitives/Button/TldrawUiButtonIcon'
|
||||||
import { TldrawUiMenuItem } from '../menus/TldrawUiMenuItem'
|
|
||||||
import {
|
import {
|
||||||
DropdownMenuContent,
|
TldrawUiDropdownMenuContent,
|
||||||
DropdownMenuRoot,
|
TldrawUiDropdownMenuRoot,
|
||||||
DropdownMenuTrigger,
|
TldrawUiDropdownMenuTrigger,
|
||||||
} from '../primitives/DropdownMenu'
|
} from '../primitives/TldrawUiDropdownMenu'
|
||||||
|
import { TldrawUiMenuContextProvider } from '../primitives/menus/TldrawUiMenuContext'
|
||||||
|
import { TldrawUiMenuGroup } from '../primitives/menus/TldrawUiMenuGroup'
|
||||||
|
import { TldrawUiMenuItem } from '../primitives/menus/TldrawUiMenuItem'
|
||||||
import { onMovePage } from './edit-pages-shared'
|
import { onMovePage } from './edit-pages-shared'
|
||||||
|
|
||||||
export interface PageItemSubmenuProps {
|
export interface PageItemSubmenuProps {
|
||||||
|
@ -48,13 +50,13 @@ export const PageItemSubmenu = track(function PageItemSubmenu({
|
||||||
}, [editor, item])
|
}, [editor, item])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DropdownMenuRoot id={`page item submenu ${index}`}>
|
<TldrawUiDropdownMenuRoot id={`page item submenu ${index}`}>
|
||||||
<DropdownMenuTrigger
|
<TldrawUiDropdownMenuTrigger>
|
||||||
type="icon"
|
<TldrawUiButton type="icon" title={msg('page-menu.submenu.title')}>
|
||||||
title={msg('page-menu.submenu.title')}
|
<TldrawUiButtonIcon icon="dots-vertical" />
|
||||||
icon="dots-vertical"
|
</TldrawUiButton>
|
||||||
/>
|
</TldrawUiDropdownMenuTrigger>
|
||||||
<DropdownMenuContent alignOffset={0} side="right" sideOffset={-4}>
|
<TldrawUiDropdownMenuContent alignOffset={0} side="right" sideOffset={-4}>
|
||||||
<TldrawUiMenuContextProvider type="menu" sourceId="page-menu">
|
<TldrawUiMenuContextProvider type="menu" sourceId="page-menu">
|
||||||
<TldrawUiMenuGroup id="modify">
|
<TldrawUiMenuGroup id="modify">
|
||||||
{onRename && (
|
{onRename && (
|
||||||
|
@ -87,7 +89,7 @@ export const PageItemSubmenu = track(function PageItemSubmenu({
|
||||||
</TldrawUiMenuGroup>
|
</TldrawUiMenuGroup>
|
||||||
)}
|
)}
|
||||||
</TldrawUiMenuContextProvider>
|
</TldrawUiMenuContextProvider>
|
||||||
</DropdownMenuContent>
|
</TldrawUiDropdownMenuContent>
|
||||||
</DropdownMenuRoot>
|
</TldrawUiDropdownMenuRoot>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { memo } from 'react'
|
import { memo } from 'react'
|
||||||
import { TldrawUiMenuContextProvider } from '../menus/TldrawUiMenuContext'
|
import { TldrawUiMenuContextProvider } from '../primitives/menus/TldrawUiMenuContext'
|
||||||
import { DefaultQuickActionsContent } from './DefaultQuickActionsContent'
|
import { DefaultQuickActionsContent } from './DefaultQuickActionsContent'
|
||||||
|
|
||||||
/** @public */
|
/** @public */
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { useEditor, useValue } from '@tldraw/editor'
|
||||||
import { useActions } from '../../context/actions'
|
import { useActions } from '../../context/actions'
|
||||||
import { useCanRedo, useCanUndo, useUnlockedSelectedShapesCount } from '../../hooks/menu-hooks'
|
import { useCanRedo, useCanUndo, useUnlockedSelectedShapesCount } from '../../hooks/menu-hooks'
|
||||||
import { useReadonly } from '../../hooks/useReadonly'
|
import { useReadonly } from '../../hooks/useReadonly'
|
||||||
import { TldrawUiMenuItem } from '../menus/TldrawUiMenuItem'
|
import { TldrawUiMenuItem } from '../primitives/menus/TldrawUiMenuItem'
|
||||||
|
|
||||||
/** @public */
|
/** @public */
|
||||||
export function DefaultQuickActionsContent() {
|
export function DefaultQuickActionsContent() {
|
||||||
|
|
|
@ -33,7 +33,7 @@ export const DefaultStylePanel = memo(function DefaultStylePanel({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={classNames('tlui-style-panel', { 'tlui-style-panel__wrapper': !isMobile })}
|
className={classNames('', { 'tlui-style-panel__wrapper': !isMobile })}
|
||||||
data-ismobile={isMobile}
|
data-ismobile={isMobile}
|
||||||
onPointerLeave={handlePointerOut}
|
onPointerLeave={handlePointerOut}
|
||||||
>
|
>
|
||||||
|
|
|
@ -17,15 +17,16 @@ import {
|
||||||
useEditor,
|
useEditor,
|
||||||
} from '@tldraw/editor'
|
} from '@tldraw/editor'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
import { STYLES } from '../../../styles'
|
||||||
import { useUiEvents } from '../../context/events'
|
import { useUiEvents } from '../../context/events'
|
||||||
import { useRelevantStyles } from '../../hooks/useRevelantStyles'
|
import { useRelevantStyles } from '../../hooks/useRevelantStyles'
|
||||||
import { useTranslation } from '../../hooks/useTranslation/useTranslation'
|
import { useTranslation } from '../../hooks/useTranslation/useTranslation'
|
||||||
import { Button } from '../primitives/Button'
|
import { TldrawUiButton } from '../primitives/Button/TldrawUiButton'
|
||||||
import { ButtonPicker } from '../primitives/ButtonPicker'
|
import { TldrawUiButtonIcon } from '../primitives/Button/TldrawUiButtonIcon'
|
||||||
import { Slider } from '../primitives/Slider'
|
import { TldrawUiButtonPicker } from '../primitives/TldrawUiButtonPicker'
|
||||||
|
import { TldrawUiSlider } from '../primitives/TldrawUiSlider'
|
||||||
import { DoubleDropdownPicker } from './DoubleDropdownPicker'
|
import { DoubleDropdownPicker } from './DoubleDropdownPicker'
|
||||||
import { DropdownPicker } from './DropdownPicker'
|
import { DropdownPicker } from './DropdownPicker'
|
||||||
import { STYLES } from './styles'
|
|
||||||
|
|
||||||
/** @public */
|
/** @public */
|
||||||
export type TLUiStylePanelContentProps = {
|
export type TLUiStylePanelContentProps = {
|
||||||
|
@ -137,7 +138,7 @@ function CommonStylePickerSet({
|
||||||
aria-label="style panel styles"
|
aria-label="style panel styles"
|
||||||
>
|
>
|
||||||
{color === undefined ? null : (
|
{color === undefined ? null : (
|
||||||
<ButtonPicker
|
<TldrawUiButtonPicker
|
||||||
title={msg('style-panel.color')}
|
title={msg('style-panel.color')}
|
||||||
uiType="color"
|
uiType="color"
|
||||||
style={DefaultColorStyle}
|
style={DefaultColorStyle}
|
||||||
|
@ -147,7 +148,7 @@ function CommonStylePickerSet({
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{opacity === undefined ? null : (
|
{opacity === undefined ? null : (
|
||||||
<Slider
|
<TldrawUiSlider
|
||||||
data-testid="style.opacity"
|
data-testid="style.opacity"
|
||||||
value={opacityIndex >= 0 ? opacityIndex : tldrawSupportedOpacities.length - 1}
|
value={opacityIndex >= 0 ? opacityIndex : tldrawSupportedOpacities.length - 1}
|
||||||
label={
|
label={
|
||||||
|
@ -162,7 +163,7 @@ function CommonStylePickerSet({
|
||||||
{showPickers && (
|
{showPickers && (
|
||||||
<div className="tlui-style-panel__section" aria-label="style panel styles">
|
<div className="tlui-style-panel__section" aria-label="style panel styles">
|
||||||
{fill === undefined ? null : (
|
{fill === undefined ? null : (
|
||||||
<ButtonPicker
|
<TldrawUiButtonPicker
|
||||||
title={msg('style-panel.fill')}
|
title={msg('style-panel.fill')}
|
||||||
uiType="fill"
|
uiType="fill"
|
||||||
style={DefaultFillStyle}
|
style={DefaultFillStyle}
|
||||||
|
@ -172,7 +173,7 @@ function CommonStylePickerSet({
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{dash === undefined ? null : (
|
{dash === undefined ? null : (
|
||||||
<ButtonPicker
|
<TldrawUiButtonPicker
|
||||||
title={msg('style-panel.dash')}
|
title={msg('style-panel.dash')}
|
||||||
uiType="dash"
|
uiType="dash"
|
||||||
style={DefaultDashStyle}
|
style={DefaultDashStyle}
|
||||||
|
@ -182,7 +183,7 @@ function CommonStylePickerSet({
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{size === undefined ? null : (
|
{size === undefined ? null : (
|
||||||
<ButtonPicker
|
<TldrawUiButtonPicker
|
||||||
title={msg('style-panel.size')}
|
title={msg('style-panel.size')}
|
||||||
uiType="size"
|
uiType="size"
|
||||||
style={DefaultSizeStyle}
|
style={DefaultSizeStyle}
|
||||||
|
@ -211,7 +212,7 @@ function TextStylePickerSet({ styles }: { styles: ReadonlySharedStyleMap }) {
|
||||||
return (
|
return (
|
||||||
<div className="tlui-style-panel__section" aria-label="style panel text">
|
<div className="tlui-style-panel__section" aria-label="style panel text">
|
||||||
{font === undefined ? null : (
|
{font === undefined ? null : (
|
||||||
<ButtonPicker
|
<TldrawUiButtonPicker
|
||||||
title={msg('style-panel.font')}
|
title={msg('style-panel.font')}
|
||||||
uiType="font"
|
uiType="font"
|
||||||
style={DefaultFontStyle}
|
style={DefaultFontStyle}
|
||||||
|
@ -223,7 +224,7 @@ function TextStylePickerSet({ styles }: { styles: ReadonlySharedStyleMap }) {
|
||||||
|
|
||||||
{align === undefined ? null : (
|
{align === undefined ? null : (
|
||||||
<div className="tlui-style-panel__row">
|
<div className="tlui-style-panel__row">
|
||||||
<ButtonPicker
|
<TldrawUiButtonPicker
|
||||||
title={msg('style-panel.align')}
|
title={msg('style-panel.align')}
|
||||||
uiType="align"
|
uiType="align"
|
||||||
style={DefaultHorizontalAlignStyle}
|
style={DefaultHorizontalAlignStyle}
|
||||||
|
@ -233,13 +234,14 @@ function TextStylePickerSet({ styles }: { styles: ReadonlySharedStyleMap }) {
|
||||||
/>
|
/>
|
||||||
<div className="tlui-style-panel__row__extra-button">
|
<div className="tlui-style-panel__row__extra-button">
|
||||||
{verticalAlign === undefined ? (
|
{verticalAlign === undefined ? (
|
||||||
<Button
|
<TldrawUiButton
|
||||||
type="icon"
|
type="icon"
|
||||||
title={msg('style-panel.vertical-align')}
|
title={msg('style-panel.vertical-align')}
|
||||||
data-testid="vertical-align"
|
data-testid="vertical-align"
|
||||||
icon="vertical-align-center"
|
|
||||||
disabled
|
disabled
|
||||||
/>
|
>
|
||||||
|
<TldrawUiButtonIcon icon="vertical-align-center" />
|
||||||
|
</TldrawUiButton>
|
||||||
) : (
|
) : (
|
||||||
<DropdownPicker
|
<DropdownPicker
|
||||||
type="icon"
|
type="icon"
|
||||||
|
|
|
@ -1,15 +1,16 @@
|
||||||
import { SharedStyle, StyleProp } from '@tldraw/editor'
|
import { SharedStyle, StyleProp } from '@tldraw/editor'
|
||||||
import * as React from 'react'
|
import * as React from 'react'
|
||||||
|
import { StyleValuesForUi } from '../../../styles'
|
||||||
import { TLUiTranslationKey } from '../../hooks/useTranslation/TLUiTranslationKey'
|
import { TLUiTranslationKey } from '../../hooks/useTranslation/TLUiTranslationKey'
|
||||||
import { useTranslation } from '../../hooks/useTranslation/useTranslation'
|
import { useTranslation } from '../../hooks/useTranslation/useTranslation'
|
||||||
import { TLUiIconType } from '../../icon-types'
|
import { TldrawUiButton } from '../primitives/Button/TldrawUiButton'
|
||||||
|
import { TldrawUiButtonIcon } from '../primitives/Button/TldrawUiButtonIcon'
|
||||||
import {
|
import {
|
||||||
DropdownMenuContent,
|
TldrawUiDropdownMenuContent,
|
||||||
DropdownMenuItem,
|
TldrawUiDropdownMenuItem,
|
||||||
DropdownMenuRoot,
|
TldrawUiDropdownMenuRoot,
|
||||||
DropdownMenuTrigger,
|
TldrawUiDropdownMenuTrigger,
|
||||||
} from '../primitives/DropdownMenu'
|
} from '../primitives/TldrawUiDropdownMenu'
|
||||||
import { StyleValuesForUi } from './styles'
|
|
||||||
|
|
||||||
interface DoubleDropdownPickerProps<T extends string> {
|
interface DoubleDropdownPickerProps<T extends string> {
|
||||||
uiTypeA: string
|
uiTypeA: string
|
||||||
|
@ -63,8 +64,9 @@ export const DoubleDropdownPicker = React.memo(function DoubleDropdownPicker<T e
|
||||||
{msg(label)}
|
{msg(label)}
|
||||||
</div>
|
</div>
|
||||||
<div className="tlui-buttons__horizontal">
|
<div className="tlui-buttons__horizontal">
|
||||||
<DropdownMenuRoot id={`style panel ${uiTypeA} A`}>
|
<TldrawUiDropdownMenuRoot id={`style panel ${uiTypeA} A`}>
|
||||||
<DropdownMenuTrigger
|
<TldrawUiDropdownMenuTrigger>
|
||||||
|
<TldrawUiButton
|
||||||
type="icon"
|
type="icon"
|
||||||
data-testid={`style.${uiTypeA}`}
|
data-testid={`style.${uiTypeA}`}
|
||||||
title={
|
title={
|
||||||
|
@ -74,34 +76,32 @@ export const DoubleDropdownPicker = React.memo(function DoubleDropdownPicker<T e
|
||||||
? msg('style-panel.mixed')
|
? msg('style-panel.mixed')
|
||||||
: msg(`${uiTypeA}-style.${valueA.value}` as TLUiTranslationKey))
|
: msg(`${uiTypeA}-style.${valueA.value}` as TLUiTranslationKey))
|
||||||
}
|
}
|
||||||
icon={iconA as any}
|
>
|
||||||
invertIcon
|
<TldrawUiButtonIcon icon={iconA} small invertIcon />
|
||||||
smallIcon
|
</TldrawUiButton>
|
||||||
/>
|
</TldrawUiDropdownMenuTrigger>
|
||||||
<DropdownMenuContent side="bottom" align="end" sideOffset={0} alignOffset={-2}>
|
<TldrawUiDropdownMenuContent side="bottom" align="end" sideOffset={0} alignOffset={-2}>
|
||||||
<div className="tlui-buttons__grid">
|
<div className="tlui-buttons__grid">
|
||||||
{itemsA.map((item) => {
|
{itemsA.map((item) => {
|
||||||
return (
|
return (
|
||||||
<DropdownMenuItem
|
<TldrawUiDropdownMenuItem data-testid={`style.${uiTypeA}.${item.value}`}>
|
||||||
|
<TldrawUiButton
|
||||||
type="icon"
|
type="icon"
|
||||||
title={
|
|
||||||
msg(labelA) +
|
|
||||||
' — ' +
|
|
||||||
msg(`${uiTypeA}-style.${item.value}` as TLUiTranslationKey)
|
|
||||||
}
|
|
||||||
data-testid={`style.${uiTypeA}.${item.value}`}
|
|
||||||
key={item.value}
|
key={item.value}
|
||||||
icon={item.icon as TLUiIconType}
|
|
||||||
onClick={() => onValueChange(styleA, item.value, false)}
|
onClick={() => onValueChange(styleA, item.value, false)}
|
||||||
invertIcon
|
title={`${msg(labelA)} — ${msg(`${uiTypeA}-style.${item.value}`)}`}
|
||||||
/>
|
>
|
||||||
|
<TldrawUiButtonIcon icon={item.icon} invertIcon />
|
||||||
|
</TldrawUiButton>
|
||||||
|
</TldrawUiDropdownMenuItem>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
</DropdownMenuContent>
|
</TldrawUiDropdownMenuContent>
|
||||||
</DropdownMenuRoot>
|
</TldrawUiDropdownMenuRoot>
|
||||||
<DropdownMenuRoot id={`style panel ${uiTypeB}`}>
|
<TldrawUiDropdownMenuRoot id={`style panel ${uiTypeB}`}>
|
||||||
<DropdownMenuTrigger
|
<TldrawUiDropdownMenuTrigger>
|
||||||
|
<TldrawUiButton
|
||||||
type="icon"
|
type="icon"
|
||||||
data-testid={`style.${uiTypeB}`}
|
data-testid={`style.${uiTypeB}`}
|
||||||
title={
|
title={
|
||||||
|
@ -111,30 +111,29 @@ export const DoubleDropdownPicker = React.memo(function DoubleDropdownPicker<T e
|
||||||
? msg('style-panel.mixed')
|
? msg('style-panel.mixed')
|
||||||
: msg(`${uiTypeB}-style.${valueB.value}` as TLUiTranslationKey))
|
: msg(`${uiTypeB}-style.${valueB.value}` as TLUiTranslationKey))
|
||||||
}
|
}
|
||||||
icon={iconB as any}
|
>
|
||||||
smallIcon
|
<TldrawUiButtonIcon icon={iconB} small />
|
||||||
/>
|
</TldrawUiButton>
|
||||||
<DropdownMenuContent side="bottom" align="end" sideOffset={0} alignOffset={-2}>
|
</TldrawUiDropdownMenuTrigger>
|
||||||
|
<TldrawUiDropdownMenuContent side="bottom" align="end" sideOffset={0} alignOffset={-2}>
|
||||||
<div className="tlui-buttons__grid">
|
<div className="tlui-buttons__grid">
|
||||||
{itemsB.map((item) => {
|
{itemsB.map((item) => {
|
||||||
return (
|
return (
|
||||||
<DropdownMenuItem
|
<TldrawUiDropdownMenuItem key={item.value}>
|
||||||
|
<TldrawUiButton
|
||||||
type="icon"
|
type="icon"
|
||||||
title={
|
title={`${msg(labelB)} — ${msg(`${uiTypeB}-style.${item.value}` as TLUiTranslationKey)}`}
|
||||||
msg(labelB) +
|
|
||||||
' — ' +
|
|
||||||
msg(`${uiTypeB}-style.${item.value}` as TLUiTranslationKey)
|
|
||||||
}
|
|
||||||
data-testid={`style.${uiTypeB}.${item.value}`}
|
data-testid={`style.${uiTypeB}.${item.value}`}
|
||||||
key={item.value}
|
|
||||||
icon={item.icon as TLUiIconType}
|
|
||||||
onClick={() => onValueChange(styleB, item.value, false)}
|
onClick={() => onValueChange(styleB, item.value, false)}
|
||||||
/>
|
>
|
||||||
|
<TldrawUiButtonIcon icon={item.icon} />
|
||||||
|
</TldrawUiButton>
|
||||||
|
</TldrawUiDropdownMenuItem>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
</DropdownMenuContent>
|
</TldrawUiDropdownMenuContent>
|
||||||
</DropdownMenuRoot>
|
</TldrawUiDropdownMenuRoot>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,16 +1,18 @@
|
||||||
import { SharedStyle, StyleProp } from '@tldraw/editor'
|
import { SharedStyle, StyleProp } from '@tldraw/editor'
|
||||||
import * as React from 'react'
|
import * as React from 'react'
|
||||||
|
import { StyleValuesForUi } from '../../../styles'
|
||||||
import { TLUiTranslationKey } from '../../hooks/useTranslation/TLUiTranslationKey'
|
import { TLUiTranslationKey } from '../../hooks/useTranslation/TLUiTranslationKey'
|
||||||
import { useTranslation } from '../../hooks/useTranslation/useTranslation'
|
import { useTranslation } from '../../hooks/useTranslation/useTranslation'
|
||||||
import { TLUiIconType } from '../../icon-types'
|
import { TLUiIconType } from '../../icon-types'
|
||||||
import { TLUiButtonProps } from '../primitives/Button'
|
import { TLUiButtonProps, TldrawUiButton } from '../primitives/Button/TldrawUiButton'
|
||||||
|
import { TldrawUiButtonIcon } from '../primitives/Button/TldrawUiButtonIcon'
|
||||||
|
import { TldrawUiButtonLabel } from '../primitives/Button/TldrawUiButtonLabel'
|
||||||
import {
|
import {
|
||||||
DropdownMenuContent,
|
TldrawUiDropdownMenuContent,
|
||||||
DropdownMenuItem,
|
TldrawUiDropdownMenuItem,
|
||||||
DropdownMenuRoot,
|
TldrawUiDropdownMenuRoot,
|
||||||
DropdownMenuTrigger,
|
TldrawUiDropdownMenuTrigger,
|
||||||
} from '../primitives/DropdownMenu'
|
} from '../primitives/TldrawUiDropdownMenu'
|
||||||
import { StyleValuesForUi } from './styles'
|
|
||||||
|
|
||||||
interface DropdownPickerProps<T extends string> {
|
interface DropdownPickerProps<T extends string> {
|
||||||
id: string
|
id: string
|
||||||
|
@ -40,35 +42,38 @@ export const DropdownPicker = React.memo(function DropdownPicker<T extends strin
|
||||||
[items, value]
|
[items, value]
|
||||||
)
|
)
|
||||||
|
|
||||||
return (
|
const titleStr =
|
||||||
<DropdownMenuRoot id={`style panel ${id}`}>
|
|
||||||
<DropdownMenuTrigger
|
|
||||||
type={type}
|
|
||||||
data-testid={`style.${uiType}`}
|
|
||||||
title={
|
|
||||||
value.type === 'mixed'
|
value.type === 'mixed'
|
||||||
? msg('style-panel.mixed')
|
? msg('style-panel.mixed')
|
||||||
: msg(`${uiType}-style.${value.value}` as TLUiTranslationKey)
|
: msg(`${uiType}-style.${value.value}` as TLUiTranslationKey)
|
||||||
}
|
const labelStr = label ? msg(label) : ''
|
||||||
label={label}
|
|
||||||
icon={(icon as TLUiIconType) ?? 'mixed'}
|
return (
|
||||||
/>
|
<TldrawUiDropdownMenuRoot id={`style panel ${id}`}>
|
||||||
<DropdownMenuContent side="left" align="center" alignOffset={0}>
|
<TldrawUiDropdownMenuTrigger>
|
||||||
|
<TldrawUiButton type={type} data-testid={`style.${uiType}`} title={titleStr}>
|
||||||
|
<TldrawUiButtonLabel>{labelStr}</TldrawUiButtonLabel>
|
||||||
|
<TldrawUiButtonIcon icon={(icon as TLUiIconType) ?? 'mixed'} />
|
||||||
|
</TldrawUiButton>
|
||||||
|
</TldrawUiDropdownMenuTrigger>
|
||||||
|
<TldrawUiDropdownMenuContent side="left" align="center" alignOffset={0}>
|
||||||
<div className="tlui-buttons__grid">
|
<div className="tlui-buttons__grid">
|
||||||
{items.map((item) => {
|
{items.map((item) => {
|
||||||
return (
|
return (
|
||||||
<DropdownMenuItem
|
<TldrawUiDropdownMenuItem key={item.value}>
|
||||||
|
<TldrawUiButton
|
||||||
type="icon"
|
type="icon"
|
||||||
data-testid={`style.${uiType}.${item.value}`}
|
data-testid={`style.${uiType}.${item.value}`}
|
||||||
title={msg(`${uiType}-style.${item.value}` as TLUiTranslationKey)}
|
title={msg(`${uiType}-style.${item.value}` as TLUiTranslationKey)}
|
||||||
key={item.value}
|
|
||||||
icon={item.icon as TLUiIconType}
|
|
||||||
onClick={() => onValueChange(style, item.value, false)}
|
onClick={() => onValueChange(style, item.value, false)}
|
||||||
/>
|
>
|
||||||
|
<TldrawUiButtonIcon icon={item.icon} />
|
||||||
|
</TldrawUiButton>
|
||||||
|
</TldrawUiDropdownMenuItem>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
</DropdownMenuContent>
|
</TldrawUiDropdownMenuContent>
|
||||||
</DropdownMenuRoot>
|
</TldrawUiDropdownMenuRoot>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
|
@ -3,8 +3,9 @@ import * as React from 'react'
|
||||||
import { TLUiToast, useToasts } from '../context/toasts'
|
import { TLUiToast, useToasts } from '../context/toasts'
|
||||||
import { useTranslation } from '../hooks/useTranslation/useTranslation'
|
import { useTranslation } from '../hooks/useTranslation/useTranslation'
|
||||||
import { TLUiIconType } from '../icon-types'
|
import { TLUiIconType } from '../icon-types'
|
||||||
import { Button } from './primitives/Button'
|
import { TldrawUiButton } from './primitives/Button/TldrawUiButton'
|
||||||
import { Icon } from './primitives/Icon'
|
import { TldrawUiButtonLabel } from './primitives/Button/TldrawUiButtonLabel'
|
||||||
|
import { TldrawUiIcon } from './primitives/TldrawUiIcon'
|
||||||
|
|
||||||
function Toast({ toast }: { toast: TLUiToast }) {
|
function Toast({ toast }: { toast: TLUiToast }) {
|
||||||
const { removeToast } = useToasts()
|
const { removeToast } = useToasts()
|
||||||
|
@ -26,7 +27,7 @@ function Toast({ toast }: { toast: TLUiToast }) {
|
||||||
>
|
>
|
||||||
{toast.icon && (
|
{toast.icon && (
|
||||||
<div className="tlui-toast__icon">
|
<div className="tlui-toast__icon">
|
||||||
<Icon icon={toast.icon as TLUiIconType} />
|
<TldrawUiIcon icon={toast.icon as TLUiIconType} />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className="tlui-toast__main">
|
<div className="tlui-toast__main">
|
||||||
|
@ -40,22 +41,28 @@ function Toast({ toast }: { toast: TLUiToast }) {
|
||||||
<div className="tlui-toast__actions">
|
<div className="tlui-toast__actions">
|
||||||
{toast.actions.map((action, i) => (
|
{toast.actions.map((action, i) => (
|
||||||
<T.Action key={i} altText={action.label} asChild onClick={action.onClick}>
|
<T.Action key={i} altText={action.label} asChild onClick={action.onClick}>
|
||||||
<Button type={action.type}>{action.label}</Button>
|
<TldrawUiButton type={action.type}>
|
||||||
|
<TldrawUiButtonLabel>{action.label}</TldrawUiButtonLabel>
|
||||||
|
</TldrawUiButton>
|
||||||
</T.Action>
|
</T.Action>
|
||||||
))}
|
))}
|
||||||
<T.Close asChild>
|
<T.Close asChild>
|
||||||
<Button type="normal" className="tlui-toast__close" style={{ marginLeft: 'auto' }}>
|
<TldrawUiButton
|
||||||
{toast.closeLabel ?? msg('toast.close')}
|
type="normal"
|
||||||
</Button>
|
className="tlui-toast__close"
|
||||||
|
style={{ marginLeft: 'auto' }}
|
||||||
|
>
|
||||||
|
<TldrawUiButtonLabel>{toast.closeLabel ?? msg('toast.close')}</TldrawUiButtonLabel>
|
||||||
|
</TldrawUiButton>
|
||||||
</T.Close>
|
</T.Close>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{!hasActions && (
|
{!hasActions && (
|
||||||
<T.Close asChild>
|
<T.Close asChild>
|
||||||
<Button type="normal" className="tlui-toast__close">
|
<TldrawUiButton type="normal" className="tlui-toast__close">
|
||||||
{toast.closeLabel ?? msg('toast.close')}
|
<TldrawUiButtonLabel>{toast.closeLabel ?? msg('toast.close')}</TldrawUiButtonLabel>
|
||||||
</Button>
|
</TldrawUiButton>
|
||||||
</T.Close>
|
</T.Close>
|
||||||
)}
|
)}
|
||||||
</T.Root>
|
</T.Root>
|
||||||
|
|
|
@ -10,15 +10,16 @@ import { useReadonly } from '../../hooks/useReadonly'
|
||||||
import { TLUiToolbarItem, useToolbarSchema } from '../../hooks/useToolbarSchema'
|
import { TLUiToolbarItem, useToolbarSchema } from '../../hooks/useToolbarSchema'
|
||||||
import { TLUiToolItem } from '../../hooks/useTools'
|
import { TLUiToolItem } from '../../hooks/useTools'
|
||||||
import { useTranslation } from '../../hooks/useTranslation/useTranslation'
|
import { useTranslation } from '../../hooks/useTranslation/useTranslation'
|
||||||
|
import { kbdStr } from '../../kbd-utils'
|
||||||
import { MobileStylePanel } from '../MobileStylePanel'
|
import { MobileStylePanel } from '../MobileStylePanel'
|
||||||
import { Button } from '../primitives/Button'
|
import { TldrawUiButton } from '../primitives/Button/TldrawUiButton'
|
||||||
|
import { TldrawUiButtonIcon } from '../primitives/Button/TldrawUiButtonIcon'
|
||||||
import {
|
import {
|
||||||
DropdownMenuContent,
|
TldrawUiDropdownMenuContent,
|
||||||
DropdownMenuItem,
|
TldrawUiDropdownMenuItem,
|
||||||
DropdownMenuRoot,
|
TldrawUiDropdownMenuRoot,
|
||||||
DropdownMenuTrigger,
|
TldrawUiDropdownMenuTrigger,
|
||||||
} from '../primitives/DropdownMenu'
|
} from '../primitives/TldrawUiDropdownMenu'
|
||||||
import { kbdStr } from '../primitives/shared'
|
|
||||||
import { ToggleToolLockedButton } from './ToggleToolLockedButton'
|
import { ToggleToolLockedButton } from './ToggleToolLockedButton'
|
||||||
|
|
||||||
/** @public */
|
/** @public */
|
||||||
|
@ -143,18 +144,21 @@ export const DefaultToolbar = memo(function DefaultToolbar() {
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
{/* The dropdown to select everything else */}
|
{/* The dropdown to select everything else */}
|
||||||
<DropdownMenuRoot id="toolbar overflow" modal={false}>
|
<TldrawUiDropdownMenuRoot id="toolbar overflow" modal={false}>
|
||||||
<DropdownMenuTrigger
|
<TldrawUiDropdownMenuTrigger>
|
||||||
className="tlui-toolbar__overflow"
|
<TldrawUiButton
|
||||||
icon="chevron-up"
|
|
||||||
type="tool"
|
|
||||||
data-testid="tools.more"
|
|
||||||
title={msg('tool-panel.more')}
|
title={msg('tool-panel.more')}
|
||||||
/>
|
type="tool"
|
||||||
<DropdownMenuContent side="top" align="center">
|
className="tlui-toolbar__overflow"
|
||||||
|
data-testid="tools.more"
|
||||||
|
>
|
||||||
|
<TldrawUiButtonIcon icon="chevron-up" />
|
||||||
|
</TldrawUiButton>
|
||||||
|
</TldrawUiDropdownMenuTrigger>
|
||||||
|
<TldrawUiDropdownMenuContent side="top" align="center">
|
||||||
<OverflowToolsContent toolbarItems={itemsInDropdown} />
|
<OverflowToolsContent toolbarItems={itemsInDropdown} />
|
||||||
</DropdownMenuContent>
|
</TldrawUiDropdownMenuContent>
|
||||||
</DropdownMenuRoot>
|
</TldrawUiDropdownMenuRoot>
|
||||||
</>
|
</>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
|
@ -180,18 +184,22 @@ const OverflowToolsContent = track(function OverflowToolsContent({
|
||||||
<div className="tlui-buttons__grid">
|
<div className="tlui-buttons__grid">
|
||||||
{toolbarItems.map(({ toolItem: { id, meta, kbd, label, onSelect, icon } }) => {
|
{toolbarItems.map(({ toolItem: { id, meta, kbd, label, onSelect, icon } }) => {
|
||||||
return (
|
return (
|
||||||
<DropdownMenuItem
|
<TldrawUiDropdownMenuItem
|
||||||
key={id}
|
key={id}
|
||||||
type="icon"
|
|
||||||
className="tlui-button-grid__button"
|
|
||||||
data-testid={`tools.more.${id}`}
|
|
||||||
data-tool={id}
|
data-tool={id}
|
||||||
data-geo={meta?.geo ?? ''}
|
data-geo={meta?.geo ?? ''}
|
||||||
aria-label={label}
|
aria-label={label}
|
||||||
|
>
|
||||||
|
<TldrawUiButton
|
||||||
|
type="icon"
|
||||||
|
className="tlui-button-grid__button"
|
||||||
onClick={() => onSelect('toolbar')}
|
onClick={() => onSelect('toolbar')}
|
||||||
|
data-testid={`tools.more.${id}`}
|
||||||
title={label ? `${msg(label)} ${kbd ? kbdStr(kbd) : ''}` : ''}
|
title={label ? `${msg(label)} ${kbd ? kbdStr(kbd) : ''}` : ''}
|
||||||
icon={icon}
|
>
|
||||||
/>
|
<TldrawUiButtonIcon icon={icon} />
|
||||||
|
</TldrawUiButton>
|
||||||
|
</TldrawUiDropdownMenuItem>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
|
@ -208,21 +216,22 @@ function ToolbarButton({
|
||||||
isSelected: boolean
|
isSelected: boolean
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<Button
|
<TldrawUiButton
|
||||||
type="tool"
|
type="tool"
|
||||||
data-testid={`tools.${item.id}`}
|
data-testid={`tools.${item.id}`}
|
||||||
data-tool={item.id}
|
data-tool={item.id}
|
||||||
data-geo={item.meta?.geo ?? ''}
|
data-geo={item.meta?.geo ?? ''}
|
||||||
aria-label={item.label}
|
aria-label={item.label}
|
||||||
title={title}
|
|
||||||
icon={item.icon}
|
|
||||||
data-state={isSelected ? 'selected' : undefined}
|
data-state={isSelected ? 'selected' : undefined}
|
||||||
onClick={() => item.onSelect('toolbar')}
|
onClick={() => item.onSelect('toolbar')}
|
||||||
|
title={title}
|
||||||
onTouchStart={(e) => {
|
onTouchStart={(e) => {
|
||||||
preventDefault(e)
|
preventDefault(e)
|
||||||
item.onSelect('toolbar')
|
item.onSelect('toolbar')
|
||||||
}}
|
}}
|
||||||
/>
|
>
|
||||||
|
<TldrawUiButtonIcon icon={item.icon} />
|
||||||
|
</TldrawUiButton>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,8 @@ import classNames from 'classnames'
|
||||||
import { PORTRAIT_BREAKPOINT } from '../../constants'
|
import { PORTRAIT_BREAKPOINT } from '../../constants'
|
||||||
import { useBreakpoint } from '../../context/breakpoints'
|
import { useBreakpoint } from '../../context/breakpoints'
|
||||||
import { useTranslation } from '../../hooks/useTranslation/useTranslation'
|
import { useTranslation } from '../../hooks/useTranslation/useTranslation'
|
||||||
import { Button } from '../primitives/Button'
|
import { TldrawUiButton } from '../primitives/Button/TldrawUiButton'
|
||||||
|
import { TldrawUiButtonIcon } from '../primitives/Button/TldrawUiButtonIcon'
|
||||||
|
|
||||||
interface ToggleToolLockedButtonProps {
|
interface ToggleToolLockedButtonProps {
|
||||||
activeToolId?: string
|
activeToolId?: string
|
||||||
|
@ -32,15 +33,15 @@ export function ToggleToolLockedButton({ activeToolId }: ToggleToolLockedButtonP
|
||||||
if (!activeToolId || NOT_LOCKABLE_TOOLS.includes(activeToolId)) return null
|
if (!activeToolId || NOT_LOCKABLE_TOOLS.includes(activeToolId)) return null
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Button
|
<TldrawUiButton
|
||||||
type="normal"
|
type="normal"
|
||||||
title={msg('action.toggle-tool-lock')}
|
title={msg('action.toggle-tool-lock')}
|
||||||
className={classNames('tlui-toolbar__lock-button', {
|
className={classNames('tlui-toolbar__lock-button', {
|
||||||
'tlui-toolbar__lock-button__mobile': breakpoint < PORTRAIT_BREAKPOINT.TABLET_SM,
|
'tlui-toolbar__lock-button__mobile': breakpoint < PORTRAIT_BREAKPOINT.TABLET_SM,
|
||||||
})}
|
})}
|
||||||
icon={isToolLocked ? 'lock' : 'unlock'}
|
|
||||||
onClick={() => editor.updateInstanceState({ isToolLocked: !isToolLocked })}
|
onClick={() => editor.updateInstanceState({ isToolLocked: !isToolLocked })}
|
||||||
smallIcon
|
>
|
||||||
/>
|
<TldrawUiButtonIcon icon={isToolLocked ? 'lock' : 'unlock'} small />
|
||||||
|
</TldrawUiButton>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,8 +5,8 @@ import { PORTRAIT_BREAKPOINT } from '../../constants'
|
||||||
import { useBreakpoint } from '../../context/breakpoints'
|
import { useBreakpoint } from '../../context/breakpoints'
|
||||||
import { useMenuIsOpen } from '../../hooks/useMenuIsOpen'
|
import { useMenuIsOpen } from '../../hooks/useMenuIsOpen'
|
||||||
import { useTranslation } from '../../hooks/useTranslation/useTranslation'
|
import { useTranslation } from '../../hooks/useTranslation/useTranslation'
|
||||||
import { TldrawUiMenuContextProvider } from '../menus/TldrawUiMenuContext'
|
import { TldrawUiButton } from '../primitives/Button/TldrawUiButton'
|
||||||
import { Button } from '../primitives/Button'
|
import { TldrawUiMenuContextProvider } from '../primitives/menus/TldrawUiMenuContext'
|
||||||
import { DefaultZoomMenuContent } from './DefaultZoomMenuContent'
|
import { DefaultZoomMenuContent } from './DefaultZoomMenuContent'
|
||||||
|
|
||||||
/** @public */
|
/** @public */
|
||||||
|
@ -59,7 +59,7 @@ const ZoomTriggerButton = forwardRef<HTMLButtonElement, any>(
|
||||||
}, [editor])
|
}, [editor])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Button
|
<TldrawUiButton
|
||||||
ref={ref}
|
ref={ref}
|
||||||
{...props}
|
{...props}
|
||||||
type="icon"
|
type="icon"
|
||||||
|
@ -76,7 +76,7 @@ const ZoomTriggerButton = forwardRef<HTMLButtonElement, any>(
|
||||||
{breakpoint < PORTRAIT_BREAKPOINT.MOBILE ? null : (
|
{breakpoint < PORTRAIT_BREAKPOINT.MOBILE ? null : (
|
||||||
<span style={{ flexGrow: 0, textAlign: 'center' }}>{Math.floor(zoom * 100)}%</span>
|
<span style={{ flexGrow: 0, textAlign: 'center' }}>{Math.floor(zoom * 100)}%</span>
|
||||||
)}
|
)}
|
||||||
</Button>
|
</TldrawUiButton>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { useActions } from '../../context/actions'
|
import { useActions } from '../../context/actions'
|
||||||
import { ZoomTo100MenuItem, ZoomToFitMenuItem, ZoomToSelectionMenuItem } from '../menu-items'
|
import { ZoomTo100MenuItem, ZoomToFitMenuItem, ZoomToSelectionMenuItem } from '../menu-items'
|
||||||
import { TldrawUiMenuItem } from '../menus/TldrawUiMenuItem'
|
import { TldrawUiMenuItem } from '../primitives/menus/TldrawUiMenuItem'
|
||||||
|
|
||||||
/** @public */
|
/** @public */
|
||||||
export function DefaultZoomMenuContent() {
|
export function DefaultZoomMenuContent() {
|
||||||
|
|
|
@ -21,10 +21,10 @@ import {
|
||||||
useThreeStackableItems,
|
useThreeStackableItems,
|
||||||
useUnlockedSelectedShapesCount,
|
useUnlockedSelectedShapesCount,
|
||||||
} from '../hooks/menu-hooks'
|
} from '../hooks/menu-hooks'
|
||||||
import { TldrawUiMenuCheckboxItem } from './menus/TldrawUiMenuCheckboxItem'
|
import { TldrawUiMenuCheckboxItem } from './primitives/menus/TldrawUiMenuCheckboxItem'
|
||||||
import { TldrawUiMenuGroup } from './menus/TldrawUiMenuGroup'
|
import { TldrawUiMenuGroup } from './primitives/menus/TldrawUiMenuGroup'
|
||||||
import { TldrawUiMenuItem } from './menus/TldrawUiMenuItem'
|
import { TldrawUiMenuItem } from './primitives/menus/TldrawUiMenuItem'
|
||||||
import { TldrawUiMenuSubmenu } from './menus/TldrawUiMenuSubmenu'
|
import { TldrawUiMenuSubmenu } from './primitives/menus/TldrawUiMenuSubmenu'
|
||||||
|
|
||||||
/* -------------------- Selection ------------------- */
|
/* -------------------- Selection ------------------- */
|
||||||
|
|
||||||
|
|
|
@ -1,80 +0,0 @@
|
||||||
import { useEditor } from '@tldraw/editor'
|
|
||||||
import classnames from 'classnames'
|
|
||||||
import * as React from 'react'
|
|
||||||
import { TLUiTranslationKey } from '../../hooks/useTranslation/TLUiTranslationKey'
|
|
||||||
import { useTranslation } from '../../hooks/useTranslation/useTranslation'
|
|
||||||
import { TLUiIconType } from '../../icon-types'
|
|
||||||
import { Spinner } from '../Spinner'
|
|
||||||
import { Icon } from './Icon'
|
|
||||||
import { Kbd } from './Kbd'
|
|
||||||
|
|
||||||
/** @public */
|
|
||||||
export interface TLUiButtonProps extends React.HTMLAttributes<HTMLButtonElement> {
|
|
||||||
loading?: boolean // TODO: loading spinner
|
|
||||||
disabled?: boolean
|
|
||||||
label?: TLUiTranslationKey | Exclude<string, TLUiTranslationKey>
|
|
||||||
icon?: TLUiIconType | Exclude<string, TLUiIconType>
|
|
||||||
spinner?: boolean
|
|
||||||
iconLeft?: TLUiIconType | Exclude<string, TLUiIconType>
|
|
||||||
smallIcon?: boolean
|
|
||||||
kbd?: string
|
|
||||||
isChecked?: boolean
|
|
||||||
invertIcon?: boolean
|
|
||||||
type: 'normal' | 'primary' | 'danger' | 'low' | 'icon' | 'tool' | 'menu' | 'help'
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @public */
|
|
||||||
export const Button = React.forwardRef<HTMLButtonElement, TLUiButtonProps>(function Button(
|
|
||||||
{
|
|
||||||
label,
|
|
||||||
icon,
|
|
||||||
invertIcon,
|
|
||||||
iconLeft,
|
|
||||||
smallIcon,
|
|
||||||
kbd,
|
|
||||||
isChecked = false,
|
|
||||||
type,
|
|
||||||
children,
|
|
||||||
spinner,
|
|
||||||
disabled,
|
|
||||||
...props
|
|
||||||
},
|
|
||||||
ref
|
|
||||||
) {
|
|
||||||
const msg = useTranslation()
|
|
||||||
const labelStr = label ? msg(label) : ''
|
|
||||||
const editor = useEditor()
|
|
||||||
|
|
||||||
// If the button is getting disabled while it's focused, move focus to the editor
|
|
||||||
// so that the user can continue using keyboard shortcuts
|
|
||||||
const current = (ref as React.MutableRefObject<HTMLButtonElement | null>)?.current
|
|
||||||
if (disabled && current === document.activeElement) {
|
|
||||||
editor.getContainer().focus()
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<button
|
|
||||||
ref={ref}
|
|
||||||
draggable={false}
|
|
||||||
type="button"
|
|
||||||
disabled={disabled}
|
|
||||||
{...props}
|
|
||||||
title={props.title ?? labelStr}
|
|
||||||
className={classnames('tlui-button', `tlui-button__${type}`, props.className)}
|
|
||||||
>
|
|
||||||
{iconLeft && <Icon icon={iconLeft} className="tlui-button__icon-left" small />}
|
|
||||||
{children}
|
|
||||||
{label && (
|
|
||||||
<span className="tlui-button__label" draggable={false}>
|
|
||||||
{labelStr}
|
|
||||||
{isChecked && <Icon icon="check" />}
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
{kbd && <Kbd>{kbd}</Kbd>}
|
|
||||||
{icon && !spinner && (
|
|
||||||
<Icon icon={icon} small={!!label || smallIcon} invertIcon={invertIcon} />
|
|
||||||
)}
|
|
||||||
{spinner && <Spinner />}
|
|
||||||
</button>
|
|
||||||
)
|
|
||||||
})
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
import { useEditor } from '@tldraw/editor'
|
||||||
|
import classnames from 'classnames'
|
||||||
|
import * as React from 'react'
|
||||||
|
|
||||||
|
/** @public */
|
||||||
|
export interface TLUiButtonProps extends React.HTMLAttributes<HTMLButtonElement> {
|
||||||
|
disabled?: boolean
|
||||||
|
type: 'normal' | 'primary' | 'danger' | 'low' | 'icon' | 'tool' | 'menu' | 'help'
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @public */
|
||||||
|
export const TldrawUiButton = React.forwardRef<HTMLButtonElement, TLUiButtonProps>(
|
||||||
|
function TldrawUiButton({ children, disabled, type, ...props }, ref) {
|
||||||
|
const editor = useEditor()
|
||||||
|
|
||||||
|
// If the button is getting disabled while it's focused, move focus to the editor
|
||||||
|
// so that the user can continue using keyboard shortcuts
|
||||||
|
const current = (ref as React.MutableRefObject<HTMLButtonElement | null>)?.current
|
||||||
|
if (disabled && current === document.activeElement) {
|
||||||
|
editor.getContainer().focus()
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
ref={ref}
|
||||||
|
type="button"
|
||||||
|
draggable={false}
|
||||||
|
disabled={disabled}
|
||||||
|
{...props}
|
||||||
|
className={classnames('tlui-button', `tlui-button__${type}`, props.className)}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</button>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
|
@ -0,0 +1,11 @@
|
||||||
|
import { TldrawUiIcon } from '../TldrawUiIcon'
|
||||||
|
|
||||||
|
/** @public */
|
||||||
|
export type TLUiButtonCheckProps = { checked: boolean }
|
||||||
|
|
||||||
|
/** @public */
|
||||||
|
export function TldrawUiButtonCheck({ checked }: TLUiButtonCheckProps) {
|
||||||
|
return (
|
||||||
|
<TldrawUiIcon icon={checked ? 'check' : 'checkbox-empty'} className="tlui-button__icon" small />
|
||||||
|
)
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
import { TldrawUiIcon } from '../TldrawUiIcon'
|
||||||
|
|
||||||
|
/** @public */
|
||||||
|
export type TLUiButtonIconProps = {
|
||||||
|
icon: string
|
||||||
|
small?: boolean
|
||||||
|
invertIcon?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @public */
|
||||||
|
export function TldrawUiButtonIcon({ icon, small, invertIcon }: TLUiButtonIconProps) {
|
||||||
|
return (
|
||||||
|
<TldrawUiIcon className="tlui-button__icon" icon={icon} small={small} invertIcon={invertIcon} />
|
||||||
|
)
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
/** @public */
|
||||||
|
export type TLUiButtonLabelProps = { children?: any }
|
||||||
|
|
||||||
|
/** @public */
|
||||||
|
export function TldrawUiButtonLabel({ children }: TLUiButtonLabelProps) {
|
||||||
|
return <span className="tlui-button__label">{children}</span>
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
import { Spinner } from '../../Spinner'
|
||||||
|
|
||||||
|
/** @public */
|
||||||
|
export function TldrawUiButtonSpinner() {
|
||||||
|
return <Spinner />
|
||||||
|
}
|
|
@ -1,165 +0,0 @@
|
||||||
import { stopEventPropagation, useEditor } from '@tldraw/editor'
|
|
||||||
import classNames from 'classnames'
|
|
||||||
import * as React from 'react'
|
|
||||||
import { TLUiTranslationKey } from '../../hooks/useTranslation/TLUiTranslationKey'
|
|
||||||
import { useTranslation } from '../../hooks/useTranslation/useTranslation'
|
|
||||||
import { TLUiIconType } from '../../icon-types'
|
|
||||||
import { Icon } from './Icon'
|
|
||||||
|
|
||||||
/** @public */
|
|
||||||
export interface TLUiInputProps {
|
|
||||||
disabled?: boolean
|
|
||||||
label?: TLUiTranslationKey | Exclude<string, TLUiTranslationKey>
|
|
||||||
icon?: TLUiIconType | Exclude<string, TLUiIconType>
|
|
||||||
iconLeft?: TLUiIconType | Exclude<string, TLUiIconType>
|
|
||||||
autofocus?: boolean
|
|
||||||
autoselect?: boolean
|
|
||||||
children?: any
|
|
||||||
defaultValue?: string
|
|
||||||
placeholder?: string
|
|
||||||
onComplete?: (value: string) => void
|
|
||||||
onValueChange?: (value: string) => void
|
|
||||||
onCancel?: (value: string) => void
|
|
||||||
onBlur?: (value: string) => void
|
|
||||||
className?: string
|
|
||||||
/**
|
|
||||||
* Usually on iOS when you focus an input, the browser will adjust the viewport to bring the input
|
|
||||||
* into view. Sometimes this doesn't work properly though - for example, if the input is newly
|
|
||||||
* created, iOS seems to have a hard time adjusting the viewport for it. This prop allows you to
|
|
||||||
* opt-in to some extra code to manually bring the input into view when the visual viewport of the
|
|
||||||
* browser changes, but we don't want to use it everywhere because generally the native behavior
|
|
||||||
* looks nicer in scenarios where it's sufficient.
|
|
||||||
*/
|
|
||||||
shouldManuallyMaintainScrollPositionWhenFocused?: boolean
|
|
||||||
value?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @public */
|
|
||||||
export const Input = React.forwardRef<HTMLInputElement, TLUiInputProps>(function Input(
|
|
||||||
{
|
|
||||||
className,
|
|
||||||
label,
|
|
||||||
icon,
|
|
||||||
iconLeft,
|
|
||||||
autoselect = false,
|
|
||||||
autofocus = false,
|
|
||||||
defaultValue,
|
|
||||||
placeholder,
|
|
||||||
onComplete,
|
|
||||||
onValueChange,
|
|
||||||
onCancel,
|
|
||||||
onBlur,
|
|
||||||
shouldManuallyMaintainScrollPositionWhenFocused = false,
|
|
||||||
children,
|
|
||||||
value,
|
|
||||||
},
|
|
||||||
ref
|
|
||||||
) {
|
|
||||||
const editor = useEditor()
|
|
||||||
const rInputRef = React.useRef<HTMLInputElement>(null)
|
|
||||||
|
|
||||||
// combine rInputRef and ref
|
|
||||||
React.useImperativeHandle(ref, () => rInputRef.current as HTMLInputElement)
|
|
||||||
|
|
||||||
const msg = useTranslation()
|
|
||||||
const rInitialValue = React.useRef<string>(defaultValue ?? '')
|
|
||||||
const rCurrentValue = React.useRef<string>(defaultValue ?? '')
|
|
||||||
|
|
||||||
const [isFocused, setIsFocused] = React.useState(false)
|
|
||||||
const handleFocus = React.useCallback(
|
|
||||||
(e: React.FocusEvent<HTMLInputElement>) => {
|
|
||||||
setIsFocused(true)
|
|
||||||
const elm = e.currentTarget as HTMLInputElement
|
|
||||||
rCurrentValue.current = elm.value
|
|
||||||
requestAnimationFrame(() => {
|
|
||||||
if (autoselect) {
|
|
||||||
elm.select()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
[autoselect]
|
|
||||||
)
|
|
||||||
|
|
||||||
const handleChange = React.useCallback(
|
|
||||||
(e: React.ChangeEvent<HTMLInputElement>) => {
|
|
||||||
const value = e.currentTarget.value
|
|
||||||
rCurrentValue.current = value
|
|
||||||
onValueChange?.(value)
|
|
||||||
},
|
|
||||||
[onValueChange]
|
|
||||||
)
|
|
||||||
|
|
||||||
const handleKeyUp = React.useCallback(
|
|
||||||
(e: React.KeyboardEvent<HTMLInputElement>) => {
|
|
||||||
switch (e.key) {
|
|
||||||
case 'Enter': {
|
|
||||||
e.currentTarget.blur()
|
|
||||||
stopEventPropagation(e)
|
|
||||||
onComplete?.(e.currentTarget.value)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
case 'Escape': {
|
|
||||||
e.currentTarget.value = rInitialValue.current
|
|
||||||
e.currentTarget.blur()
|
|
||||||
stopEventPropagation(e)
|
|
||||||
onCancel?.(e.currentTarget.value)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[onComplete, onCancel]
|
|
||||||
)
|
|
||||||
|
|
||||||
const handleBlur = React.useCallback(
|
|
||||||
(e: React.FocusEvent<HTMLInputElement>) => {
|
|
||||||
setIsFocused(false)
|
|
||||||
const value = e.currentTarget.value
|
|
||||||
onBlur?.(value)
|
|
||||||
},
|
|
||||||
[onBlur]
|
|
||||||
)
|
|
||||||
|
|
||||||
React.useEffect(() => {
|
|
||||||
if (!editor.environment.isIos) return
|
|
||||||
|
|
||||||
const visualViewport = window.visualViewport
|
|
||||||
if (isFocused && shouldManuallyMaintainScrollPositionWhenFocused && visualViewport) {
|
|
||||||
const onViewportChange = () => {
|
|
||||||
rInputRef.current?.scrollIntoView({ block: 'center' })
|
|
||||||
}
|
|
||||||
visualViewport.addEventListener('resize', onViewportChange)
|
|
||||||
visualViewport.addEventListener('scroll', onViewportChange)
|
|
||||||
|
|
||||||
requestAnimationFrame(() => {
|
|
||||||
rInputRef.current?.scrollIntoView({ block: 'center' })
|
|
||||||
})
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
visualViewport.removeEventListener('resize', onViewportChange)
|
|
||||||
visualViewport.removeEventListener('scroll', onViewportChange)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, [editor, isFocused, shouldManuallyMaintainScrollPositionWhenFocused])
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div draggable={false} className="tlui-input__wrapper">
|
|
||||||
{children}
|
|
||||||
{label && <label>{msg(label)}</label>}
|
|
||||||
{iconLeft && <Icon icon={iconLeft} className="tlui-icon-left" small />}
|
|
||||||
<input
|
|
||||||
ref={rInputRef}
|
|
||||||
className={classNames('tlui-input', className)}
|
|
||||||
type="text"
|
|
||||||
defaultValue={defaultValue}
|
|
||||||
onKeyUp={handleKeyUp}
|
|
||||||
onChange={handleChange}
|
|
||||||
onFocus={handleFocus}
|
|
||||||
onBlur={handleBlur}
|
|
||||||
autoFocus={autofocus}
|
|
||||||
placeholder={placeholder}
|
|
||||||
value={value}
|
|
||||||
/>
|
|
||||||
{icon && <Icon icon={icon} small={!!label} />}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
})
|
|
|
@ -8,16 +8,15 @@ import {
|
||||||
useValue,
|
useValue,
|
||||||
} from '@tldraw/editor'
|
} from '@tldraw/editor'
|
||||||
import classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
import * as React from 'react'
|
import { memo, useMemo, useRef } from 'react'
|
||||||
import { useRef } from 'react'
|
import { StyleValuesForUi } from '../../../styles'
|
||||||
import { TLUiTranslationKey } from '../../hooks/useTranslation/TLUiTranslationKey'
|
import { TLUiTranslationKey } from '../../hooks/useTranslation/TLUiTranslationKey'
|
||||||
import { useTranslation } from '../../hooks/useTranslation/useTranslation'
|
import { useTranslation } from '../../hooks/useTranslation/useTranslation'
|
||||||
import { TLUiIconType } from '../../icon-types'
|
import { TldrawUiButton } from './Button/TldrawUiButton'
|
||||||
import { StyleValuesForUi } from '../StylePanel/styles'
|
import { TldrawUiButtonIcon } from './Button/TldrawUiButtonIcon'
|
||||||
import { Button } from './Button'
|
|
||||||
|
|
||||||
/** @internal */
|
/** @public */
|
||||||
export interface ButtonPickerProps<T extends string> {
|
export interface TLUiButtonPickerProps<T extends string> {
|
||||||
title: string
|
title: string
|
||||||
uiType: string
|
uiType: string
|
||||||
style: StyleProp<T>
|
style: StyleProp<T>
|
||||||
|
@ -26,7 +25,10 @@ export interface ButtonPickerProps<T extends string> {
|
||||||
onValueChange: (style: StyleProp<T>, value: T, squashing: boolean) => void
|
onValueChange: (style: StyleProp<T>, value: T, squashing: boolean) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
function _ButtonPicker<T extends string>(props: ButtonPickerProps<T>) {
|
/** @public */
|
||||||
|
export const TldrawUiButtonPicker = memo(function TldrawUiButtonPicker<T extends string>(
|
||||||
|
props: TLUiButtonPickerProps<T>
|
||||||
|
) {
|
||||||
const {
|
const {
|
||||||
uiType,
|
uiType,
|
||||||
items,
|
items,
|
||||||
|
@ -46,7 +48,7 @@ function _ButtonPicker<T extends string>(props: ButtonPickerProps<T>) {
|
||||||
handleButtonPointerDown,
|
handleButtonPointerDown,
|
||||||
handleButtonPointerEnter,
|
handleButtonPointerEnter,
|
||||||
handleButtonPointerUp,
|
handleButtonPointerUp,
|
||||||
} = React.useMemo(() => {
|
} = useMemo(() => {
|
||||||
const handlePointerUp = () => {
|
const handlePointerUp = () => {
|
||||||
rPointing.current = false
|
rPointing.current = false
|
||||||
window.removeEventListener('pointerup', handlePointerUp)
|
window.removeEventListener('pointerup', handlePointerUp)
|
||||||
|
@ -99,7 +101,7 @@ function _ButtonPicker<T extends string>(props: ButtonPickerProps<T>) {
|
||||||
return (
|
return (
|
||||||
<div className={classNames('tlui-buttons__grid')}>
|
<div className={classNames('tlui-buttons__grid')}>
|
||||||
{items.map((item) => (
|
{items.map((item) => (
|
||||||
<Button
|
<TldrawUiButton
|
||||||
type="icon"
|
type="icon"
|
||||||
key={item.value}
|
key={item.value}
|
||||||
data-id={item.value}
|
data-id={item.value}
|
||||||
|
@ -117,12 +119,10 @@ function _ButtonPicker<T extends string>(props: ButtonPickerProps<T>) {
|
||||||
onPointerDown={handleButtonPointerDown}
|
onPointerDown={handleButtonPointerDown}
|
||||||
onPointerUp={handleButtonPointerUp}
|
onPointerUp={handleButtonPointerUp}
|
||||||
onClick={handleButtonClick}
|
onClick={handleButtonClick}
|
||||||
icon={item.icon as TLUiIconType}
|
>
|
||||||
/>
|
<TldrawUiButtonIcon icon={item.icon} />
|
||||||
|
</TldrawUiButton>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
})
|
||||||
|
|
||||||
/** @internal */
|
|
||||||
export const ButtonPicker = React.memo(_ButtonPicker) as typeof _ButtonPicker
|
|
|
@ -1,7 +1,7 @@
|
||||||
import * as _Dialog from '@radix-ui/react-dialog'
|
import * as _Dialog from '@radix-ui/react-dialog'
|
||||||
import classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
import { Button } from './Button'
|
import { TldrawUiButton } from './Button/TldrawUiButton'
|
||||||
import { Icon } from './Icon'
|
import { TldrawUiButtonIcon } from './Button/TldrawUiButtonIcon'
|
||||||
|
|
||||||
/** @public */
|
/** @public */
|
||||||
export type TLUiDialogHeaderProps = {
|
export type TLUiDialogHeaderProps = {
|
||||||
|
@ -10,7 +10,7 @@ export type TLUiDialogHeaderProps = {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @public */
|
/** @public */
|
||||||
export function DialogHeader({ className, children }: TLUiDialogHeaderProps) {
|
export function TldrawUiDialogHeader({ className, children }: TLUiDialogHeaderProps) {
|
||||||
return <div className={classNames('tlui-dialog__header', className)}>{children}</div>
|
return <div className={classNames('tlui-dialog__header', className)}>{children}</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ export type TLUiDialogTitleProps = {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @public */
|
/** @public */
|
||||||
export function DialogTitle({ className, children }: TLUiDialogTitleProps) {
|
export function TldrawUiDialogTitle({ className, children }: TLUiDialogTitleProps) {
|
||||||
return (
|
return (
|
||||||
<_Dialog.DialogTitle dir="ltr" className={classNames('tlui-dialog__header__title', className)}>
|
<_Dialog.DialogTitle dir="ltr" className={classNames('tlui-dialog__header__title', className)}>
|
||||||
{children}
|
{children}
|
||||||
|
@ -30,17 +30,17 @@ export function DialogTitle({ className, children }: TLUiDialogTitleProps) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @public */
|
/** @public */
|
||||||
export function DialogCloseButton() {
|
export function TldrawUiDialogCloseButton() {
|
||||||
return (
|
return (
|
||||||
<div className="tlui-dialog__header__close">
|
<div className="tlui-dialog__header__close">
|
||||||
<_Dialog.DialogClose data-testid="dialog.close" dir="ltr" asChild>
|
<_Dialog.DialogClose data-testid="dialog.close" dir="ltr" asChild>
|
||||||
<Button
|
<TldrawUiButton
|
||||||
type="icon"
|
type="icon"
|
||||||
aria-label="Close"
|
aria-label="Close"
|
||||||
onTouchEnd={(e) => (e.target as HTMLButtonElement).click()}
|
onTouchEnd={(e) => (e.target as HTMLButtonElement).click()}
|
||||||
>
|
>
|
||||||
<Icon small icon="cross-2" />
|
<TldrawUiButtonIcon small icon="cross-2" />
|
||||||
</Button>
|
</TldrawUiButton>
|
||||||
</_Dialog.DialogClose>
|
</_Dialog.DialogClose>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
@ -54,7 +54,7 @@ export type TLUiDialogBodyProps = {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @public */
|
/** @public */
|
||||||
export function DialogBody({ className, children, style }: TLUiDialogBodyProps) {
|
export function TldrawUiDialogBody({ className, children, style }: TLUiDialogBodyProps) {
|
||||||
return (
|
return (
|
||||||
<div className={classNames('tlui-dialog__body', className)} style={style}>
|
<div className={classNames('tlui-dialog__body', className)} style={style}>
|
||||||
{children}
|
{children}
|
||||||
|
@ -69,6 +69,6 @@ export type TLUiDialogFooterProps = {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @public */
|
/** @public */
|
||||||
export function DialogFooter({ className, children }: TLUiDialogFooterProps) {
|
export function TldrawUiDialogFooter({ className, children }: TLUiDialogFooterProps) {
|
||||||
return <div className={classNames('tlui-dialog__footer', className)}>{children}</div>
|
return <div className={classNames('tlui-dialog__footer', className)}>{children}</div>
|
||||||
}
|
}
|
|
@ -1,8 +1,10 @@
|
||||||
import * as _DropdownMenu from '@radix-ui/react-dropdown-menu'
|
import * as _DropdownMenu from '@radix-ui/react-dropdown-menu'
|
||||||
import { preventDefault, useContainer } from '@tldraw/editor'
|
import { preventDefault, useContainer } from '@tldraw/editor'
|
||||||
import { useMenuIsOpen } from '../../hooks/useMenuIsOpen'
|
import { useMenuIsOpen } from '../../hooks/useMenuIsOpen'
|
||||||
import { Button, TLUiButtonProps } from './Button'
|
import { TldrawUiButton } from './Button/TldrawUiButton'
|
||||||
import { Icon } from './Icon'
|
import { TldrawUiButtonIcon } from './Button/TldrawUiButtonIcon'
|
||||||
|
import { TldrawUiButtonLabel } from './Button/TldrawUiButtonLabel'
|
||||||
|
import { TldrawUiIcon } from './TldrawUiIcon'
|
||||||
|
|
||||||
/** @public */
|
/** @public */
|
||||||
export type TLUiDropdownMenuRootProps = {
|
export type TLUiDropdownMenuRootProps = {
|
||||||
|
@ -13,7 +15,7 @@ export type TLUiDropdownMenuRootProps = {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @public */
|
/** @public */
|
||||||
export function DropdownMenuRoot({
|
export function TldrawUiDropdownMenuRoot({
|
||||||
id,
|
id,
|
||||||
children,
|
children,
|
||||||
modal = false,
|
modal = false,
|
||||||
|
@ -34,20 +36,21 @@ export function DropdownMenuRoot({
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @public */
|
/** @public */
|
||||||
export interface TLUiDropdownMenuTriggerProps extends TLUiButtonProps {
|
export interface TLUiDropdownMenuTriggerProps {
|
||||||
children?: any
|
children?: any
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @public */
|
/** @public */
|
||||||
export function DropdownMenuTrigger({ children, ...rest }: TLUiDropdownMenuTriggerProps) {
|
export function TldrawUiDropdownMenuTrigger({ children, ...rest }: TLUiDropdownMenuTriggerProps) {
|
||||||
return (
|
return (
|
||||||
<_DropdownMenu.Trigger
|
<_DropdownMenu.Trigger
|
||||||
dir="ltr"
|
dir="ltr"
|
||||||
asChild
|
asChild
|
||||||
// Firefox fix: Stop the dropdown immediately closing after touch
|
// Firefox fix: Stop the dropdown immediately closing after touch
|
||||||
onTouchEnd={(e) => preventDefault(e)}
|
onTouchEnd={(e) => preventDefault(e)}
|
||||||
|
{...rest}
|
||||||
>
|
>
|
||||||
<Button {...rest}>{children}</Button>
|
{children}
|
||||||
</_DropdownMenu.Trigger>
|
</_DropdownMenu.Trigger>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -63,7 +66,7 @@ export type TLUiDropdownMenuContentProps = {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @public */
|
/** @public */
|
||||||
export function DropdownMenuContent({
|
export function TldrawUiDropdownMenuContent({
|
||||||
side = 'bottom',
|
side = 'bottom',
|
||||||
align = 'start',
|
align = 'start',
|
||||||
sideOffset = 8,
|
sideOffset = 8,
|
||||||
|
@ -92,7 +95,7 @@ export function DropdownMenuContent({
|
||||||
export type TLUiDropdownMenuSubProps = { id: string; children: any }
|
export type TLUiDropdownMenuSubProps = { id: string; children: any }
|
||||||
|
|
||||||
/** @public */
|
/** @public */
|
||||||
export function DropdownMenuSub({ id, children }: TLUiDropdownMenuSubProps) {
|
export function TldrawUiDropdownMenuSub({ id, children }: TLUiDropdownMenuSubProps) {
|
||||||
const [open, onOpenChange] = useMenuIsOpen(id)
|
const [open, onOpenChange] = useMenuIsOpen(id)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -111,21 +114,22 @@ export type TLUiDropdownMenuSubTriggerProps = {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @public */
|
/** @public */
|
||||||
export function DropdownMenuSubTrigger({
|
export function TldrawUiDropdownMenuSubTrigger({
|
||||||
label,
|
label,
|
||||||
title,
|
title,
|
||||||
disabled,
|
disabled,
|
||||||
}: TLUiDropdownMenuSubTriggerProps) {
|
}: TLUiDropdownMenuSubTriggerProps) {
|
||||||
return (
|
return (
|
||||||
<_DropdownMenu.SubTrigger dir="ltr" asChild>
|
<_DropdownMenu.SubTrigger dir="ltr" asChild>
|
||||||
<Button
|
<TldrawUiButton
|
||||||
type="menu"
|
type="menu"
|
||||||
className="tlui-menu__submenu__trigger"
|
className="tlui-menu__submenu__trigger"
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
title={title}
|
title={title}
|
||||||
label={label}
|
>
|
||||||
icon="chevron-right"
|
<TldrawUiButtonLabel>{label}</TldrawUiButtonLabel>
|
||||||
/>
|
<TldrawUiButtonIcon icon="chevron-right" small />
|
||||||
|
</TldrawUiButton>
|
||||||
</_DropdownMenu.SubTrigger>
|
</_DropdownMenu.SubTrigger>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -139,7 +143,7 @@ export type TLUiDropdownMenuSubContentProps = {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @public */
|
/** @public */
|
||||||
export function DropdownMenuSubContent({
|
export function TldrawUiDropdownMenuSubContent({
|
||||||
alignOffset = -1,
|
alignOffset = -1,
|
||||||
sideOffset = -4,
|
sideOffset = -4,
|
||||||
children,
|
children,
|
||||||
|
@ -166,7 +170,10 @@ export type TLUiDropdownMenuGroupProps = {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @public */
|
/** @public */
|
||||||
export function DropdownMenuGroup({ children, size = 'medium' }: TLUiDropdownMenuGroupProps) {
|
export function TldrawUiDropdownMenuGroup({
|
||||||
|
children,
|
||||||
|
size = 'medium',
|
||||||
|
}: TLUiDropdownMenuGroupProps) {
|
||||||
return (
|
return (
|
||||||
<_DropdownMenu.Group dir="ltr" className="tlui-menu__group" data-size={size}>
|
<_DropdownMenu.Group dir="ltr" className="tlui-menu__group" data-size={size}>
|
||||||
{children}
|
{children}
|
||||||
|
@ -175,28 +182,25 @@ export function DropdownMenuGroup({ children, size = 'medium' }: TLUiDropdownMen
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @public */
|
/** @public */
|
||||||
export function DropdownMenuIndicator() {
|
export function TldrawUiDropdownMenuIndicator() {
|
||||||
return (
|
return (
|
||||||
<_DropdownMenu.ItemIndicator dir="ltr" asChild>
|
<_DropdownMenu.ItemIndicator dir="ltr" asChild>
|
||||||
<Icon icon="check" />
|
<TldrawUiIcon icon="check" />
|
||||||
</_DropdownMenu.ItemIndicator>
|
</_DropdownMenu.ItemIndicator>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @public */
|
/** @public */
|
||||||
export interface TLUiDropdownMenuItemProps extends TLUiButtonProps {
|
export interface TLUiDropdownMenuItemProps {
|
||||||
noClose?: boolean
|
noClose?: boolean
|
||||||
|
children: any
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @public */
|
/** @public */
|
||||||
export function DropdownMenuItem({ noClose, ...props }: TLUiDropdownMenuItemProps) {
|
export function TldrawUiDropdownMenuItem({ noClose, children }: TLUiDropdownMenuItemProps) {
|
||||||
return (
|
return (
|
||||||
<_DropdownMenu.Item
|
<_DropdownMenu.Item dir="ltr" asChild onClick={noClose ? preventDefault : undefined}>
|
||||||
dir="ltr"
|
{children}
|
||||||
asChild
|
|
||||||
onClick={noClose || props.isChecked !== undefined ? preventDefault : undefined}
|
|
||||||
>
|
|
||||||
<Button {...props} />
|
|
||||||
</_DropdownMenu.Item>
|
</_DropdownMenu.Item>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -211,7 +215,7 @@ export interface TLUiDropdownMenuCheckboxItemProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @public */
|
/** @public */
|
||||||
export function DropdownMenuCheckboxItem({
|
export function TldrawUiDropdownMenuCheckboxItem({
|
||||||
children,
|
children,
|
||||||
onSelect,
|
onSelect,
|
||||||
...rest
|
...rest
|
||||||
|
@ -228,38 +232,7 @@ export function DropdownMenuCheckboxItem({
|
||||||
>
|
>
|
||||||
<div className="tlui-button__checkbox__indicator">
|
<div className="tlui-button__checkbox__indicator">
|
||||||
<_DropdownMenu.ItemIndicator dir="ltr">
|
<_DropdownMenu.ItemIndicator dir="ltr">
|
||||||
<Icon icon="check" small />
|
<TldrawUiIcon icon="check" small />
|
||||||
</_DropdownMenu.ItemIndicator>
|
|
||||||
</div>
|
|
||||||
{children}
|
|
||||||
</_DropdownMenu.CheckboxItem>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @public */
|
|
||||||
export interface TLUiDropdownMenuRadioItemProps {
|
|
||||||
checked?: boolean
|
|
||||||
onSelect?: (e: Event) => void
|
|
||||||
disabled?: boolean
|
|
||||||
title: string
|
|
||||||
children: any
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @public */
|
|
||||||
export function DropdownMenuRadioItem({ children, ...rest }: TLUiDropdownMenuRadioItemProps) {
|
|
||||||
return (
|
|
||||||
<_DropdownMenu.CheckboxItem
|
|
||||||
dir="ltr"
|
|
||||||
className="tlui-button tlui-button__menu tlui-button__checkbox"
|
|
||||||
{...rest}
|
|
||||||
onSelect={(e) => {
|
|
||||||
preventDefault(e)
|
|
||||||
rest.onSelect?.(e)
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div className="tlui-button__checkbox__indicator">
|
|
||||||
<_DropdownMenu.ItemIndicator dir="ltr">
|
|
||||||
<Icon icon="check" small />
|
|
||||||
</_DropdownMenu.ItemIndicator>
|
</_DropdownMenu.ItemIndicator>
|
||||||
</div>
|
</div>
|
||||||
{children}
|
{children}
|
|
@ -14,7 +14,7 @@ export interface TLUiIconProps extends React.HTMLProps<HTMLDivElement> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @public */
|
/** @public */
|
||||||
export const Icon = memo(function Icon({
|
export const TldrawUiIcon = memo(function TldrawUi({
|
||||||
small,
|
small,
|
||||||
invertIcon,
|
invertIcon,
|
||||||
icon,
|
icon,
|
|
@ -0,0 +1,167 @@
|
||||||
|
import { stopEventPropagation, useEditor } from '@tldraw/editor'
|
||||||
|
import classNames from 'classnames'
|
||||||
|
import * as React from 'react'
|
||||||
|
import { TLUiTranslationKey } from '../../hooks/useTranslation/TLUiTranslationKey'
|
||||||
|
import { useTranslation } from '../../hooks/useTranslation/useTranslation'
|
||||||
|
import { TLUiIconType } from '../../icon-types'
|
||||||
|
import { TldrawUiIcon } from './TldrawUiIcon'
|
||||||
|
|
||||||
|
/** @public */
|
||||||
|
export interface TLUiInputProps {
|
||||||
|
disabled?: boolean
|
||||||
|
label?: TLUiTranslationKey | Exclude<string, TLUiTranslationKey>
|
||||||
|
icon?: TLUiIconType | Exclude<string, TLUiIconType>
|
||||||
|
iconLeft?: TLUiIconType | Exclude<string, TLUiIconType>
|
||||||
|
autofocus?: boolean
|
||||||
|
autoselect?: boolean
|
||||||
|
children?: any
|
||||||
|
defaultValue?: string
|
||||||
|
placeholder?: string
|
||||||
|
onComplete?: (value: string) => void
|
||||||
|
onValueChange?: (value: string) => void
|
||||||
|
onCancel?: (value: string) => void
|
||||||
|
onBlur?: (value: string) => void
|
||||||
|
className?: string
|
||||||
|
/**
|
||||||
|
* Usually on iOS when you focus an input, the browser will adjust the viewport to bring the input
|
||||||
|
* into view. Sometimes this doesn't work properly though - for example, if the input is newly
|
||||||
|
* created, iOS seems to have a hard time adjusting the viewport for it. This prop allows you to
|
||||||
|
* opt-in to some extra code to manually bring the input into view when the visual viewport of the
|
||||||
|
* browser changes, but we don't want to use it everywhere because generally the native behavior
|
||||||
|
* looks nicer in scenarios where it's sufficient.
|
||||||
|
*/
|
||||||
|
shouldManuallyMaintainScrollPositionWhenFocused?: boolean
|
||||||
|
value?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @public */
|
||||||
|
export const TldrawUiInput = React.forwardRef<HTMLInputElement, TLUiInputProps>(
|
||||||
|
function TldrawUiInput(
|
||||||
|
{
|
||||||
|
className,
|
||||||
|
label,
|
||||||
|
icon,
|
||||||
|
iconLeft,
|
||||||
|
autoselect = false,
|
||||||
|
autofocus = false,
|
||||||
|
defaultValue,
|
||||||
|
placeholder,
|
||||||
|
onComplete,
|
||||||
|
onValueChange,
|
||||||
|
onCancel,
|
||||||
|
onBlur,
|
||||||
|
shouldManuallyMaintainScrollPositionWhenFocused = false,
|
||||||
|
children,
|
||||||
|
value,
|
||||||
|
},
|
||||||
|
ref
|
||||||
|
) {
|
||||||
|
const editor = useEditor()
|
||||||
|
const rInputRef = React.useRef<HTMLInputElement>(null)
|
||||||
|
|
||||||
|
// combine rInputRef and ref
|
||||||
|
React.useImperativeHandle(ref, () => rInputRef.current as HTMLInputElement)
|
||||||
|
|
||||||
|
const msg = useTranslation()
|
||||||
|
const rInitialValue = React.useRef<string>(defaultValue ?? '')
|
||||||
|
const rCurrentValue = React.useRef<string>(defaultValue ?? '')
|
||||||
|
|
||||||
|
const [isFocused, setIsFocused] = React.useState(false)
|
||||||
|
const handleFocus = React.useCallback(
|
||||||
|
(e: React.FocusEvent<HTMLInputElement>) => {
|
||||||
|
setIsFocused(true)
|
||||||
|
const elm = e.currentTarget as HTMLInputElement
|
||||||
|
rCurrentValue.current = elm.value
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
if (autoselect) {
|
||||||
|
elm.select()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
[autoselect]
|
||||||
|
)
|
||||||
|
|
||||||
|
const handleChange = React.useCallback(
|
||||||
|
(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
const value = e.currentTarget.value
|
||||||
|
rCurrentValue.current = value
|
||||||
|
onValueChange?.(value)
|
||||||
|
},
|
||||||
|
[onValueChange]
|
||||||
|
)
|
||||||
|
|
||||||
|
const handleKeyUp = React.useCallback(
|
||||||
|
(e: React.KeyboardEvent<HTMLInputElement>) => {
|
||||||
|
switch (e.key) {
|
||||||
|
case 'Enter': {
|
||||||
|
e.currentTarget.blur()
|
||||||
|
stopEventPropagation(e)
|
||||||
|
onComplete?.(e.currentTarget.value)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case 'Escape': {
|
||||||
|
e.currentTarget.value = rInitialValue.current
|
||||||
|
e.currentTarget.blur()
|
||||||
|
stopEventPropagation(e)
|
||||||
|
onCancel?.(e.currentTarget.value)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[onComplete, onCancel]
|
||||||
|
)
|
||||||
|
|
||||||
|
const handleBlur = React.useCallback(
|
||||||
|
(e: React.FocusEvent<HTMLInputElement>) => {
|
||||||
|
setIsFocused(false)
|
||||||
|
const value = e.currentTarget.value
|
||||||
|
onBlur?.(value)
|
||||||
|
},
|
||||||
|
[onBlur]
|
||||||
|
)
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (!editor.environment.isIos) return
|
||||||
|
|
||||||
|
const visualViewport = window.visualViewport
|
||||||
|
if (isFocused && shouldManuallyMaintainScrollPositionWhenFocused && visualViewport) {
|
||||||
|
const onViewportChange = () => {
|
||||||
|
rInputRef.current?.scrollIntoView({ block: 'center' })
|
||||||
|
}
|
||||||
|
visualViewport.addEventListener('resize', onViewportChange)
|
||||||
|
visualViewport.addEventListener('scroll', onViewportChange)
|
||||||
|
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
rInputRef.current?.scrollIntoView({ block: 'center' })
|
||||||
|
})
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
visualViewport.removeEventListener('resize', onViewportChange)
|
||||||
|
visualViewport.removeEventListener('scroll', onViewportChange)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [editor, isFocused, shouldManuallyMaintainScrollPositionWhenFocused])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div draggable={false} className="tlui-input__wrapper">
|
||||||
|
{children}
|
||||||
|
{label && <label>{msg(label)}</label>}
|
||||||
|
{iconLeft && <TldrawUiIcon icon={iconLeft} className="tlui-icon-left" small />}
|
||||||
|
<input
|
||||||
|
ref={rInputRef}
|
||||||
|
className={classNames('tlui-input', className)}
|
||||||
|
type="text"
|
||||||
|
defaultValue={defaultValue}
|
||||||
|
onKeyUp={handleKeyUp}
|
||||||
|
onChange={handleChange}
|
||||||
|
onFocus={handleFocus}
|
||||||
|
onBlur={handleBlur}
|
||||||
|
autoFocus={autofocus}
|
||||||
|
placeholder={placeholder}
|
||||||
|
value={value}
|
||||||
|
/>
|
||||||
|
{icon && <TldrawUiIcon icon={icon} small={!!label} />}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
|
@ -1,14 +1,14 @@
|
||||||
import { PORTRAIT_BREAKPOINT } from '../../constants'
|
import { PORTRAIT_BREAKPOINT } from '../../constants'
|
||||||
import { useBreakpoint } from '../../context/breakpoints'
|
import { useBreakpoint } from '../../context/breakpoints'
|
||||||
import { kbd } from './shared'
|
import { kbd } from '../../kbd-utils'
|
||||||
|
|
||||||
/** @internal */
|
/** @public */
|
||||||
export interface KbdProps {
|
export interface TLUiKbdProps {
|
||||||
children: string
|
children: string
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @internal */
|
/** @public */
|
||||||
export function Kbd({ children }: KbdProps) {
|
export function TldrawUiKbd({ children }: TLUiKbdProps) {
|
||||||
const breakpoint = useBreakpoint()
|
const breakpoint = useBreakpoint()
|
||||||
if (breakpoint < PORTRAIT_BREAKPOINT.MOBILE) return null
|
if (breakpoint < PORTRAIT_BREAKPOINT.MOBILE) return null
|
||||||
return (
|
return (
|
|
@ -2,7 +2,6 @@ import * as PopoverPrimitive from '@radix-ui/react-popover'
|
||||||
import { useContainer } from '@tldraw/editor'
|
import { useContainer } from '@tldraw/editor'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { useMenuIsOpen } from '../../hooks/useMenuIsOpen'
|
import { useMenuIsOpen } from '../../hooks/useMenuIsOpen'
|
||||||
import { Button, TLUiButtonProps } from './Button'
|
|
||||||
|
|
||||||
/** @public */
|
/** @public */
|
||||||
export type TLUiPopoverProps = {
|
export type TLUiPopoverProps = {
|
||||||
|
@ -13,7 +12,7 @@ export type TLUiPopoverProps = {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @public */
|
/** @public */
|
||||||
export function Popover({ id, children, onOpenChange, open }: TLUiPopoverProps) {
|
export function TldrawUiPopover({ id, children, onOpenChange, open }: TLUiPopoverProps) {
|
||||||
const [isOpen, handleOpenChange] = useMenuIsOpen(id, onOpenChange)
|
const [isOpen, handleOpenChange] = useMenuIsOpen(id, onOpenChange)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -27,15 +26,15 @@ export function Popover({ id, children, onOpenChange, open }: TLUiPopoverProps)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @public */
|
/** @public */
|
||||||
export interface TLUiPopoverTriggerProps extends TLUiButtonProps {
|
export interface TLUiPopoverTriggerProps {
|
||||||
children?: React.ReactNode
|
children?: React.ReactNode
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @public */
|
/** @public */
|
||||||
export function PopoverTrigger({ children, ...rest }: TLUiPopoverTriggerProps) {
|
export function TldrawUiPopoverTrigger({ children }: TLUiPopoverTriggerProps) {
|
||||||
return (
|
return (
|
||||||
<PopoverPrimitive.Trigger asChild dir="ltr">
|
<PopoverPrimitive.Trigger asChild dir="ltr">
|
||||||
<Button {...rest}>{children}</Button>
|
{children}
|
||||||
</PopoverPrimitive.Trigger>
|
</PopoverPrimitive.Trigger>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -50,7 +49,7 @@ export type TLUiPopoverContentProps = {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @public */
|
/** @public */
|
||||||
export function PopoverContent({
|
export function TldrawUiPopoverContent({
|
||||||
side,
|
side,
|
||||||
children,
|
children,
|
||||||
align = 'center',
|
align = 'center',
|
|
@ -5,7 +5,7 @@ import { TLUiTranslationKey } from '../../hooks/useTranslation/TLUiTranslationKe
|
||||||
import { useTranslation } from '../../hooks/useTranslation/useTranslation'
|
import { useTranslation } from '../../hooks/useTranslation/useTranslation'
|
||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
export interface SliderProps {
|
export interface TLUiSliderProps {
|
||||||
steps: number
|
steps: number
|
||||||
value: number | null
|
value: number | null
|
||||||
label: string
|
label: string
|
||||||
|
@ -15,7 +15,7 @@ export interface SliderProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
export const Slider = memo(function Slider(props: SliderProps) {
|
export const TldrawUiSlider = memo(function Slider(props: TLUiSliderProps) {
|
||||||
const { title, steps, value, label, onValueChange } = props
|
const { title, steps, value, label, onValueChange } = props
|
||||||
const editor = useEditor()
|
const editor = useEditor()
|
||||||
const msg = useTranslation()
|
const msg = useTranslation()
|
|
@ -1,13 +1,13 @@
|
||||||
import * as _ContextMenu from '@radix-ui/react-context-menu'
|
import * as _ContextMenu from '@radix-ui/react-context-menu'
|
||||||
import * as _DropdownMenu from '@radix-ui/react-dropdown-menu'
|
import * as _DropdownMenu from '@radix-ui/react-dropdown-menu'
|
||||||
import { preventDefault } from '@tldraw/editor'
|
import { preventDefault } from '@tldraw/editor'
|
||||||
import { unwrapLabel } from '../../context/actions'
|
import { unwrapLabel } from '../../../context/actions'
|
||||||
import { TLUiEventSource } from '../../context/events'
|
import { TLUiEventSource } from '../../../context/events'
|
||||||
import { useReadonly } from '../../hooks/useReadonly'
|
import { useReadonly } from '../../../hooks/useReadonly'
|
||||||
import { TLUiTranslationKey } from '../../hooks/useTranslation/TLUiTranslationKey'
|
import { TLUiTranslationKey } from '../../../hooks/useTranslation/TLUiTranslationKey'
|
||||||
import { useTranslation } from '../../hooks/useTranslation/useTranslation'
|
import { useTranslation } from '../../../hooks/useTranslation/useTranslation'
|
||||||
import { Icon } from '../primitives/Icon'
|
import { TldrawUiIcon } from '../TldrawUiIcon'
|
||||||
import { Kbd } from '../primitives/Kbd'
|
import { TldrawUiKbd } from '../TldrawUiKbd'
|
||||||
import { useTldrawUiMenuContext } from './TldrawUiMenuContext'
|
import { useTldrawUiMenuContext } from './TldrawUiMenuContext'
|
||||||
|
|
||||||
/** @public */
|
/** @public */
|
||||||
|
@ -63,13 +63,13 @@ export function TldrawUiMenuCheckboxItem<
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
checked={checked}
|
checked={checked}
|
||||||
>
|
>
|
||||||
<Icon small icon={checked ? 'check' : 'checkbox-empty'} />
|
<TldrawUiIcon small icon={checked ? 'check' : 'checkbox-empty'} />
|
||||||
{labelStr && (
|
{labelStr && (
|
||||||
<span className="tlui-button__label" draggable={false}>
|
<span className="tlui-button__label" draggable={false}>
|
||||||
{labelStr}
|
{labelStr}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
{kbd && <Kbd>{kbd}</Kbd>}
|
{kbd && <TldrawUiKbd>{kbd}</TldrawUiKbd>}
|
||||||
</_DropdownMenu.CheckboxItem>
|
</_DropdownMenu.CheckboxItem>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -87,13 +87,13 @@ export function TldrawUiMenuCheckboxItem<
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
checked={checked}
|
checked={checked}
|
||||||
>
|
>
|
||||||
<Icon small icon={checked ? 'check' : 'checkbox-empty'} />
|
<TldrawUiIcon small icon={checked ? 'check' : 'checkbox-empty'} />
|
||||||
{labelStr && (
|
{labelStr && (
|
||||||
<span className="tlui-button__label" draggable={false}>
|
<span className="tlui-button__label" draggable={false}>
|
||||||
{labelStr}
|
{labelStr}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
{kbd && <Kbd>{kbd}</Kbd>}
|
{kbd && <TldrawUiKbd>{kbd}</TldrawUiKbd>}
|
||||||
</_ContextMenu.CheckboxItem>
|
</_ContextMenu.CheckboxItem>
|
||||||
)
|
)
|
||||||
}
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
import { createContext, useContext } from 'react'
|
import { createContext, useContext } from 'react'
|
||||||
import { TLUiEventSource } from '../../context/events'
|
import { TLUiEventSource } from '../../../context/events'
|
||||||
|
|
||||||
/** @public */
|
/** @public */
|
||||||
export type TldrawUiMenuContextType =
|
export type TldrawUiMenuContextType =
|
|
@ -1,8 +1,8 @@
|
||||||
import { ContextMenuGroup } from '@radix-ui/react-context-menu'
|
import { ContextMenuGroup } from '@radix-ui/react-context-menu'
|
||||||
import { unwrapLabel } from '../../context/actions'
|
import { unwrapLabel } from '../../../context/actions'
|
||||||
import { TLUiTranslationKey } from '../../hooks/useTranslation/TLUiTranslationKey'
|
import { TLUiTranslationKey } from '../../../hooks/useTranslation/TLUiTranslationKey'
|
||||||
import { useTranslation } from '../../hooks/useTranslation/useTranslation'
|
import { useTranslation } from '../../../hooks/useTranslation/useTranslation'
|
||||||
import { DropdownMenuGroup } from '../primitives/DropdownMenu'
|
import { TldrawUiDropdownMenuGroup } from '../TldrawUiDropdownMenu'
|
||||||
import { useTldrawUiMenuContext } from './TldrawUiMenuContext'
|
import { useTldrawUiMenuContext } from './TldrawUiMenuContext'
|
||||||
|
|
||||||
/** @public */
|
/** @public */
|
||||||
|
@ -33,9 +33,12 @@ export function TldrawUiMenuGroup({ id, label, small = false, children }: TLUiMe
|
||||||
}
|
}
|
||||||
case 'menu': {
|
case 'menu': {
|
||||||
return (
|
return (
|
||||||
<DropdownMenuGroup data-testid={`${sourceId}-group.${id}`} size={small ? 'tiny' : 'medium'}>
|
<TldrawUiDropdownMenuGroup
|
||||||
|
data-testid={`${sourceId}-group.${id}`}
|
||||||
|
size={small ? 'tiny' : 'medium'}
|
||||||
|
>
|
||||||
{children}
|
{children}
|
||||||
</DropdownMenuGroup>
|
</TldrawUiDropdownMenuGroup>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
case 'context-menu': {
|
case 'context-menu': {
|
|
@ -1,16 +1,18 @@
|
||||||
import { ContextMenuItem } from '@radix-ui/react-context-menu'
|
import { ContextMenuItem } from '@radix-ui/react-context-menu'
|
||||||
import { preventDefault } from '@tldraw/editor'
|
import { preventDefault } from '@tldraw/editor'
|
||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
import { unwrapLabel } from '../../context/actions'
|
import { unwrapLabel } from '../../../context/actions'
|
||||||
import { TLUiEventSource } from '../../context/events'
|
import { TLUiEventSource } from '../../../context/events'
|
||||||
import { useReadonly } from '../../hooks/useReadonly'
|
import { useReadonly } from '../../../hooks/useReadonly'
|
||||||
import { TLUiTranslationKey } from '../../hooks/useTranslation/TLUiTranslationKey'
|
import { TLUiTranslationKey } from '../../../hooks/useTranslation/TLUiTranslationKey'
|
||||||
import { useTranslation } from '../../hooks/useTranslation/useTranslation'
|
import { useTranslation } from '../../../hooks/useTranslation/useTranslation'
|
||||||
import { Spinner } from '../Spinner'
|
import { kbdStr } from '../../../kbd-utils'
|
||||||
import { Button } from '../primitives/Button'
|
import { Spinner } from '../../Spinner'
|
||||||
import { DropdownMenuItem } from '../primitives/DropdownMenu'
|
import { TldrawUiButton } from '../Button/TldrawUiButton'
|
||||||
import { Kbd } from '../primitives/Kbd'
|
import { TldrawUiButtonIcon } from '../Button/TldrawUiButtonIcon'
|
||||||
import { kbdStr } from '../primitives/shared'
|
import { TldrawUiButtonLabel } from '../Button/TldrawUiButtonLabel'
|
||||||
|
import { TldrawUiDropdownMenuItem } from '../TldrawUiDropdownMenu'
|
||||||
|
import { TldrawUiKbd } from '../TldrawUiKbd'
|
||||||
import { useTldrawUiMenuContext } from './TldrawUiMenuContext'
|
import { useTldrawUiMenuContext } from './TldrawUiMenuContext'
|
||||||
|
|
||||||
/** @public */
|
/** @public */
|
||||||
|
@ -90,11 +92,10 @@ export function TldrawUiMenuItem<
|
||||||
switch (menuType) {
|
switch (menuType) {
|
||||||
case 'menu': {
|
case 'menu': {
|
||||||
return (
|
return (
|
||||||
<DropdownMenuItem
|
<TldrawUiDropdownMenuItem>
|
||||||
|
<TldrawUiButton
|
||||||
type="menu"
|
type="menu"
|
||||||
data-testid={`${sourceId}.${id}`}
|
data-testid={`${sourceId}.${id}`}
|
||||||
kbd={kbd}
|
|
||||||
label={labelStr}
|
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
title={titleStr}
|
title={titleStr}
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
|
@ -107,7 +108,11 @@ export function TldrawUiMenuItem<
|
||||||
onSelect(sourceId)
|
onSelect(sourceId)
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
>
|
||||||
|
<TldrawUiButtonLabel>{labelStr}</TldrawUiButtonLabel>
|
||||||
|
{kbd && <TldrawUiKbd>{kbd}</TldrawUiKbd>}
|
||||||
|
</TldrawUiButton>
|
||||||
|
</TldrawUiDropdownMenuItem>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
case 'context-menu': {
|
case 'context-menu': {
|
||||||
|
@ -133,37 +138,37 @@ export function TldrawUiMenuItem<
|
||||||
<span className="tlui-button__label" draggable={false}>
|
<span className="tlui-button__label" draggable={false}>
|
||||||
{labelStr}
|
{labelStr}
|
||||||
</span>
|
</span>
|
||||||
{kbd && <Kbd>{kbd}</Kbd>}
|
{kbd && <TldrawUiKbd>{kbd}</TldrawUiKbd>}
|
||||||
{spinner && <Spinner />}
|
{spinner && <Spinner />}
|
||||||
</ContextMenuItem>
|
</ContextMenuItem>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
case 'panel': {
|
case 'panel': {
|
||||||
return (
|
return (
|
||||||
<Button
|
<TldrawUiButton
|
||||||
data-testid={`${sourceId}.${id}`}
|
data-testid={`${sourceId}.${id}`}
|
||||||
icon={icon}
|
|
||||||
type="menu"
|
type="menu"
|
||||||
label={labelStr}
|
|
||||||
title={titleStr}
|
title={titleStr}
|
||||||
onClick={() => onSelect(sourceId)}
|
|
||||||
smallIcon
|
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
/>
|
onClick={() => onSelect(sourceId)}
|
||||||
|
>
|
||||||
|
<TldrawUiButtonLabel>{labelStr}</TldrawUiButtonLabel>
|
||||||
|
{icon && <TldrawUiButtonIcon icon={icon} />}
|
||||||
|
</TldrawUiButton>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
case 'small-icons':
|
case 'small-icons':
|
||||||
case 'icons': {
|
case 'icons': {
|
||||||
return (
|
return (
|
||||||
<Button
|
<TldrawUiButton
|
||||||
data-testid={`${sourceId}.${id}`}
|
data-testid={`${sourceId}.${id}`}
|
||||||
icon={icon}
|
|
||||||
type="icon"
|
type="icon"
|
||||||
title={titleStr}
|
title={titleStr}
|
||||||
onClick={() => onSelect(sourceId)}
|
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
smallIcon={menuType === 'small-icons'}
|
onClick={() => onSelect(sourceId)}
|
||||||
/>
|
>
|
||||||
|
<TldrawUiButtonIcon icon={icon!} small={menuType === 'small-icons'} />
|
||||||
|
</TldrawUiButton>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
case 'keyboard-shortcuts': {
|
case 'keyboard-shortcuts': {
|
||||||
|
@ -173,14 +178,17 @@ export function TldrawUiMenuItem<
|
||||||
<div className="tlui-shortcuts-dialog__key-pair" data-testid={`${sourceId}.${id}`}>
|
<div className="tlui-shortcuts-dialog__key-pair" data-testid={`${sourceId}.${id}`}>
|
||||||
<div className="tlui-shortcuts-dialog__key-pair__key">{labelStr}</div>
|
<div className="tlui-shortcuts-dialog__key-pair__key">{labelStr}</div>
|
||||||
<div className="tlui-shortcuts-dialog__key-pair__value">
|
<div className="tlui-shortcuts-dialog__key-pair__value">
|
||||||
<Kbd>{kbd!}</Kbd>
|
<TldrawUiKbd>{kbd!}</TldrawUiKbd>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
case 'helper-buttons': {
|
case 'helper-buttons': {
|
||||||
return (
|
return (
|
||||||
<Button type="low" label={labelStr} iconLeft={icon} onClick={() => onSelect(sourceId)} />
|
<TldrawUiButton type="low" onClick={() => onSelect(sourceId)}>
|
||||||
|
<TldrawUiButtonIcon icon={icon!} />
|
||||||
|
<TldrawUiButtonLabel>{labelStr}</TldrawUiButtonLabel>
|
||||||
|
</TldrawUiButton>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
|
@ -5,15 +5,17 @@ import {
|
||||||
ContextMenuSubTrigger,
|
ContextMenuSubTrigger,
|
||||||
} from '@radix-ui/react-context-menu'
|
} from '@radix-ui/react-context-menu'
|
||||||
import { useContainer } from '@tldraw/editor'
|
import { useContainer } from '@tldraw/editor'
|
||||||
import { useMenuIsOpen } from '../../hooks/useMenuIsOpen'
|
import { useMenuIsOpen } from '../../../hooks/useMenuIsOpen'
|
||||||
import { TLUiTranslationKey } from '../../hooks/useTranslation/TLUiTranslationKey'
|
import { TLUiTranslationKey } from '../../../hooks/useTranslation/TLUiTranslationKey'
|
||||||
import { useTranslation } from '../../hooks/useTranslation/useTranslation'
|
import { useTranslation } from '../../../hooks/useTranslation/useTranslation'
|
||||||
import { Button } from '../primitives/Button'
|
import { TldrawUiButton } from '../Button/TldrawUiButton'
|
||||||
|
import { TldrawUiButtonIcon } from '../Button/TldrawUiButtonIcon'
|
||||||
|
import { TldrawUiButtonLabel } from '../Button/TldrawUiButtonLabel'
|
||||||
import {
|
import {
|
||||||
DropdownMenuSub,
|
TldrawUiDropdownMenuSub,
|
||||||
DropdownMenuSubContent,
|
TldrawUiDropdownMenuSubContent,
|
||||||
DropdownMenuSubTrigger,
|
TldrawUiDropdownMenuSubTrigger,
|
||||||
} from '../primitives/DropdownMenu'
|
} from '../TldrawUiDropdownMenu'
|
||||||
import { useTldrawUiMenuContext } from './TldrawUiMenuContext'
|
import { useTldrawUiMenuContext } from './TldrawUiMenuContext'
|
||||||
|
|
||||||
/** @public */
|
/** @public */
|
||||||
|
@ -46,34 +48,33 @@ export function TldrawUiMenuSubmenu<Translation extends string = string>({
|
||||||
switch (menuType) {
|
switch (menuType) {
|
||||||
case 'menu': {
|
case 'menu': {
|
||||||
return (
|
return (
|
||||||
<DropdownMenuSub id={`${sourceId}-sub.${id}`}>
|
<TldrawUiDropdownMenuSub id={`${sourceId}-sub.${id}`}>
|
||||||
<DropdownMenuSubTrigger
|
<TldrawUiDropdownMenuSubTrigger
|
||||||
id={`${sourceId}-sub.${id}`}
|
id={`${sourceId}-sub.${id}`}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
label={labelStr!}
|
label={labelStr!}
|
||||||
title={labelStr!}
|
title={labelStr!}
|
||||||
/>
|
/>
|
||||||
<DropdownMenuSubContent id={`${sourceId}-sub-content.${id}`} data-size={size}>
|
<TldrawUiDropdownMenuSubContent id={`${sourceId}-sub-content.${id}`} data-size={size}>
|
||||||
{children}
|
{children}
|
||||||
</DropdownMenuSubContent>
|
</TldrawUiDropdownMenuSubContent>
|
||||||
</DropdownMenuSub>
|
</TldrawUiDropdownMenuSub>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
case 'context-menu': {
|
case 'context-menu': {
|
||||||
|
if (disabled) return null
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ContextMenuSubWithMenu id={`${sourceId}-sub.${id}`}>
|
<ContextMenuSubWithMenu id={`${sourceId}-sub.${id}`}>
|
||||||
<ContextMenuSubTrigger
|
<ContextMenuSubTrigger dir="ltr" disabled={disabled} asChild>
|
||||||
dir="ltr"
|
<TldrawUiButton
|
||||||
disabled={disabled}
|
|
||||||
data-testid={`${sourceId}-sub-trigger.${id}`}
|
data-testid={`${sourceId}-sub-trigger.${id}`}
|
||||||
asChild
|
|
||||||
>
|
|
||||||
<Button
|
|
||||||
type="menu"
|
type="menu"
|
||||||
className="tlui-menu__submenu__trigger"
|
className="tlui-menu__submenu__trigger"
|
||||||
label={labelStr}
|
>
|
||||||
icon="chevron-right"
|
<TldrawUiButtonLabel>{labelStr}</TldrawUiButtonLabel>
|
||||||
/>
|
<TldrawUiButtonIcon icon="chevron-right" small />
|
||||||
|
</TldrawUiButton>
|
||||||
</ContextMenuSubTrigger>
|
</ContextMenuSubTrigger>
|
||||||
<ContextMenuPortal container={container}>
|
<ContextMenuPortal container={container}>
|
||||||
<ContextMenuSubContent
|
<ContextMenuSubContent
|
|
@ -76,6 +76,7 @@ export function TldrawUiContextProvider({
|
||||||
</AssetUrlsProvider>
|
</AssetUrlsProvider>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function InternalProviders({
|
function InternalProviders({
|
||||||
overrides,
|
overrides,
|
||||||
children,
|
children,
|
||||||
|
|
|
@ -19,6 +19,7 @@ import {
|
||||||
TLUiKeyboardShortcutsDialogProps,
|
TLUiKeyboardShortcutsDialogProps,
|
||||||
} from '../components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialog'
|
} from '../components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialog'
|
||||||
import { DefaultMainMenu, TLUiMainMenuProps } from '../components/MainMenu/DefaultMainMenu'
|
import { DefaultMainMenu, TLUiMainMenuProps } from '../components/MainMenu/DefaultMainMenu'
|
||||||
|
import { DefaultMenuPanel } from '../components/MenuPanel'
|
||||||
import { DefaultMinimap } from '../components/Minimap/DefaultMinimap'
|
import { DefaultMinimap } from '../components/Minimap/DefaultMinimap'
|
||||||
import { DefaultNavigationPanel } from '../components/NavigationPanel/DefaultNavigationPanel'
|
import { DefaultNavigationPanel } from '../components/NavigationPanel/DefaultNavigationPanel'
|
||||||
import { DefaultPageMenu } from '../components/PageMenu/DefaultPageMenu'
|
import { DefaultPageMenu } from '../components/PageMenu/DefaultPageMenu'
|
||||||
|
@ -45,6 +46,9 @@ export interface BaseTLUiComponents {
|
||||||
QuickActions: ComponentType<TLUiQuickActionsProps>
|
QuickActions: ComponentType<TLUiQuickActionsProps>
|
||||||
HelperButtons: ComponentType<TLUiHelperButtonsProps>
|
HelperButtons: ComponentType<TLUiHelperButtonsProps>
|
||||||
DebugMenu: ComponentType
|
DebugMenu: ComponentType
|
||||||
|
MenuPanel: ComponentType
|
||||||
|
TopPanel: ComponentType
|
||||||
|
SharePanel: ComponentType
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @public */
|
/** @public */
|
||||||
|
@ -54,7 +58,8 @@ export type TLUiComponents = Partial<{
|
||||||
|
|
||||||
const TldrawUiComponentsContext = createContext({} as TLUiComponents)
|
const TldrawUiComponentsContext = createContext({} as TLUiComponents)
|
||||||
|
|
||||||
type ComponentsContextProviderProps = {
|
/** @public */
|
||||||
|
export type TLUiComponentsProviderProps = {
|
||||||
overrides?: TLUiComponents
|
overrides?: TLUiComponents
|
||||||
children: any
|
children: any
|
||||||
}
|
}
|
||||||
|
@ -63,7 +68,7 @@ type ComponentsContextProviderProps = {
|
||||||
export function TldrawUiComponentsProvider({
|
export function TldrawUiComponentsProvider({
|
||||||
overrides = {},
|
overrides = {},
|
||||||
children,
|
children,
|
||||||
}: ComponentsContextProviderProps) {
|
}: TLUiComponentsProviderProps) {
|
||||||
const _overrides = useShallowObjectIdentity(overrides)
|
const _overrides = useShallowObjectIdentity(overrides)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -84,6 +89,7 @@ export function TldrawUiComponentsProvider({
|
||||||
QuickActions: DefaultQuickActions,
|
QuickActions: DefaultQuickActions,
|
||||||
HelperButtons: DefaultHelperButtons,
|
HelperButtons: DefaultHelperButtons,
|
||||||
DebugMenu: DefaultDebugMenu,
|
DebugMenu: DefaultDebugMenu,
|
||||||
|
MenuPanel: DefaultMenuPanel,
|
||||||
..._overrides,
|
..._overrides,
|
||||||
}),
|
}),
|
||||||
[_overrides]
|
[_overrides]
|
||||||
|
|
|
@ -1,11 +1,3 @@
|
||||||
/** @internal */
|
|
||||||
export function toStartCase(str: string) {
|
|
||||||
return str
|
|
||||||
.split(' ')
|
|
||||||
.map((s) => s.charAt(0).toUpperCase() + s.slice(1))
|
|
||||||
.join(' ')
|
|
||||||
}
|
|
||||||
|
|
||||||
const isDarwin =
|
const isDarwin =
|
||||||
typeof window === 'undefined'
|
typeof window === 'undefined'
|
||||||
? false
|
? false
|
||||||
|
@ -13,7 +5,7 @@ const isDarwin =
|
||||||
const cmdKey = isDarwin ? '⌘' : 'Ctrl'
|
const cmdKey = isDarwin ? '⌘' : 'Ctrl'
|
||||||
const altKey = isDarwin ? '⌥' : 'Alt'
|
const altKey = isDarwin ? '⌥' : 'Alt'
|
||||||
|
|
||||||
/** @internal */
|
/** @public */
|
||||||
export function kbd(str: string) {
|
export function kbd(str: string) {
|
||||||
return str
|
return str
|
||||||
.split(',')[0]
|
.split(',')[0]
|
||||||
|
@ -24,17 +16,7 @@ export function kbd(str: string) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @internal */
|
/** @public */
|
||||||
export function kbdStr(str: string) {
|
export function kbdStr(str: string) {
|
||||||
return (
|
return '— ' + kbd(str).join(' ')
|
||||||
'— ' +
|
|
||||||
str
|
|
||||||
.split(',')[0]
|
|
||||||
.split('')
|
|
||||||
.map((sub) => {
|
|
||||||
const subStr = sub.replace(/\$/g, cmdKey).replace(/\?/g, altKey).replace(/!/g, '⇧')
|
|
||||||
return subStr[0].toUpperCase() + subStr.slice(1)
|
|
||||||
})
|
|
||||||
.join(' ')
|
|
||||||
)
|
|
||||||
}
|
}
|
Loading…
Reference in a new issue