@textbus/collaborate 2.0.0-beta.1 → 2.0.0-beta.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bundles/{collab/collaborate-cursor.d.ts → collaborate-cursor.d.ts} +10 -5
 - package/bundles/collaborate-cursor.js +260 -0
 - package/bundles/collaborate.d.ts +5 -5
 - package/bundles/collaborate.js +76 -43
 - package/bundles/public-api.d.ts +3 -1
 - package/bundles/public-api.js +15 -2
 - package/bundles/unknown.component.d.ts +1 -0
 - package/bundles/unknown.component.js +22 -0
 - package/package.json +6 -6
 - package/src/{collab/collaborate-cursor.ts → collaborate-cursor.ts} +71 -52
 - package/src/collaborate.ts +80 -52
 - package/src/public-api.ts +17 -1
 - package/src/unknown.component.ts +22 -0
 - package/bundles/collab/_api.d.ts +0 -1
 - package/bundles/collab/_api.js +0 -2
 - package/bundles/collab/collaborate-cursor.js +0 -245
 - package/src/collab/_api.ts +0 -1
 
| 
         @@ -1,7 +1,6 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            import { Inject, Injectable } from '@tanbo/di'
         
     | 
| 
      
 1 
     | 
    
         
            +
            import { Inject, Injectable, Optional } from '@tanbo/di'
         
     | 
| 
       2 
