Move InFrontOfTheCanvas (#3782)
Our `InFrontOfTheCanvas` UI override component (we don't have a default implementation, it's just an entry point for sdk users to insert their own UI) was being mounted outside of the UI react context subtree, which is an error because it won't have access to important things like translations and asset URLs. #3750 made this bug manifest as a thrown error in our `context-toolbar` example, as reported in #3773. To fix this I just moved the injection site of the `InFrontOfTheCanvas` component to be within the UI context. It ends up in the same place in the DOM. This PR closes #3773 ### Change Type <!-- ❗ Please select a 'Scope' label ❗️ --> - [x] `sdk` — Changes the tldraw SDK - [ ] `dotcom` — Changes the tldraw.com web app - [ ] `docs` — Changes to the documentation, examples, or templates. - [ ] `vs code` — Changes to the vscode plugin - [ ] `internal` — Does not affect user-facing stuff <!-- ❗ Please select a 'Type' label ❗️ --> - [x] `bugfix` — Bug fix - [ ] `feature` — New feature - [ ] `improvement` — Improving existing features - [ ] `chore` — Updating dependencies, other boring stuff - [ ] `galaxy brain` — Architectural changes - [ ] `tests` — Changes to any test code - [ ] `tools` — Changes to infrastructure, CI, internal scripts, debugging tools, etc. - [ ] `dunno` — I don't know ### Test Plan 1. Add a step-by-step description of how to test your PR here. 2. - [ ] Unit Tests - [ ] End to end tests ### Release Notes - Add a brief release note for your PR here.
This commit is contained in:
parent
9ffd7f15ee
commit
29608838ef
4 changed files with 64 additions and 68 deletions
|
@ -389,22 +389,7 @@ function Layout({ children, onMount }: { children: ReactNode; onMount?: TLOnMoun
|
|||
useForceUpdate()
|
||||
useOnMount(onMount)
|
||||
|
||||
return (
|
||||
<>
|
||||
{children}
|
||||
<InFrontOfTheCanvasWrapper />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
function InFrontOfTheCanvasWrapper() {
|
||||
const { InFrontOfTheCanvas } = useEditorComponents()
|
||||
if (!InFrontOfTheCanvas) return null
|
||||
return (
|
||||
<div className="tl-front">
|
||||
<InFrontOfTheCanvas />
|
||||
</div>
|
||||
)
|
||||
return <>{children}</>
|
||||
}
|
||||
|
||||
function Crash({ crashingError }: { crashingError: unknown }): null {
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import { ToastProvider } from '@radix-ui/react-toast'
|
||||
import { Expand, useEditor, useValue } from '@tldraw/editor'
|
||||
import { Expand, useEditor, useEditorComponents, useValue } from '@tldraw/editor'
|
||||
import classNames from 'classnames'
|
||||
import React, { ReactNode } from 'react'
|
||||
import { TLUiAssetUrlOverrides } from './assetUrls'
|
||||
|
@ -98,10 +97,21 @@ const TldrawUiInner = React.memo(function TldrawUiInner({
|
|||
<>
|
||||
{children}
|
||||
{hideUi ? null : <TldrawUiContent {...rest} />}
|
||||
<InFrontOfTheCanvasWrapper />
|
||||
</>
|
||||
)
|
||||
})
|
||||
|
||||
function InFrontOfTheCanvasWrapper() {
|
||||
const { InFrontOfTheCanvas } = useEditorComponents()
|
||||
if (!InFrontOfTheCanvas) return null
|
||||
return (
|
||||
<div className="tl-front">
|
||||
<InFrontOfTheCanvas />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const TldrawUiContent = React.memo(function TldrawUI() {
|
||||
const editor = useEditor()
|
||||
const msg = useTranslation()
|
||||
|
@ -129,54 +139,52 @@ const TldrawUiContent = React.memo(function TldrawUI() {
|
|||
const { 'toggle-focus-mode': toggleFocus } = useActions()
|
||||
|
||||
return (
|
||||
<ToastProvider>
|
||||
<div
|
||||
className={classNames('tlui-layout', {
|
||||
'tlui-layout__mobile': breakpoint < PORTRAIT_BREAKPOINT.TABLET_SM,
|
||||
})}
|
||||
data-breakpoint={breakpoint}
|
||||
>
|
||||
{isFocusMode ? (
|
||||
<div
|
||||
className={classNames('tlui-layout', {
|
||||
'tlui-layout__mobile': breakpoint < PORTRAIT_BREAKPOINT.TABLET_SM,
|
||||
})}
|
||||
data-breakpoint={breakpoint}
|
||||
>
|
||||
{isFocusMode ? (
|
||||
<div className="tlui-layout__top">
|
||||
<TldrawUiButton
|
||||
type="icon"
|
||||
className="tlui-focus-button"
|
||||
title={msg('focus-mode.toggle-focus-mode')}
|
||||
onClick={() => toggleFocus.onSelect('menu')}
|
||||
>
|
||||
<TldrawUiButtonIcon icon="dot" />
|
||||
</TldrawUiButton>
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<div className="tlui-layout__top">
|
||||
<TldrawUiButton
|
||||
type="icon"
|
||||
className="tlui-focus-button"
|
||||
title={msg('focus-mode.toggle-focus-mode')}
|
||||
onClick={() => toggleFocus.onSelect('menu')}
|
||||
>
|
||||
<TldrawUiButtonIcon icon="dot" />
|
||||
</TldrawUiButton>
|
||||
<div className="tlui-layout__top__left">
|
||||
{MenuPanel && <MenuPanel />}
|
||||
{HelperButtons && <HelperButtons />}
|
||||
</div>
|
||||
<div className="tlui-layout__top__center">{TopPanel && <TopPanel />}</div>
|
||||
<div className="tlui-layout__top__right">
|
||||
{SharePanel && <SharePanel />}
|
||||
{StylePanel && breakpoint >= PORTRAIT_BREAKPOINT.TABLET_SM && !isReadonlyMode && (
|
||||
<StylePanel />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<div className="tlui-layout__top">
|
||||
<div className="tlui-layout__top__left">
|
||||
{MenuPanel && <MenuPanel />}
|
||||
{HelperButtons && <HelperButtons />}
|
||||
</div>
|
||||
<div className="tlui-layout__top__center">{TopPanel && <TopPanel />}</div>
|
||||
<div className="tlui-layout__top__right">
|
||||
{SharePanel && <SharePanel />}
|
||||
{StylePanel && breakpoint >= PORTRAIT_BREAKPOINT.TABLET_SM && !isReadonlyMode && (
|
||||
<StylePanel />
|
||||
)}
|
||||
</div>
|
||||
<div className="tlui-layout__bottom">
|
||||
<div className="tlui-layout__bottom__main">
|
||||
{NavigationPanel && <NavigationPanel />}
|
||||
{Toolbar && <Toolbar />}
|
||||
{HelpMenu && <HelpMenu />}
|
||||
</div>
|
||||
<div className="tlui-layout__bottom">
|
||||
<div className="tlui-layout__bottom__main">
|
||||
{NavigationPanel && <NavigationPanel />}
|
||||
{Toolbar && <Toolbar />}
|
||||
{HelpMenu && <HelpMenu />}
|
||||
</div>
|
||||
{isDebugMode && DebugPanel && <DebugPanel />}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
<Toasts />
|
||||
<Dialogs />
|
||||
<ToastViewport />
|
||||
<FollowingIndicator />
|
||||
</div>
|
||||
</ToastProvider>
|
||||
{isDebugMode && DebugPanel && <DebugPanel />}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
<Toasts />
|
||||
<Dialogs />
|
||||
<ToastViewport />
|
||||
<FollowingIndicator />
|
||||
</div>
|
||||
)
|
||||
})
|
||||
|
|
|
@ -14,7 +14,7 @@ export interface TLUiIconProps extends React.HTMLProps<HTMLDivElement> {
|
|||
}
|
||||
|
||||
/** @public */
|
||||
export const TldrawUiIcon = memo(function TldrawUi({
|
||||
export const TldrawUiIcon = memo(function TldrawUiIcon({
|
||||
small,
|
||||
invertIcon,
|
||||
icon,
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { ToastProvider } from '@radix-ui/react-toast'
|
||||
import { Editor, uniqueId } from '@tldraw/editor'
|
||||
import { ReactNode, createContext, useCallback, useContext, useState } from 'react'
|
||||
import { TLUiIconType } from '../icon-types'
|
||||
|
@ -61,9 +62,11 @@ export function ToastsProvider({ children }: ToastsProviderProps) {
|
|||
}, [])
|
||||
|
||||
return (
|
||||
<ToastsContext.Provider value={{ toasts, addToast, removeToast, clearToasts }}>
|
||||
{children}
|
||||
</ToastsContext.Provider>
|
||||
<ToastProvider>
|
||||
<ToastsContext.Provider value={{ toasts, addToast, removeToast, clearToasts }}>
|
||||
{children}
|
||||
</ToastsContext.Provider>
|
||||
</ToastProvider>
|
||||
)
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue