Browse Source

Fix control by props, add control test example

main
Steve Ruiz 4 years ago
parent
commit
2aeb513342

+ 3
- 2
packages/dev/src/app.tsx View File

@@ -1,6 +1,7 @@
1 1
 import * as React from 'react'
2
-import Editor from './components/editor'
2
+import Controlled from './controlled'
3
+import Basic from './basic'
3 4
 
4 5
 export default function App(): JSX.Element {
5
-  return <Editor />
6
+  return <Controlled />
6 7
 }

+ 6
- 0
packages/dev/src/basic.tsx View File

@@ -0,0 +1,6 @@
1
+import * as React from 'react'
2
+import Editor from './components/editor'
3
+
4
+export default function BasicUsage(): JSX.Element {
5
+  return <Editor />
6
+}

+ 93
- 0
packages/dev/src/controlled.tsx View File

@@ -0,0 +1,93 @@
1
+import * as React from 'react'
2
+import {
3
+  TLDraw,
4
+  ColorStyle,
5
+  DashStyle,
6
+  SizeStyle,
7
+  TLDrawDocument,
8
+  TLDrawShapeType,
9
+} from '@tldraw/tldraw'
10
+
11
+export default function Controlled() {
12
+  const [doc, setDoc] = React.useState<TLDrawDocument>({
13
+    id: 'doc',
14
+    pages: {
15
+      page1: {
16
+        id: 'page1',
17
+        shapes: {
18
+          rect1: {
19
+            id: 'rect1',
20
+            type: TLDrawShapeType.Rectangle,
21
+            parentId: 'page1',
22
+            name: 'Rectangle',
23
+            childIndex: 1,
24
+            point: [100, 100],
25
+            size: [100, 100],
26
+            style: {
27
+              dash: DashStyle.Draw,
28
+              size: SizeStyle.Medium,
29
+              color: ColorStyle.Blue,
30
+            },
31
+          },
32
+          rect2: {
33
+            id: 'rect2',
34
+            parentId: 'page1',
35
+            name: 'Rectangle',
36
+            childIndex: 2,
37
+            type: TLDrawShapeType.Rectangle,
38
+            point: [150, 250],
39
+            size: [150, 150],
40
+            style: {
41
+              dash: DashStyle.Draw,
42
+              size: SizeStyle.Medium,
43
+              color: ColorStyle.Blue,
44
+            },
45
+          },
46
+        },
47
+        bindings: {},
48
+      },
49
+    },
50
+    pageStates: {
51
+      page1: {
52
+        id: 'page1',
53
+        selectedIds: ['rect1'],
54
+        camera: {
55
+          point: [0, 0],
56
+          zoom: 1,
57
+        },
58
+      },
59
+    },
60
+  })
61
+
62
+  React.useEffect(() => {
63
+    const timeout = setTimeout(
64
+      () =>
65
+        setDoc({
66
+          ...doc,
67
+          pages: {
68
+            ...doc.pages,
69
+            page1: {
70
+              ...doc.pages.page1,
71
+              shapes: {
72
+                ...doc.pages.page1.shapes,
73
+                rect2: {
74
+                  ...doc.pages.page1.shapes.rect2,
75
+                  style: {
76
+                    ...doc.pages.page1.shapes.rect2.style,
77
+                    color: ColorStyle.Orange,
78
+                  },
79
+                },
80
+              },
81
+            },
82
+          },
83
+        }),
84
+      1000
85
+    )
86
+
87
+    return () => {
88
+      clearTimeout(timeout)
89
+    }
90
+  }, [])
91
+
92
+  return <TLDraw document={doc} />
93
+}

+ 24
- 14
packages/tldraw/src/components/tldraw/tldraw.tsx View File

@@ -61,30 +61,26 @@ export function TLDraw({ id, document, currentPageId, onMount, onChange }: TLDra
61 61
     return { tlstate, useSelector: tlstate.useStore }
62 62
   })
63 63
 
64
-  React.useEffect(() => {
65
-    if (!document) return
66
-    tlstate.loadDocument(document)
67
-  }, [document, tlstate])
68
-
69
-  React.useEffect(() => {
70
-    if (!currentPageId) return
71
-    tlstate.changePage(currentPageId)
72
-  }, [currentPageId, tlstate])
73
-
74 64
   return (
75 65
     <TLDrawContext.Provider value={context}>
76 66
       <IdProvider>
77
-        <InnerTldraw />
67
+        <InnerTldraw currentPageId={currentPageId} document={document} />
78 68
       </IdProvider>
79 69
     </TLDrawContext.Provider>
80 70
   )
81 71
 }
82 72
 