2 
     | 
    
         
             
            import {
         
     | 
| 
       3 
3 
     | 
    
         
             
              createElement,
         
     | 
| 
       4 
     | 
    
         
            -
              EDITABLE_DOCUMENT,
         
     | 
| 
       5 
4 
     | 
    
         
             
              EDITOR_CONTAINER,
         
     | 
| 
       6 
5 
     | 
    
         
             
              getLayoutRectByRange,
         
     | 
| 
       7 
6 
     | 
    
         
             
              SelectionBridge
         
     | 
| 
         @@ -15,21 +14,28 @@ export interface RemoteSelection { 
     | 
|
| 
       15 
14 
     | 
    
         
             
              paths: SelectionPaths
         
     | 
| 
       16 
15 
     | 
    
         
             
            }
         
     | 
| 
       17 
16 
     | 
    
         | 
| 
       18 
     | 
    
         
            -
            export interface  
     | 
| 
       19 
     | 
    
         
            -
              color: string
         
     | 
| 
       20 
     | 
    
         
            -
              username: string
         
     | 
| 
      
 17 
     | 
    
         
            +
            export interface Rect {
         
     | 
| 
       21 
18 
     | 
    
         
             
              x: number
         
     | 
| 
       22 
19 
     | 
    
         
             
              y: number
         
     | 
| 
       23 
20 
     | 
    
         
             
              width: number
         
     | 
| 
       24 
21 
     | 
    
         
             
              height: number
         
     | 
| 
       25 
22 
     | 
    
         
             
            }
         
     | 
| 
       26 
23 
     | 
    
         | 
| 
      
 24 
     | 
    
         
            +
            export interface SelectionRect extends Rect {
         
     | 
| 
      
 25 
     | 
    
         
            +
              color: string
         
     | 
| 
      
 26 
     | 
    
         
            +
              username: string
         
     | 
| 
      
 27 
     | 
    
         
            +
            }
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
       27 
29 
     | 
    
         
             
            export interface RemoteSelectionCursor {
         
     | 
| 
       28 
30 
     | 
    
         
             
              cursor: HTMLElement
         
     | 
| 
       29 
31 
     | 
    
         
             
              anchor: HTMLElement
         
     | 
| 
       30 
32 
     | 
    
         
             
              userTip: HTMLElement
         
     | 
| 
       31 
33 
     | 
    
         
             
            }
         
     | 
| 
       32 
34 
     | 
    
         | 
| 
      
 35 
     | 
    
         
            +
            export abstract class CollaborateCursorAwarenessDelegate {
         
     | 
| 
      
 36 
     | 
    
         
            +
              abstract getRects(selection: Selection, nativeRange: Range): false | Rect[]
         
     | 
| 
      
 37 
     | 
    
         
            +
            }
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
       33 
39 
     | 
    
         
             
            @Injectable()
         
     | 
| 
       34 
40 
     | 
    
         
             
            export class CollaborateCursor {
         
     | 
| 
       35 
41 
     | 
    
         
             
              private canvas = createElement('canvas', {
         
     | 
| 
         @@ -60,7 +66,7 @@ export class CollaborateCursor { 
     | 
|
| 
       60 
66 
     | 
    
         
             
              private onRectsChange = new Subject<SelectionRect[]>()
         
     | 
| 
       61 
67 
     | 
    
         | 
| 
       62 
68 
     | 
    
         
             
              constructor(@Inject(EDITOR_CONTAINER) private container: HTMLElement,
         
     | 
| 
       63 
     | 
    
         
            -
                          @ 
     | 
| 
      
 69 
     | 
    
         
            +
                          @Optional() private awarenessDelegate: CollaborateCursorAwarenessDelegate,
         
     | 
| 
       64 
70 
     | 
    
         
             
                          private nativeSelection: SelectionBridge,
         
     | 
| 
       65 
71 
     | 
    
         
             
                          private selection: Selection) {
         
     | 
| 
       66 
72 
     | 
    
         
             
                container.prepend(this.canvas, this.tooltips)
         
     | 
| 
         @@ -85,55 +91,68 @@ export class CollaborateCursor { 
     | 
|
| 
       85 
91 
     | 
    
         | 
| 
       86 
92 
     | 
    
         | 
| 
       87 
93 
     | 
    
         
             
                paths.filter(i => {
         
     | 
| 
       88 
     | 
    
         
            -
                  return i.paths. 
     | 
| 
      
 94 
     | 
    
         
            +
                  return i.paths.anchor.length && i.paths.focus.length
         
     | 
| 
       89 
95 
     | 
    
         
             
                }).forEach(item => {
         
     | 
| 
       90 
     | 
    
         
            -
                  const  
     | 
| 
       91 
     | 
    
         
            -
                  const  
     | 
| 
       92 
     | 
    
         
            -
                  const  
     | 
| 
       93 
     | 
    
         
            -
                  const  
     | 
| 
       94 
     | 
    
         
            -
             
     | 
| 
       95 
     | 
    
         
            -
             
     | 
| 
       96 
     | 
    
         
            -
             
     | 
| 
       97 
     | 
    
         
            -
             
     | 
| 
       98 
     | 
    
         
            -
             
     | 
| 
       99 
     | 
    
         
            -
             
     | 
| 
       100 
     | 
    
         
            -
             
     | 
| 
      
 96 
     | 
    
         
            +
                  const anchorOffset = item.paths.anchor.pop()!
         
     | 
| 
      
 97 
     | 
    
         
            +
                  const anchorSlot = this.selection.findSlotByPaths(item.paths.anchor)
         
     | 
| 
      
 98 
     | 
    
         
            +
                  const focusOffset = item.paths.focus.pop()!
         
     | 
| 
      
 99 
     | 
    
         
            +
                  const focusSlot = this.selection.findSlotByPaths(item.paths.focus)
         
     | 
| 
      
 100 
     | 
    
         
            +
                  if (!anchorSlot || !focusSlot) {
         
     | 
| 
      
 101 
     | 
    
         
            +
                    return
         
     | 
| 
      
 102 
     | 
    
         
            +
                  }
         
     | 
| 
      
 103 
     | 
    
         
            +
             
     | 
| 
      
 104 
     | 
    
         
            +
                  const {focus, anchor} = this.nativeSelection.getPositionByRange({
         
     | 
| 
      
 105 
     | 
    
         
            +
                    focusOffset,
         
     | 
| 
      
 106 
     | 
    
         
            +
                    anchorOffset,
         
     | 
| 
      
 107 
     | 
    
         
            +
                    focusSlot,
         
     | 
| 
      
 108 
     | 
    
         
            +
                    anchorSlot
         
     | 
| 
      
 109 
     | 
    
         
            +
                  })
         
     | 
| 
      
 110 
     | 
    
         
            +
                  if (!focus || !anchor) {
         
     | 
| 
      
 111 
     | 
    
         
            +
                    return
         
     | 
| 
      
 112 
     | 
    
         
            +
                  }
         
     | 
| 
      
 113 
     | 
    
         
            +
                  const nativeRange = document.createRange()
         
     | 
| 
      
 114 
     | 
    
         
            +
                  nativeRange.setStart(anchor.node, anchor.offset)
         
     | 
| 
      
 115 
     | 
    
         
            +
                  nativeRange.setEnd(focus.node, focus.offset)
         
     | 
| 
      
 116 
     | 
    
         
            +
                  if ((anchor.node !== focus.node || anchor.offset !== focus.offset) && nativeRange.collapsed) {
         
     | 
| 
      
 117 
     | 
    
         
            +
                    nativeRange.setStart(focus.node, focus.offset)
         
     | 
| 
      
 118 
     | 
    
         
            +
                    nativeRange.setEnd(anchor.node, anchor.offset)
         
     | 
| 
      
 119 
     | 
    
         
            +
                  }
         
     | 
| 
      
 120 
     | 
    
         
            +
             
     | 
| 
      
 121 
     | 
    
         
            +
                  let rects: Rect[] | DOMRectList | false = false
         
     | 
| 
      
 122 
     | 
    
         
            +
                  if (this.awarenessDelegate) {
         
     | 
| 
      
 123 
     | 
    
         
            +
                    rects = this.awarenessDelegate.getRects(this.selection, nativeRange)
         
     | 
| 
      
 124 
     | 
    
         
            +
                  }
         
     | 
| 
      
 125 
     | 
    
         
            +
                  if (!rects) {
         
     | 
| 
      
 126 
     | 
    
         
            +
                    rects = nativeRange.getClientRects()
         
     | 
| 
      
 127 
     | 
    
         
            +
                  }
         
     | 
| 
      
 128 
     | 
    
         
            +
                  const selectionRects: SelectionRect[] = []
         
     | 
| 
      
 129 
     | 
    
         
            +
                  for (let i = rects.length - 1; i >= 0; i--) {
         
     | 
| 
      
 130 
     | 
    
         
            +
                    const rect = rects[i]
         
     | 
| 
      
 131 
     | 
    
         
            +
                    selectionRects.push({
         
     | 
| 
      
 132 
     | 
    
         
            +
                      color: item.color,
         
     | 
| 
      
 133 
     | 
    
         
            +
                      username: item.username,
         
     | 
| 
      
 134 
     | 
    
         
            +
                      x: rect.x - containerRect.x,
         
     | 
| 
      
 135 
     | 
    
         
            +
                      y: rect.y - containerRect.y,
         
     | 
| 
      
 136 
     | 
    
         
            +
                      width: rect.width,
         
     | 
| 
      
 137 
     | 
    
         
            +
                      height: rect.height,
         
     | 
| 
       101 
138 
     | 
    
         
             
                    })
         
     | 
| 
       102 
     | 
    
         
            -
                    if (position.start && position.end) {
         
     | 
| 
       103 
     | 
    
         
            -
                      const nativeRange = this.document.createRange()
         
     | 
| 
       104 
     | 
    
         
            -
                      nativeRange.setStart(position.start.node, position.start.offset)
         
     | 
| 
       105 
     | 
    
         
            -
                      nativeRange.setEnd(position.end.node, position.end.offset)
         
     | 
| 
       106 
     | 
    
         
            -
             
     | 
| 
       107 
     | 
    
         
            -
                      const rects = nativeRange.getClientRects()
         
     | 
| 
       108 
     | 
    
         
            -
                      const selectionRects: SelectionRect[] = []
         
     | 
| 
       109 
     | 
    
         
            -
                      for (let i = rects.length - 1; i >= 0; i--) {
         
     | 
| 
       110 
     | 
    
         
            -
                        const rect = rects[i]
         
     | 
| 
       111 
     | 
    
         
            -
                        selectionRects.push({
         
     | 
| 
       112 
     | 
    
         
            -
                          color: item.color,
         
     | 
| 
       113 
     | 
    
         
            -
                          username: item.username,
         
     | 
| 
       114 
     | 
    
         
            -
                          x: rect.x - containerRect.x,
         
     | 
| 
       115 
     | 
    
         
            -
                          y: rect.y - containerRect.y,
         
     | 
| 
       116 
     | 
    
         
            -
                          width: rect.width,
         
     | 
| 
       117 
     | 
    
         
            -
                          height: rect.height,
         
     | 
| 
       118 
     | 
    
         
            -
                        })
         
     | 
| 
       119 
     | 
    
         
            -
                      }
         
     | 
| 
       120 
     | 
    
         
            -
                      this.onRectsChange.next(selectionRects)
         
     | 
| 
       121 
     | 
    
         
            -
             
     | 
| 
       122 
     | 
    
         
            -
                      const cursorRange = nativeRange.cloneRange()
         
     | 
| 
       123 
     | 
    
         
            -
                      cursorRange.collapse(!item.paths.focusEnd)
         
     | 
| 
       124 
     | 
    
         
            -
             
     | 
| 
       125 
     | 
    
         
            -
                      const cursorRect = getLayoutRectByRange(cursorRange)
         
     | 
| 
       126 
     | 
    
         
            -
             
     | 
| 
       127 
     | 
    
         
            -
                      users.push({
         
     | 
| 
       128 
     | 
    
         
            -
                        username: item.username,
         
     | 
| 
       129 
     | 
    
         
            -
                        color: item.color,
         
     | 
| 
       130 
     | 
    
         
            -
                        x: cursorRect.x - containerRect.x,
         
     | 
| 
       131 
     | 
    
         
            -
                        y: cursorRect.y - containerRect.y,
         
     | 
| 
       132 
     | 
    
         
            -
                        width: 2,
         
     | 
| 
       133 
     | 
    
         
            -
                        height: cursorRect.height
         
     | 
| 
       134 
     | 
    
         
            -
                      })
         
     | 
| 
       135 
     | 
    
         
            -
                    }
         
     | 
| 
       136 
139 
     | 
    
         
             
                  }
         
     | 
| 
      
 140 
     | 
    
         
            +
                  this.onRectsChange.next(selectionRects)
         
     | 
| 
      
 141 
     | 
    
         
            +
             
     | 
| 
      
 142 
     | 
    
         
            +
                  const cursorRange = nativeRange.cloneRange()
         
     | 
| 
      
 143 
     | 
    
         
            +
                  cursorRange.setStart(focus.node, focus.offset)
         
     | 
| 
      
 144 
     | 
    
         
            +
                  cursorRange.collapse(true)
         
     | 
| 
      
 145 
     | 
    
         
            +
             
     | 
| 
      
 146 
     | 
    
         
            +
                  const cursorRect = getLayoutRectByRange(cursorRange)
         
     | 
| 
      
 147 
     | 
    
         
            +
             
     | 
| 
      
 148 
     | 
    
         
            +
                  users.push({
         
     | 
| 
      
 149 
     | 
    
         
            +
                    username: item.username,
         
     | 
| 
      
 150 
     | 
    
         
            +
                    color: item.color,
         
     | 
| 
      
 151 
     | 
    
         
            +
                    x: cursorRect.x - containerRect.x,
         
     | 
| 
      
 152 
     | 
    
         
            +
                    y: cursorRect.y - containerRect.y,
         
     | 
| 
      
 153 
     | 
    
         
            +
                    width: 2,
         
     | 
| 
      
 154 
     | 
    
         
            +
                    height: cursorRect.height
         
     | 
| 
      
 155 
     | 
    
         
            +
                  })
         
     | 
| 
       137 
156 
     | 
    
         
             
                })
         
     | 
| 
       138 
157 
     | 
    
         
             
                this.drawUserCursor(users)
         
     | 
| 
       139 
158 
     | 
    
         
             
              }
         
     | 
    
        package/src/collaborate.ts
    CHANGED
    
    | 
         @@ -1,24 +1,24 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            import { Injectable } from '@tanbo/di'
         
     | 
| 
       2 
     | 
    
         
            -
            import {  
     | 
| 
      
 2 
     | 
    
         
            +
            import { Observable, Subject, Subscription } from '@tanbo/stream'
         
     | 
| 
       3 
3 
     | 
    
         
             
            import {
         
     | 
| 
       4 
     | 
    
         
            -
               
     | 
| 
       5 
     | 
    
         
            -
               
     | 
| 
       6 
     | 
    
         
            -
               
     | 
| 
      
 4 
     | 
    
         
            +
              ComponentInstance,
         
     | 
| 
      
 5 
     | 
    
         
            +
              ContentType,
         
     | 
| 
      
 6 
     | 
    
         
            +
              Formats,
         
     | 
| 
      
 7 
     | 
    
         
            +
              History,
         
     | 
| 
      
 8 
     | 
    
         
            +
              makeError,
         
     | 
| 
       7 
9 
     | 
    
         
             
              Registry,
         
     | 
| 
      
 10 
     | 
    
         
            +
              RootComponentRef,
         
     | 
| 
      
 11 
     | 
    
         
            +
              Scheduler,
         
     | 
| 
       8 
12 
     | 
    
         
             
              Selection,
         
     | 
| 
       9 
13 
     | 
    
         
             
              SelectionPaths,
         
     | 
| 
       10 
     | 
    
         
            -
               
     | 
| 
      
 14 
     | 
    
         
            +
              Slot,
         
     | 
| 
      
 15 
     | 
    
         
            +
              Starter,
         
     | 
| 
      
 16 
     | 
    
         
            +
              Translator
         
     | 
| 
       11 
17 
     | 
    
         
             
            } from '@textbus/core'
         
     | 
| 
       12 
     | 
    
         
            -
            import {
         
     | 
| 
       13 
     | 
    
         
            -
              Doc as YDoc,
         
     | 
| 
       14 
     | 
    
         
            -
              Map as YMap,
         
     | 
| 
       15 
     | 
    
         
            -
              Text as YText,
         
     | 
| 
       16 
     | 
    
         
            -
              Array as YArray,
         
     | 
| 
       17 
     | 
    
         
            -
              UndoManager,
         
     | 
| 
       18 
     | 
    
         
            -
              Transaction
         
     | 
| 
       19 
     | 
    
         
            -
            } from 'yjs'
         
     | 
| 
      
 18 
     | 
    
         
            +
            import { Array as YArray, Doc as YDoc, Map as YMap, Text as YText, Transaction, UndoManager } from 'yjs'
         
     | 
| 
       20 
19 
     | 
    
         | 
| 
       21 
     | 
    
         
            -
            import { CollaborateCursor, RemoteSelection } from './ 
     | 
| 
      
 20 
     | 
    
         
            +
            import { CollaborateCursor, RemoteSelection } from './collaborate-cursor'
         
     | 
| 
      
 21 
     | 
    
         
            +
            import { createUnknownComponent } from './unknown.component'
         
     | 
| 
       22 
22 
     | 
    
         | 
| 
       23 
23 
     | 
    
         
             
            const collaborateErrorFn = makeError('Collaborate')
         
     | 
| 
       24 
24 
     | 
    
         | 
| 
         @@ -60,8 +60,8 @@ export class Collaborate implements History { 
     | 
|
| 
       60 
60 
     | 
    
         | 
| 
       61 
61 
     | 
    
         
             
              constructor(private rootComponentRef: RootComponentRef,
         
     | 
| 
       62 
62 
     | 
    
         
             
                          private collaborateCursor: CollaborateCursor,
         
     | 
| 
      
 63 
     | 
    
         
            +
                          private scheduler: Scheduler,
         
     | 
| 
       63 
64 
     | 
    
         
             
                          private translator: Translator,
         
     | 
| 
       64 
     | 
    
         
            -
                          private renderer: Renderer,
         
     | 
| 
       65 
65 
     | 
    
         
             
                          private registry: Registry,
         
     | 
| 
       66 
66 
     | 
    
         
             
                          private selection: Selection,
         
     | 
| 
       67 
67 
     | 
    
         
             
                          private starter: Starter) {
         
     | 
| 
         @@ -74,9 +74,6 @@ export class Collaborate implements History { 
     | 
|
| 
       74 
74 
     | 
    
         | 
| 
       75 
75 
     | 
    
         
             
              setup() {
         
     | 
| 
       76 
76 
     | 
    
         
             
                this.subscriptions.push(
         
     | 
| 
       77 
     | 
    
         
            -
                  this.starter.onReady.subscribe(() => {
         
     | 
| 
       78 
     | 
    
         
            -
                    this.listen2()
         
     | 
| 
       79 
     | 
    
         
            -
                  }),
         
     | 
| 
       80 
77 
     | 
    
         
             
                  this.selection.onChange.subscribe(() => {
         
     | 
| 
       81 
78 
     | 
    
         
             
                    const paths = this.selection.getPaths()
         
     | 
| 
       82 
79 
     | 
    
         
             
                    this.selectionChangeEvent.next(paths)
         
     | 
| 
         @@ -89,18 +86,22 @@ export class Collaborate implements History { 
     | 
|
| 
       89 
86 
     | 
    
         
             
              }
         
     | 
| 
       90 
87 
     | 
    
         | 
| 
       91 
88 
     | 
    
         
             
              listen() {
         
     | 
| 
       92 
     | 
    
         
            -
                 
     | 
| 
      
 89 
     | 
    
         
            +
                this.syncRootComponent()
         
     | 
| 
       93 
90 
     | 
    
         
             
              }
         
     | 
| 
       94 
91 
     | 
    
         | 
| 
       95 
92 
     | 
    
         
             
              back() {
         
     | 
| 
       96 
93 
     | 
    
         
             
                if (this.canBack) {
         
     | 
| 
      
 94 
     | 
    
         
            +
                  this.scheduler.ignoreChanges = true
         
     | 
| 
       97 
95 
     | 
    
         
             
                  this.manager.undo()
         
     | 
| 
      
 96 
     | 
    
         
            +
                  this.scheduler.ignoreChanges = false
         
     | 
| 
       98 
97 
     | 
    
         
             
                }
         
     | 
| 
       99 
98 
     | 
    
         
             
              }
         
     | 
| 
       100 
99 
     | 
    
         | 
| 
       101 
100 
     | 
    
         
             
              forward() {
         
     | 
| 
       102 
101 
     | 
    
         
             
                if (this.canForward) {
         
     | 
| 
      
 102 
     | 
    
         
            +
                  this.scheduler.ignoreChanges = true
         
     | 
| 
       103 
103 
     | 
    
         
             
                  this.manager.redo()
         
     | 
| 
      
 104 
     | 
    
         
            +
                  this.scheduler.ignoreChanges = false
         
     | 
| 
       104 
105 
     | 
    
         
             
                }
         
     | 
| 
       105 
106 
     | 
    
         
             
              }
         
     | 
| 
       106 
107 
     | 
    
         | 
| 
         @@ -108,7 +109,7 @@ export class Collaborate implements History { 
     | 
|
| 
       108 
109 
     | 
    
         
             
                this.subscriptions.forEach(i => i.unsubscribe())
         
     | 
| 
       109 
110 
     | 
    
         
             
              }
         
     | 
| 
       110 
111 
     | 
    
         | 
| 
       111 
     | 
    
         
            -
              private  
     | 
| 
      
 112 
     | 
    
         
            +
              private syncRootComponent() {
         
     | 
| 
       112 
113 
     | 
    
         
             
                const root = this.yDoc.getText('content')
         
     | 
| 
       113 
114 
     | 
    
         
             
                const rootComponent = this.rootComponentRef.component!
         
     | 
| 
       114 
115 
     | 
    
         
             
                this.manager = new UndoManager(root, {
         
     | 
| 
         @@ -117,20 +118,13 @@ export class Collaborate implements History { 
     | 
|
| 
       117 
118 
     | 
    
         
             
                this.syncContent(root, rootComponent.slots.get(0)!)
         
     | 
| 
       118 
119 
     | 
    
         | 
| 
       119 
120 
     | 
    
         
             
                this.subscriptions.push(
         
     | 
| 
       120 
     | 
    
         
            -
                   
     | 
| 
       121 
     | 
    
         
            -
                    rootComponent.changeMarker.onForceChange,
         
     | 
| 
       122 
     | 
    
         
            -
                    rootComponent.changeMarker.onChange
         
     | 
| 
       123 
     | 
    
         
            -
                  ).pipe(
         
     | 
| 
       124 
     | 
    
         
            -
                    microTask()
         
     | 
| 
       125 
     | 
    
         
            -
                  ).subscribe(() => {
         
     | 
| 
      
 121 
     | 
    
         
            +
                  this.scheduler.onDocChange.subscribe(() => {
         
     | 
| 
       126 
122 
     | 
    
         
             
                    this.yDoc.transact(() => {
         
     | 
| 
       127 
123 
     | 
    
         
             
                      this.updateRemoteActions.forEach(fn => {
         
     | 
| 
       128 
124 
     | 
    
         
             
                        fn()
         
     | 
| 
       129 
125 
     | 
    
         
             
                      })
         
     | 
| 
       130 
126 
     | 
    
         
             
                      this.updateRemoteActions = []
         
     | 
| 
       131 
127 
     | 
    
         
             
                    }, this.yDoc)
         
     | 
| 
       132 
     | 
    
         
            -
                    this.renderer.render()
         
     | 
| 
       133 
     | 
    
         
            -
                    this.selection.restore()
         
     | 
| 
       134 
128 
     | 
    
         
             
                  })
         
     | 
| 
       135 
129 
     | 
    
         
             
                )
         
     | 
| 
       136 
130 
     | 
    
         
             
              }
         
     | 
| 
         @@ -141,7 +135,14 @@ export class Collaborate implements History { 
     | 
|
| 
       141 
135 
     | 
    
         
             
                    slot.retain(0)
         
     | 
| 
       142 
136 
     | 
    
         
             
                    ev.delta.forEach(action => {
         
     | 
| 
       143 
137 
     | 
    
         
             
                      if (Reflect.has(action, 'retain')) {
         
     | 
| 
       144 
     | 
    
         
            -
                         
     | 
| 
      
 138 
     | 
    
         
            +
                        if (action.attributes) {
         
     | 
| 
      
 139 
     | 
    
         
            +
                          const formats = makeFormats(this.registry, action.attributes)
         
     | 
| 
      
 140 
     | 
    
         
            +
                          if (formats.length) {
         
     | 
| 
      
 141 
     | 
    
         
            +
                            slot.retain(action.retain!, formats)
         
     | 
| 
      
 142 
     | 
    
         
            +
                          }
         
     | 
| 
      
 143 
     | 
    
         
            +
                        } else {
         
     | 
| 
      
 144 
     | 
    
         
            +
                          slot.retain(action.retain)
         
     | 
| 
      
 145 
     | 
    
         
            +
                        }
         
     | 
| 
       145 
146 
     | 
    
         
             
                      } else if (action.insert) {
         
     | 
| 
       146 
147 
     | 
    
         
             
                        const index = slot.index
         
     | 
| 
       147 
148 
     | 
    
         
             
                        let length = 1
         
     | 
| 
         @@ -150,17 +151,18 @@ export class Collaborate implements History { 
     | 
|
| 
       150 
151 
     | 
    
         
             
                          slot.insert(action.insert, makeFormats(this.registry, action.attributes))
         
     | 
| 
       151 
152 
     | 
    
         
             
                        } else {
         
     | 
| 
       152 
153 
     | 
    
         
             
                          const sharedComponent = action.insert as YMap<any>
         
     | 
| 
       153 
     | 
    
         
            -
                          const  
     | 
| 
      
 154 
     | 
    
         
            +
                          const canInsertInlineComponent = slot.schema.includes(ContentType.InlineComponent)
         
     | 
| 
      
 155 
     | 
    
         
            +
                          const component = this.createComponentBySharedComponent(sharedComponent, canInsertInlineComponent)
         
     | 
| 
       154 
156 
     | 
    
         
             
                          this.syncSlots(sharedComponent.get('slots'), component)
         
     | 
| 
       155 
157 
     | 
    
         
             
                          this.syncComponent(sharedComponent, component)
         
     | 
| 
       156 
158 
     | 
    
         
             
                          slot.insert(component)
         
     | 
| 
       157 
159 
     | 
    
         
             
                        }
         
     | 
| 
       158 
160 
     | 
    
         
             
                        if (this.selection.isSelected) {
         
     | 
| 
       159 
     | 
    
         
            -
                          if (slot === this.selection. 
     | 
| 
       160 
     | 
    
         
            -
                            this.selection. 
     | 
| 
      
 161 
     | 
    
         
            +
                          if (slot === this.selection.anchorSlot && this.selection.anchorOffset! > index) {
         
     | 
| 
      
 162 
     | 
    
         
            +
                            this.selection.setAnchor(slot, this.selection.anchorOffset! + length)
         
     | 
| 
       161 
163 
     | 
    
         
             
                          }
         
     | 
| 
       162 
     | 
    
         
            -
                          if (slot === this.selection. 
     | 
| 
       163 
     | 
    
         
            -
                            this.selection. 
     | 
| 
      
 164 
     | 
    
         
            +
                          if (slot === this.selection.focusSlot && this.selection.focusOffset! > index) {
         
     | 
| 
      
 165 
     | 
    
         
            +
                            this.selection.setFocus(slot, this.selection.focusOffset! + length)
         
     | 
| 
       164 
166 
     | 
    
         
             
                          }
         
     | 
| 
       165 
167 
     | 
    
         
             
                        }
         
     | 
| 
       166 
168 
     | 
    
         
             
                      } else if (action.delete) {
         
     | 
| 
         @@ -168,11 +170,11 @@ export class Collaborate implements History { 
     | 
|
| 
       168 
170 
     | 
    
         
             
                        slot.retain(slot.index)
         
     | 
| 
       169 
171 
     | 
    
         
             
                        slot.delete(action.delete)
         
     | 
| 
       170 
172 
     | 
    
         
             
                        if (this.selection.isSelected) {
         
     | 
| 
       171 
     | 
    
         
            -
                          if (slot === this.selection. 
     | 
| 
       172 
     | 
    
         
            -
                            this.selection. 
     | 
| 
      
 173 
     | 
    
         
            +
                          if (slot === this.selection.anchorSlot && this.selection.anchorOffset! >= index) {
         
     | 
| 
      
 174 
     | 
    
         
            +
                            this.selection.setAnchor(slot, this.selection.startOffset! - action.delete)
         
     | 
| 
       173 
175 
     | 
    
         
             
                          }
         
     | 
| 
       174 
     | 
    
         
            -
                          if (slot === this.selection. 
     | 
| 
       175 
     | 
    
         
            -
                            this.selection. 
     | 
| 
      
 176 
     | 
    
         
            +
                          if (slot === this.selection.focusSlot && this.selection.focusOffset! >= index) {
         
     | 
| 
      
 177 
     | 
    
         
            +
                            this.selection.setFocus(slot, this.selection.focusOffset! - action.delete)
         
     | 
| 
       176 
178 
     | 
    
         
             
                          }
         
     | 
| 
       177 
179 
     | 
    
         
             
                        }
         
     | 
| 
       178 
180 
     | 
    
         
             
                      } else if (action.attributes) {
         
     | 
| 
         @@ -191,8 +193,19 @@ export class Collaborate implements History { 
     | 
|
| 
       191 
193 
     | 
    
         
             
                    let length = 0
         
     | 
| 
       192 
194 
     | 
    
         
             
                    for (const action of actions) {
         
     | 
| 
       193 
195 
     | 
    
         
             
                      if (action.type === 'retain') {
         
     | 
| 
       194 
     | 
    
         
            -
                         
     | 
| 
       195 
     | 
    
         
            -
             
     | 
| 
      
 196 
     | 
    
         
            +
                        const formats = action.formats
         
     | 
| 
      
 197 
     | 
    
         
            +
                        if (formats) {
         
     | 
| 
      
 198 
     | 
    
         
            +
                          const keys = Object.keys(formats)
         
     | 
| 
      
 199 
     | 
    
         
            +
                          let length = keys.length
         
     | 
| 
      
 200 
     | 
    
         
            +
                          keys.forEach(key => {
         
     | 
| 
      
 201 
     | 
    
         
            +
                            if (!this.registry.getFormatter(key)) {
         
     | 
| 
      
 202 
     | 
    
         
            +
                              length--
         
     | 
| 
      
 203 
     | 
    
         
            +
                              Reflect.deleteProperty(formats, key)
         
     | 
| 
      
 204 
     | 
    
         
            +
                            }
         
     | 
| 
      
 205 
     | 
    
         
            +
                          })
         
     | 
| 
      
 206 
     | 
    
         
            +
                          if (length) {
         
     | 
| 
      
 207 
     | 
    
         
            +
                            content.format(offset, action.offset, formats)
         
     | 
| 
      
 208 
     | 
    
         
            +
                          }
         
     | 
| 
       196 
209 
     | 
    
         
             
                        } else {
         
     | 
| 
       197 
210 
     | 
    
         
             
                          offset = action.offset
         
     | 
| 
       198 
211 
     | 
    
         
             
                        }
         
     | 
| 
         @@ -201,16 +214,14 @@ export class Collaborate implements History { 
     | 
|
| 
       201 
214 
     | 
    
         
             
                        const isEmpty = delta.length === 1 && delta[0].insert === Slot.emptyPlaceholder
         
     | 
| 
       202 
215 
     | 
    
         
             
                        if (typeof action.content === 'string') {
         
     | 
| 
       203 
216 
     | 
    
         
             
                          length = action.content.length
         
     | 
| 
       204 
     | 
    
         
            -
                          content.insert(offset, action.content)
         
     | 
| 
      
 217 
     | 
    
         
            +
                          content.insert(offset, action.content, action.formats || {})
         
     | 
| 
       205 
218 
     | 
    
         
             
                        } else {
         
     | 
| 
       206 
219 
     | 
    
         
             
                          length = 1
         
     | 
| 
       207 
220 
     | 
    
         
             
                          const component = slot.getContentAtIndex(offset) as ComponentInstance
         
     | 
| 
       208 
221 
     | 
    
         
             
                          const sharedComponent = this.createSharedComponentByComponent(component)
         
     | 
| 
       209 
222 
     | 
    
         
             
                          content.insertEmbed(offset, sharedComponent)
         
     | 
| 
       210 
223 
     | 
    
         
             
                        }
         
     | 
| 
       211 
     | 
    
         
            -
             
     | 
| 
       212 
     | 
    
         
            -
                          content.format(offset, length, action.formats)
         
     | 
| 
       213 
     | 
    
         
            -
                        }
         
     | 
| 
      
 224 
     | 
    
         
            +
             
     | 
| 
       214 
225 
     | 
    
         
             
                        if (isEmpty && offset === 0) {
         
     | 
| 
       215 
226 
     | 
    
         
             
                          content.delete(content.length - 1, 1)
         
     | 
| 
       216 
227 
     | 
    
         
             
                        }
         
     | 
| 
         @@ -225,6 +236,12 @@ export class Collaborate implements History { 
     | 
|
| 
       225 
236 
     | 
    
         
             
                    }
         
     | 
| 
       226 
237 
     | 
    
         
             
                  })
         
     | 
| 
       227 
238 
     | 
    
         
             
                })
         
     | 
| 
      
 239 
     | 
    
         
            +
             
     | 
| 
      
 240 
     | 
    
         
            +
                sub.add(slot.onChildComponentRemove.subscribe(components => {
         
     | 
| 
      
 241 
     | 
    
         
            +
                  components.forEach(c => {
         
     | 
| 
      
 242 
     | 
    
         
            +
                    this.cleanSubscriptionsByComponent(c)
         
     | 
| 
      
 243 
     | 
    
         
            +
                  })
         
     | 
| 
      
 244 
     | 
    
         
            +
                }))
         
     | 
| 
       228 
245 
     | 
    
         
             
                this.contentSyncCaches.set(slot, () => {
         
     | 
| 
       229 
246 
     | 
    
         
             
                  content.unobserve(syncRemote)
         
     | 
| 
       230 
247 
     | 
    
         
             
                  sub.unsubscribe()
         
     | 
| 
         @@ -263,18 +280,21 @@ export class Collaborate implements History { 
     | 
|
| 
       263 
280 
     | 
    
         
             
                const slots = component.slots
         
     | 
| 
       264 
281 
     | 
    
         
             
                const syncRemote = (ev, tr) => {
         
     | 
| 
       265 
282 
     | 
    
         
             
                  this.runRemoteUpdate(tr, () => {
         
     | 
| 
      
 283 
     | 
    
         
            +
                    let index = 0
         
     | 
| 
       266 
284 
     | 
    
         
             
                    ev.delta.forEach(action => {
         
     | 
| 
       267 
285 
     | 
    
         
             
                      if (Reflect.has(action, 'retain')) {
         
     | 
| 
       268 
286 
     | 
    
         
             
                        slots.retain(action.retain!)
         
     | 
| 
      
 287 
     | 
    
         
            +
                        index += action.retain
         
     | 
| 
       269 
288 
     | 
    
         
             
                      } else if (action.insert) {
         
     | 
| 
       270 
289 
     | 
    
         
             
                        (action.insert as Array<YMap<any>>).forEach(item => {
         
     | 
| 
       271 
290 
     | 
    
         
             
                          const slot = this.createSlotBySharedSlot(item)
         
     | 
| 
       272 
291 
     | 
    
         
             
                          slots.insert(slot)
         
     | 
| 
       273 
292 
     | 
    
         
             
                          this.syncContent(item.get('content'), slot)
         
     | 
| 
       274 
293 
     | 
    
         
             
                          this.syncSlot(item, slot)
         
     | 
| 
      
 294 
     | 
    
         
            +
                          index++
         
     | 
| 
       275 
295 
     | 
    
         
             
                        })
         
     | 
| 
       276 
296 
     | 
    
         
             
                      } else if (action.delete) {
         
     | 
| 
       277 
     | 
    
         
            -
                        slots.retain( 
     | 
| 
      
 297 
     | 
    
         
            +
                        slots.retain(index)
         
     | 
| 
       278 
298 
     | 
    
         
             
                        slots.delete(action.delete)
         
     | 
| 
       279 
299 
     | 
    
         
             
                      }
         
     | 
| 
       280 
300 
     | 
    
         
             
                    })
         
     | 
| 
         @@ -295,15 +315,18 @@ export class Collaborate implements History { 
     | 
|
| 
       295 
315 
     | 
    
         
             
                        remoteSlots.insert(index, [sharedSlot])
         
     | 
| 
       296 
316 
     | 
    
         
             
                        index++
         
     | 
| 
       297 
317 
     | 
    
         
             
                      } else if (action.type === 'delete') {
         
     | 
| 
       298 
     | 
    
         
            -
                        slots.slice(index, index + action.count).forEach(slot => {
         
     | 
| 
       299 
     | 
    
         
            -
                          this.cleanSubscriptionsBySlot(slot)
         
     | 
| 
       300 
     | 
    
         
            -
                        })
         
     | 
| 
       301 
318 
     | 
    
         
             
                        remoteSlots.delete(index, action.count)
         
     | 
| 
       302 
319 
     | 
    
         
             
                      }
         
     | 
| 
       303 
320 
     | 
    
         
             
                    })
         
     | 
| 
       304 
321 
     | 
    
         
             
                  })
         
     | 
| 
       305 
322 
     | 
    
         
             
                })
         
     | 
| 
       306 
323 
     | 
    
         | 
| 
      
 324 
     | 
    
         
            +
                sub.add(slots.onChildSlotRemove.subscribe(slots => {
         
     | 
| 
      
 325 
     | 
    
         
            +
                  slots.forEach(slot => {
         
     | 
| 
      
 326 
     | 
    
         
            +
                    this.cleanSubscriptionsBySlot(slot)
         
     | 
| 
      
 327 
     | 
    
         
            +
                  })
         
     | 
| 
      
 328 
     | 
    
         
            +
                }))
         
     | 
| 
      
 329 
     | 
    
         
            +
             
     | 
| 
       307 
330 
     | 
    
         
             
                this.slotsSyncCaches.set(component, () => {
         
     | 
| 
       308 
331 
     | 
    
         
             
                  remoteSlots.unobserve(syncRemote)
         
     | 
| 
       309 
332 
     | 
    
         
             
                  sub.unsubscribe()
         
     | 
| 
         @@ -396,7 +419,7 @@ export class Collaborate implements History { 
     | 
|
| 
       396 
419 
     | 
    
         
             
                return sharedSlot
         
     | 
| 
       397 
420 
     | 
    
         
             
              }
         
     | 
| 
       398 
421 
     | 
    
         | 
| 
       399 
     | 
    
         
            -
              private createComponentBySharedComponent(yMap: YMap<any 
     | 
| 
      
 422 
     | 
    
         
            +
              private createComponentBySharedComponent(yMap: YMap<any>, canInsertInlineComponent: boolean): ComponentInstance {
         
     | 
| 
       400 
423 
     | 
    
         
             
                const sharedSlots = yMap.get('slots') as YArray<YMap<any>>
         
     | 
| 
       401 
424 
     | 
    
         
             
                const slots: Slot[] = []
         
     | 
| 
       402 
425 
     | 
    
         
             
                sharedSlots.forEach(sharedSlot => {
         
     | 
| 
         @@ -410,13 +433,17 @@ export class Collaborate implements History { 
     | 
|
| 
       410 
433 
     | 
    
         
             
                })
         
     | 
| 
       411 
434 
     | 
    
         
             
                if (instance) {
         
     | 
| 
       412 
435 
     | 
    
         
             
                  instance.slots.toArray().forEach((slot, index) => {
         
     | 
| 
       413 
     | 
    
         
            -
                     
     | 
| 
      
 436 
     | 
    
         
            +
                    let sharedSlot = sharedSlots.get(index)
         
     | 
| 
      
 437 
     | 
    
         
            +
                    if (!sharedSlot) {
         
     | 
| 
      
 438 
     | 
    
         
            +
                      sharedSlot = this.createSharedSlotBySlot(slot)
         
     | 
| 
      
 439 
     | 
    
         
            +
                      sharedSlots.push([sharedSlot])
         
     | 
| 
      
 440 
     | 
    
         
            +
                    }
         
     | 
| 
       414 
441 
     | 
    
         
             
                    this.syncSlot(sharedSlot, slot)
         
     | 
| 
       415 
442 
     | 
    
         
             
                    this.syncContent(sharedSlot.get('content'), slot)
         
     | 
| 
       416 
443 
     | 
    
         
             
                  })
         
     | 
| 
       417 
444 
     | 
    
         
             
                  return instance
         
     | 
| 
       418 
445 
     | 
    
         
             
                }
         
     | 
| 
       419 
     | 
    
         
            -
                 
     | 
| 
      
 446 
     | 
    
         
            +
                return createUnknownComponent(name, canInsertInlineComponent).createInstance(this.starter)
         
     | 
| 
       420 
447 
     | 
    
         
             
              }
         
     | 
| 
       421 
448 
     | 
    
         | 
| 
       422 
449 
     | 
    
         
             
              private createSlotBySharedSlot(sharedSlot: YMap<any>): Slot {
         
     | 
| 
         @@ -436,7 +463,8 @@ export class Collaborate implements History { 
     | 
|
| 
       436 
463 
     | 
    
         
             
                      slot.insert(action.insert, makeFormats(this.registry, action.attributes))
         
     | 
| 
       437 
464 
     | 
    
         
             
                    } else {
         
     | 
| 
       438 
465 
     | 
    
         
             
                      const sharedComponent = action.insert as YMap<any>
         
     | 
| 
       439 
     | 
    
         
            -
                      const  
     | 
| 
      
 466 
     | 
    
         
            +
                      const canInsertInlineComponent = slot.schema.includes(ContentType.InlineComponent)
         
     | 
| 
      
 467 
     | 
    
         
            +
                      const component = this.createComponentBySharedComponent(sharedComponent, canInsertInlineComponent)
         
     | 
| 
       440 
468 
     | 
    
         
             
                      slot.insert(component)
         
     | 
| 
       441 
469 
     | 
    
         
             
                      this.syncSlots(sharedComponent.get('slots'), component)
         
     | 
| 
       442 
470 
     | 
    
         
             
                      this.syncComponent(sharedComponent, component)
         
     | 
    
        package/src/public-api.ts
    CHANGED
    
    | 
         @@ -1,2 +1,18 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
             
     | 
| 
      
 1 
     | 
    
         
            +
            import { History, Module } from '@textbus/core'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            import { Collaborate } from './collaborate'
         
     | 
| 
      
 4 
     | 
    
         
            +
            import { CollaborateCursor } from './collaborate-cursor'
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
       2 
6 
     | 
    
         
             
            export * from './collaborate'
         
     | 
| 
      
 7 
     | 
    
         
            +
            export * from './collaborate-cursor'
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            export const collaborateModule: Module = {
         
     | 
| 
      
 10 
     | 
    
         
            +
              providers: [
         
     | 
| 
      
 11 
     | 
    
         
            +
                Collaborate,
         
     | 
| 
      
 12 
     | 
    
         
            +
                CollaborateCursor,
         
     | 
| 
      
 13 
     | 
    
         
            +
                {
         
     | 
| 
      
 14 
     | 
    
         
            +
                  provide: History,
         
     | 
| 
      
 15 
     | 
    
         
            +
                  useClass: Collaborate
         
     | 
| 
      
 16 
     | 
    
         
            +
                }
         
     | 
| 
      
 17 
     | 
    
         
            +
              ]
         
     | 
| 
      
 18 
     | 
    
         
            +
            }
         
     | 
| 
         @@ -0,0 +1,22 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            import { ContentType, defineComponent, VElement } from '@textbus/core'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            export function createUnknownComponent(factoryName: string, canInsertInlineComponent: boolean) {
         
     | 
| 
      
 4 
     | 
    
         
            +
              const unknownComponent = defineComponent({
         
     | 
| 
      
 5 
     | 
    
         
            +
                type: canInsertInlineComponent ? ContentType.InlineComponent : ContentType.BlockComponent,
         
     | 
| 
      
 6 
     | 
    
         
            +
                name: 'UnknownComponent',
         
     | 
| 
      
 7 
     | 
    
         
            +
                setup() {
         
     | 
| 
      
 8 
     | 
    
         
            +
                  console.error(`cannot find component factory \`${factoryName}\`.`)
         
     | 
| 
      
 9 
     | 
    
         
            +
                  return {
         
     | 
| 
      
 10 
     | 
    
         
            +
                    render() {
         
     | 
| 
      
 11 
     | 
    
         
            +
                      return VElement.createElement('textbus-unknown-component', {
         
     | 
| 
      
 12 
     | 
    
         
            +
                        style: {
         
     | 
| 
      
 13 
     | 
    
         
            +
                          display: canInsertInlineComponent ? 'inline' : 'block',
         
     | 
| 
      
 14 
     | 
    
         
            +
                          color: '#f00'
         
     | 
| 
      
 15 
     | 
    
         
            +
                        }
         
     | 
| 
      
 16 
     | 
    
         
            +
                      }, unknownComponent.name)
         
     | 
| 
      
 17 
     | 
    
         
            +
                    }
         
     | 
| 
      
 18 
     | 
    
         
            +
                  }
         
     | 
| 
      
 19 
     | 
    
         
            +
                }
         
     | 
| 
      
 20 
     | 
    
         
            +
              })
         
     | 
| 
      
 21 
     | 
    
         
            +
              return unknownComponent
         
     | 
| 
      
 22 
     | 
    
         
            +
            }
         
     | 
    
        package/bundles/collab/_api.d.ts
    DELETED
    
    | 
         @@ -1 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            export * from './collaborate-cursor';
         
     | 
    
        package/bundles/collab/_api.js
    DELETED
    
    | 
         @@ -1,2 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            export * from './collaborate-cursor';
         
     | 
| 
       2 
     | 
    
         
            -
            //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiX2FwaS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9jb2xsYWIvX2FwaS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxjQUFjLHNCQUFzQixDQUFBIiwic291cmNlc0NvbnRlbnQiOlsiZXhwb3J0ICogZnJvbSAnLi9jb2xsYWJvcmF0ZS1jdXJzb3InXG4iXX0=
         
     |