Fix control by props, add control test example
This commit is contained in:
parent
8c2c8d8c93
commit
2aeb513342
5 changed files with 193 additions and 60 deletions
|
@ -1,6 +1,7 @@
|
|||
import * as React from 'react'
|
||||
import Editor from './components/editor'
|
||||
import Controlled from './controlled'
|
||||
import Basic from './basic'
|
||||
|
||||
export default function App(): JSX.Element {
|
||||
return <Editor />
|
||||
return <Controlled />
|
||||
}
|
||||
|
|
6
packages/dev/src/basic.tsx
Normal file
6
packages/dev/src/basic.tsx
Normal file
|
@ -0,0 +1,6 @@
|
|||
import * as React from 'react'
|
||||
import Editor from './components/editor'
|
||||
|
||||
export default function BasicUsage(): JSX.Element {
|
||||
return <Editor />
|
||||
}
|
93
packages/dev/src/controlled.tsx
Normal file
93
packages/dev/src/controlled.tsx
Normal file
|
@ -0,0 +1,93 @@
|
|||
import * as React from 'react'
|
||||
import {
|
||||
TLDraw,
|
||||
ColorStyle,
|
||||
DashStyle,
|
||||
SizeStyle,
|
||||
TLDrawDocument,
|
||||
TLDrawShapeType,
|
||||
} from '@tldraw/tldraw'
|
||||
|
||||
export default function Controlled() {
|
||||
const [doc, setDoc] = React.useState<TLDrawDocument>({
|
||||
id: 'doc',
|
||||
pages: {
|
||||
page1: {
|
||||
id: 'page1',
|
||||
shapes: {
|
||||
rect1: {
|
||||
id: 'rect1',
|
||||
type: TLDrawShapeType.Rectangle,
|
||||
parentId: 'page1',
|
||||
name: 'Rectangle',
|
||||
childIndex: 1,
|
||||
point: [100, 100],
|
||||
size: [100, 100],
|
||||
style: {
|
||||
dash: DashStyle.Draw,
|
||||
size: SizeStyle.Medium,
|
||||
color: ColorStyle.Blue,
|
||||
},
|
||||
},
|
||||
rect2: {
|
||||
id: 'rect2',
|
||||
parentId: 'page1',
|
||||
name: 'Rectangle',
|
||||
childIndex: 2,
|
||||
type: TLDrawShapeType.Rectangle,
|
||||
point: [150, 250],
|
||||
size: [150, 150],
|
||||
style: {
|
||||
dash: DashStyle.Draw,
|
||||
size: SizeStyle.Medium,
|
||||
color: ColorStyle.Blue,
|
||||
},
|
||||
},
|
||||
},
|
||||
bindings: {},
|
||||
},
|
||||
},
|
||||
pageStates: {
|
||||
page1: {
|
||||
id: 'page1',
|
||||
selectedIds: ['rect1'],
|
||||
camera: {
|
||||
point: [0, 0],
|
||||
zoom: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
React.useEffect(() => {
|
||||
const timeout = setTimeout(
|
||||
() =>
|
||||
setDoc({
|
||||
...doc,
|
||||
pages: {
|
||||
...doc.pages,
|
||||
page1: {
|
||||
...doc.pages.page1,
|
||||
shapes: {
|
||||
...doc.pages.page1.shapes,
|
||||
rect2: {
|
||||
...doc.pages.page1.shapes.rect2,
|
||||
style: {
|
||||
...doc.pages.page1.shapes.rect2.style,
|
||||
color: ColorStyle.Orange,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
1000
|
||||
)
|
||||
|
||||
return () => {
|
||||
clearTimeout(timeout)
|
||||
}
|
||||
}, [])
|
||||
|
||||
return <TLDraw document={doc} />
|
||||
}
|
|
@ -61,30 +61,26 @@ export function TLDraw({ id, document, currentPageId, onMount, onChange }: TLDra
|
|||
return { tlstate, useSelector: tlstate.useStore }
|
||||
})
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!document) return
|
||||
tlstate.loadDocument(document)
|
||||
}, [document, tlstate])
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!currentPageId) return
|
||||
tlstate.changePage(currentPageId)
|
||||
}, [currentPageId, tlstate])
|
||||
|
||||
return (
|
||||
<TLDrawContext.Provider value={context}>
|
||||
<IdProvider>
|
||||
<InnerTldraw />
|
||||
<InnerTldraw currentPageId={currentPageId} document={document} />
|
||||
</IdProvider>
|
||||
</TLDrawContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
function InnerTldraw() {
|
||||
useCustomFonts()
|
||||
|
||||
function InnerTldraw({
|
||||
currentPageId,
|
||||
document,
|
||||
}: {
|
||||
currentPageId?: string
|
||||
document?: TLDrawDocument
|
||||
}) {
|
||||
const { tlstate, useSelector } = useTLDrawContext()
|
||||
|
||||
useCustomFonts()
|
||||
|
||||
useKeyboardShortcuts()
|
||||
|
||||
const page = useSelector(pageSelector)
|
||||
|
@ -128,6 +124,20 @@ function InnerTldraw() {
|
|||
return {}
|
||||
}, [isDarkMode])
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!document) return
|
||||
if (document.id === tlstate.document.id) {
|
||||
tlstate.updateDocument(document)
|
||||
} else {
|
||||
tlstate.loadDocument(document)
|
||||
}
|
||||
}, [document, tlstate])
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!currentPageId) return
|
||||
tlstate.changePage(currentPageId)
|
||||
}, [currentPageId, tlstate])
|
||||
|
||||
return (
|
||||
<Layout>
|
||||
<ContextMenu>
|
||||
|
|
|
@ -67,7 +67,7 @@ const defaultDocument: TLDrawDocument = {
|
|||
},
|
||||
}
|
||||
|
||||
const initialData: Data = {
|
||||
const defaultState: Data = {
|
||||
settings: {
|
||||
isPenMode: false,
|
||||
isDarkMode: false,
|
||||
|
@ -120,11 +120,11 @@ export class TLDrawState extends StateManager<Data> {
|
|||
selectedGroupId?: string
|
||||
|
||||
constructor(
|
||||
id = Utils.uniqueId(),
|
||||
id?: string,
|
||||
onChange?: (tlstate: TLDrawState, data: Data, reason: string) => void,
|
||||
onMount?: (tlstate: TLDrawState) => void
|
||||
) {
|
||||
super(initialData, id, 2, (prev, next, prevVersion) => {
|
||||
super(defaultState, id, 2, (prev, next, prevVersion) => {
|
||||
const state = { ...prev }
|
||||
if (prevVersion === 1)
|
||||
state.settings = {
|
||||
|
@ -477,6 +477,69 @@ export class TLDrawState extends StateManager<Data> {
|
|||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the current document.
|
||||
* @param document
|
||||
*/
|
||||
updateDocument = (document: TLDrawDocument, reason = 'updated_document'): this => {
|
||||
console.log(reason)
|
||||
|
||||
const state = this.state
|
||||
|
||||
const currentPageId = document.pages[this.currentPageId]
|
||||
? this.currentPageId
|
||||
: Object.keys(document.pages)[0]
|
||||
|
||||
this.replaceState(
|
||||
{
|
||||
...this.state,
|
||||
appState: {
|
||||
...this.appState,
|
||||
currentPageId,
|
||||
},
|
||||
document: {
|
||||
...document,
|
||||
pages: Object.fromEntries(
|
||||
Object.entries(document.pages)
|
||||
.sort((a, b) => (a[1].childIndex || 0) - (b[1].childIndex || 0))
|
||||
.map(([pageId, page], i) => {
|
||||
const nextPage = { ...page }
|
||||
if (!nextPage.name) nextPage.name = `Page ${i + 1}`
|
||||
return [pageId, nextPage]
|
||||
})
|
||||
),
|
||||
pageStates: Object.fromEntries(
|
||||
Object.entries(document.pageStates).map(([pageId, pageState]) => {
|
||||
const page = document.pages[pageId]
|
||||
const nextPageState = { ...pageState }
|
||||
const keysToCheck = ['bindingId', 'editingId', 'hoveredId', 'pointedId'] as const
|
||||
|
||||
for (const key of keysToCheck) {
|
||||
if (!page.shapes[key]) {
|
||||
nextPageState[key] = undefined
|
||||
}
|
||||
}
|
||||
|
||||
nextPageState.selectedIds = pageState.selectedIds.filter(
|
||||
(id) => !!document.pages[pageId].shapes[id]
|
||||
)
|
||||
|
||||
return [pageId, nextPageState]
|
||||
})
|
||||
),
|
||||
},
|
||||
},
|
||||
`${reason}:${document.id}`
|
||||
)
|
||||
|
||||
console.log(
|
||||
'did page change?',
|
||||
this.state.document.pages['page1'] !== state.document.pages['page1']
|
||||
)
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a new document.
|
||||
* @param document The document to load
|
||||
|
@ -487,47 +550,7 @@ export class TLDrawState extends StateManager<Data> {
|
|||
this.clearSelectHistory()
|
||||
this.session = undefined
|
||||
this.selectedGroupId = undefined
|
||||
|
||||
return this.replaceState(
|
||||
{
|
||||
...this.state,
|
||||
appState: {
|
||||
...this.appState,
|
||||
currentPageId: Object.keys(document.pages)[0],
|
||||
},
|
||||
document: {
|
||||
...document,
|
||||
pages: Object.fromEntries(
|
||||
Object.entries(document.pages)
|
||||
.sort((a, b) => (a[1].childIndex || 0) - (b[1].childIndex || 0))
|
||||
.map(([id, page], i) => {
|
||||
return [
|
||||
id,
|
||||
{
|
||||
...page,
|
||||
name: page.name ? page.name : `Page ${i++}`,
|
||||
},
|
||||
]
|
||||
})
|
||||
),
|
||||
pageStates: Object.fromEntries(
|
||||
Object.entries(document.pageStates).map(([id, pageState]) => {
|
||||
return [
|
||||
id,
|
||||
{
|
||||
...pageState,
|
||||
bindingId: undefined,
|
||||
editingId: undefined,
|
||||
hoveredId: undefined,
|
||||
pointedId: undefined,
|
||||
},
|
||||
]
|
||||
})
|
||||
),
|
||||
},
|
||||
},
|
||||
`loaded_document:${document.id}`
|
||||
)
|
||||
return this.updateDocument(document, 'loaded_document')
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in a new issue