83
-function InnerTldraw() {
84
-  useCustomFonts()
85
-
73
+function InnerTldraw({
74
+  currentPageId,
75
+  document,
76
+}: {
77
+  currentPageId?: string
78
+  document?: TLDrawDocument
79
+}) {
86 80
   const { tlstate, useSelector } = useTLDrawContext()
87 81
 
82
+  useCustomFonts()
83
+
88 84
   useKeyboardShortcuts()
89 85
 
90 86
   const page = useSelector(pageSelector)
@@ -128,6 +124,20 @@ function InnerTldraw() {
128 124
     return {}
129 125
   }, [isDarkMode])
130 126
 
127
+  React.useEffect(() => {
128
+    if (!document) return
129
+    if (document.id === tlstate.document.id) {
130
+      tlstate.updateDocument(document)
131
+    } else {
132
+      tlstate.loadDocument(document)
133
+    }
134
+  }, [document, tlstate])
135
+
136
+  React.useEffect(() => {
137
+    if (!currentPageId) return
138
+    tlstate.changePage(currentPageId)
139
+  }, [currentPageId, tlstate])
140
+
131 141
   return (
132 142
     <Layout>
133 143
       <ContextMenu>

+ 56
- 33
packages/tldraw/src/state/tlstate.ts View File

@@ -67,7 +67,7 @@ const defaultDocument: TLDrawDocument = {
67 67
   },
68 68
 }
69 69
 
70
-const initialData: Data = {
70
+const defaultState: Data = {
71 71
   settings: {
72 72
     isPenMode: false,
73 73
     isDarkMode: false,
@@ -120,11 +120,11 @@ export class TLDrawState extends StateManager<Data> {
120 120
   selectedGroupId?: string
121 121
 
122 122
   constructor(
123
-    id = Utils.uniqueId(),
123
+    id?: string,
124 124
     onChange?: (tlstate: TLDrawState, data: Data, reason: string) => void,
125 125
     onMount?: (tlstate: TLDrawState) => void
126 126
   ) {
127
-    super(initialData, id, 2, (prev, next, prevVersion) => {
127
+    super(defaultState, id, 2, (prev, next, prevVersion) => {
128 128
       const state = { ...prev }
129 129
       if (prevVersion === 1)
130 130
         state.settings = {
@@ -478,56 +478,79 @@ export class TLDrawState extends StateManager<Data> {
478 478
   }
479 479
 
480 480
   /**
481
-   * Load a new document.
482
-   * @param document The document to load
481
+   * Update the current document.
482
+   * @param document
483 483
    */
484
-  loadDocument = (document: TLDrawDocument): this => {
485
-    this.deselectAll()
486
-    this.resetHistory()
487
-    this.clearSelectHistory()
488
-    this.session = undefined
489
-    this.selectedGroupId = undefined
484
+  updateDocument = (document: TLDrawDocument, reason = 'updated_document'): this => {
485
+    console.log(reason)
486
+
487
+    const state = this.state
490 488
 
491
-    return this.replaceState(
489
+    const currentPageId = document.pages[this.currentPageId]
490
+      ? this.currentPageId
491
+      : Object.keys(document.pages)[0]
492
+
493
+    this.replaceState(
492 494
       {
493 495
         ...this.state,
494 496
         appState: {
495 497
           ...this.appState,
496
-          currentPageId: Object.keys(document.pages)[0],
498
+          currentPageId,
497 499
         },
498 500
         document: {
499 501
           ...document,
500 502
           pages: Object.fromEntries(
501 503
             Object.entries(document.pages)
502 504
               .sort((a, b) => (a[1].childIndex || 0) - (b[1].childIndex || 0))
503
-              .map(([id, page], i) => {
504
-                return [
505
-                  id,
506
-                  {
507
-                    ...page,
508
-                    name: page.name ? page.name : `Page ${i++}`,
509
-                  },
510
-                ]
505
+              .map(([pageId, page], i) => {
506
+                const nextPage = { ...page }
507
+                if (!nextPage.name) nextPage.name = `Page ${i + 1}`
508
+                return [pageId, nextPage]
511 509
               })
512 510
           ),
513 511
           pageStates: Object.fromEntries(
514
-            Object.entries(document.pageStates).map(([id, pageState]) => {
515
-              return [
516
-                id,
517
-                {
518
-                  ...pageState,
519
-                  bindingId: undefined,
520
-                  editingId: undefined,
521
-                  hoveredId: undefined,
522
-                  pointedId: undefined,
523
-                },
524
-              ]
512
+            Object.entries(document.pageStates).map(([pageId, pageState]) => {
513
+              const page = document.pages[pageId]
514
+              const nextPageState = { ...pageState }
515
+              const keysToCheck = ['bindingId', 'editingId', 'hoveredId', 'pointedId'] as const
516
+
517
+              for (const key of keysToCheck) {
518
+                if (!page.shapes[key]) {
519
+                  nextPageState[key] = undefined
520
+                }
521
+              }
522
+
523
+              nextPageState.selectedIds = pageState.selectedIds.filter(
524
+                (id) => !!document.pages[pageId].shapes[id]
525
+              )
526
+
527
+              return [pageId, nextPageState]
525 528
             })
526 529
           ),
527 530
         },
528 531
       },
529
-      `loaded_document:${document.id}`
532
+      `${reason}:${document.id}`
530 533
     )
534
+
535
+    console.log(
536
+      'did page change?',
537
+      this.state.document.pages['page1'] !== state.document.pages['page1']
538
+    )
539
+
540
+    return this
541
+  }
542
+
543
+  /**
544
+   * Load a new document.
545
+   * @param document The document to load
546
+   */
547
+  loadDocument = (document: TLDrawDocument): this => {
548
+    this.deselectAll()
549
+    this.resetHistory()
550
+    this.clearSelectHistory()
551
+    this.session = undefined
552
+    this.selectedGroupId = undefined
553
+    return this.updateDocument(document, 'loaded_document')
531 554
   }
532 555
 
533 556
   /**

Loading…
Cancel
Save