diff --git a/tldraw/apps/tldraw-logseq/src/lib/shapes/LogseqPortalShape.tsx b/tldraw/apps/tldraw-logseq/src/lib/shapes/LogseqPortalShape.tsx index 4cfea38133..060e7b4f9f 100644 --- a/tldraw/apps/tldraw-logseq/src/lib/shapes/LogseqPortalShape.tsx +++ b/tldraw/apps/tldraw-logseq/src/lib/shapes/LogseqPortalShape.tsx @@ -567,7 +567,7 @@ export class LogseqPortalShape extends TLBoxShape { const { props: { pageId }, } = this - const { renderers, handlers } = React.useContext(LogseqContext) + const { renderers } = React.useContext(LogseqContext) const app = useApp() const cpRefContainer = React.useRef(null) @@ -602,26 +602,6 @@ export class LogseqPortalShape extends TLBoxShape { } }, [this.initialHeightCalculated]) - const blockBlob = React.useMemo(() => { - if (pageId && this.props.blockType === 'B') { - return handlers?.queryBlockByUUID(pageId) - } - }, [handlers?.queryBlockByUUID, pageId]) - - let element: React.ReactNode = null - - if (this.props.blockType === 'B') { - if (!blockBlob) { - element = `Target block not found` - } else if (this.props.compact) { - element = - } - } - - if (!element) { - element = - } - return (
{ overflow: this.props.compact ? 'visible' : 'auto', }} > - {element} + {this.props.blockType === 'B' && this.props.compact ? ( + + ) : ( + + )}
) }) @@ -642,7 +626,7 @@ export class LogseqPortalShape extends TLBoxShape { } = this const app = useApp() - const { renderers } = React.useContext(LogseqContext) + const { renderers, handlers } = React.useContext(LogseqContext) this.persist = () => app.persist() const isMoving = useCameraMovingRef() @@ -693,14 +677,22 @@ export class LogseqPortalShape extends TLBoxShape { app.history.persist() }, []) - const showingPortal = !this.props.collapsed || isEditing - const PortalComponent = this.PortalComponent const LogseqQuickSearch = this.LogseqQuickSearch + const blockContent = React.useMemo(() => { + if (pageId && this.props.blockType === 'B') { + return handlers?.queryBlockByUUID(pageId)?.content + } + }, [handlers?.queryBlockByUUID, pageId]) + + const targetNotFound = this.props.blockType === 'B' && !blockContent + const showingPortal = (!this.props.collapsed || isEditing) && !targetNotFound + if (!renderers?.Page) { return null // not being correctly configured } + const { Breadcrumb, PageNameLink } = renderers return ( @@ -738,7 +730,7 @@ export class LogseqPortalShape extends TLBoxShape { '--ls-title-text-color': !stroke?.startsWith('var') ? stroke : undefined, }} > - {!this.props.compact && ( + {!this.props.compact && !targetNotFound && ( {this.props.blockType === 'P' ? ( @@ -747,6 +739,7 @@ export class LogseqPortalShape extends TLBoxShape { )} )} + {targetNotFound &&
Target not found
} {showingPortal && } )} diff --git a/tldraw/apps/tldraw-logseq/src/styles.css b/tldraw/apps/tldraw-logseq/src/styles.css index ae944444db..e306237645 100644 --- a/tldraw/apps/tldraw-logseq/src/styles.css +++ b/tldraw/apps/tldraw-logseq/src/styles.css @@ -676,3 +676,11 @@ html[data-theme='dark'] .tl-logseq-portal-header { border-radius: 4px; box-shadow: 0 8px 12px 0 #85c8c81a, 0 4px 32px 0 #85c8c880; } + +.tl-target-not-found { + display: flex; + align-items: center; + justify-content: center; + height: 100%; + width: 100%; +} diff --git a/tldraw/demo/src/App.jsx b/tldraw/demo/src/App.jsx index 3920cfeecd..b5950c1164 100644 --- a/tldraw/demo/src/App.jsx +++ b/tldraw/demo/src/App.jsx @@ -152,6 +152,8 @@ export default function App() { handlers={{ search: searchHandler, addNewBlock: () => uniqueId(), + queryBlockByUUID: (uuid) => ({uuid, content: 'some random content'}), + isWhiteboardPage: () => false }} model={documentModel} onPersist={onPersist} diff --git a/tldraw/packages/core/src/lib/TLApp/TLApp.ts b/tldraw/packages/core/src/lib/TLApp/TLApp.ts index 2f4a78576a..4b41ae7f18 100644 --- a/tldraw/packages/core/src/lib/TLApp/TLApp.ts +++ b/tldraw/packages/core/src/lib/TLApp/TLApp.ts @@ -66,6 +66,32 @@ export class TLApp< if (Tools) this.registerTools(Tools) this.history.resume() if (serializedApp) this.history.deserialize(serializedApp) + this.api = new TLApi(this) + makeObservable(this) + this.notify('mount', null) + } + + keybindingRegistered = false + + static id = 'app' + static initial = 'select' + + readonly api: TLApi + readonly inputs = new TLInputs() + readonly cursors = new TLCursors() + readonly viewport = new TLViewport() + readonly settings = new TLSettings() + + dispose() { + super.dispose() + this.keybindingRegistered = false + return this + } + + initKeyboardShortcuts() { + if (this.keybindingRegistered) { + return + } const ownShortcuts: TLShortcut[] = [ { keys: 'mod+shift+g', @@ -165,20 +191,9 @@ export class TLApp< }) }) ) - this.api = new TLApi(this) - makeObservable(this) - this.notify('mount', null) + this.keybindingRegistered = true } - static id = 'app' - static initial = 'select' - - readonly api: TLApi - readonly inputs = new TLInputs() - readonly cursors = new TLCursors() - readonly viewport = new TLViewport() - readonly settings = new TLSettings() - /* --------------------- History -------------------- */ history = new TLHistory(this) diff --git a/tldraw/packages/core/src/lib/TLState.ts b/tldraw/packages/core/src/lib/TLState.ts index 47aa542a2f..de6f5ac5b2 100644 --- a/tldraw/packages/core/src/lib/TLState.ts +++ b/tldraw/packages/core/src/lib/TLState.ts @@ -53,6 +53,7 @@ export abstract class TLRootState dispose() { this._disposables.forEach(disposable => disposable()) + this._disposables = [] return this } diff --git a/tldraw/packages/core/src/utils/KeyUtils.ts b/tldraw/packages/core/src/utils/KeyUtils.ts index 1fa8121061..4f8db51fae 100644 --- a/tldraw/packages/core/src/utils/KeyUtils.ts +++ b/tldraw/packages/core/src/utils/KeyUtils.ts @@ -24,8 +24,9 @@ export class KeyUtils { } callback(keyboardEvent, combo) } - // todo: figure out why mod+a need to bind keypress instead of keydown - Mousetrap.bind(keys, fn, keys === 'mod+a' ? 'keypress' : 'keydown') - return () => Mousetrap.unbind(keys) + Mousetrap.bind(keys, fn, 'keydown') + return () => { + Mousetrap.unbind(keys) + } } } diff --git a/tldraw/packages/react/src/hooks/useAppSetup.ts b/tldraw/packages/react/src/hooks/useAppSetup.ts index 6e399560c3..5e19dc233a 100644 --- a/tldraw/packages/react/src/hooks/useAppSetup.ts +++ b/tldraw/packages/react/src/hooks/useAppSetup.ts @@ -7,5 +7,13 @@ export function useAppSetup = TL ): R { if ('app' in props) return props.app const [app] = React.useState(() => new TLReactApp(props.model, props.Shapes, props.Tools) as R) + + React.useLayoutEffect(() => { + app.initKeyboardShortcuts() + return () => { + app.dispose() + } + }, [app]) + return app } diff --git a/tldraw/packages/react/src/hooks/useSetup.ts b/tldraw/packages/react/src/hooks/useSetup.ts index 2ae1f22aab..da43f89adf 100644 --- a/tldraw/packages/react/src/hooks/useSetup.ts +++ b/tldraw/packages/react/src/hooks/useSetup.ts @@ -31,7 +31,6 @@ export function useSetup< if (onMount) onMount(app, null) return () => { unsubs.forEach(unsub => unsub()) - app.dispose() } }, [app])