diff --git a/packages/backend/src/Connection.ts b/packages/backend/src/Connection.ts index aa27f4e..0940434 100644 --- a/packages/backend/src/Connection.ts +++ b/packages/backend/src/Connection.ts @@ -118,6 +118,8 @@ class Connection { this.connections[id].receiveMsg(data) this.saveDoc(name) + + this.garbageCursors(name) } catch (e) { console.log(e) } diff --git a/packages/bridge/src/apply/annotation.ts b/packages/bridge/src/apply/annotation.ts index e58bb85..dd7326a 100644 --- a/packages/bridge/src/apply/annotation.ts +++ b/packages/bridge/src/apply/annotation.ts @@ -1,4 +1,4 @@ -import { Operation, SyncDoc } from '../model' +import { Operation, SyncDoc } from '../model/index' export const addAnnotation = (doc: SyncDoc, op: Operation): SyncDoc => { console.log('addAnnotation!!!', op.toJS()) diff --git a/packages/bridge/src/apply/index.ts b/packages/bridge/src/apply/index.ts index c7d366c..2679830 100644 --- a/packages/bridge/src/apply/index.ts +++ b/packages/bridge/src/apply/index.ts @@ -21,7 +21,10 @@ export const applyOperation = (doc: SyncDoc, op: Operation): SyncDoc => { try { const applyOp = opType[op.type] - if (!applyOp) throw new TypeError('Unsupported operation type!') + if (!applyOp) { + console.log('operation', op.toJS()) + throw new TypeError(`Unsupported operation type: ${op.type}!`) + } return applyOp(doc, op) } catch (e) { diff --git a/packages/bridge/src/convert/index.ts b/packages/bridge/src/convert/index.ts index f0bc7a3..782e14c 100644 --- a/packages/bridge/src/convert/index.ts +++ b/packages/bridge/src/convert/index.ts @@ -30,9 +30,7 @@ const toSlateOp = (ops: Automerge.Diff[], doc) => { [] ]) - const res = defer.flatMap(op => op(tempTree, doc)).filter(op => op) - - return res + return defer.flatMap(op => op(tempTree, doc)).filter(op => op) } export { toSlateOp } diff --git a/packages/bridge/src/cursor/index.ts b/packages/bridge/src/cursor/index.ts index 480891e..c8d7087 100644 --- a/packages/bridge/src/cursor/index.ts +++ b/packages/bridge/src/cursor/index.ts @@ -1,5 +1,5 @@ import { Operation, Selection } from 'slate' -import { List } from 'immutable' +import * as Immutable from 'immutable' import merge from 'lodash/merge' import { toJS } from '../utils' @@ -51,7 +51,7 @@ export const removeCursor = (doc: SyncDoc, key: CursorKey) => { return doc } -export const cursorOpFilter = (ops: List, type: string) => +export const cursorOpFilter = (ops: Immutable.List, type: string) => ops.filter(op => { if (op.type === 'set_annotation') { return !( diff --git a/packages/client/Cursor.tsx b/packages/client/Cursor.tsx deleted file mode 100644 index e69de29..0000000 diff --git a/packages/client/src/Cursor.tsx b/packages/client/src/Cursor.tsx new file mode 100644 index 0000000..3af7c45 --- /dev/null +++ b/packages/client/src/Cursor.tsx @@ -0,0 +1,47 @@ +import React, { Fragment } from 'react' + +const cursorStyleBase = { + position: 'absolute', + top: -2, + pointerEvents: 'none', + userSelect: 'none', + transform: 'translateY(-100%)', + fontSize: 10, + color: 'white', + background: 'palevioletred', + whiteSpace: 'nowrap' +} as any + +const caretStyleBase = { + position: 'absolute', + top: 0, + pointerEvents: 'none', + userSelect: 'none', + height: '100%', + width: 2, + background: 'palevioletred' +} as any + +const Cursor = ({ color, isBackward, name }) => { + const cursorStyles = { + ...cursorStyleBase, + background: color, + left: isBackward ? '0%' : '100%' + } + const caretStyles = { + ...caretStyleBase, + background: color, + left: isBackward ? '0%' : '100%' + } + + return ( + + + {name} + + + + ) +} + +export default Cursor diff --git a/packages/client/src/index.ts b/packages/client/src/index.tsx similarity index 70% rename from packages/client/src/index.ts rename to packages/client/src/index.tsx index 112ea77..0623a68 100644 --- a/packages/client/src/index.ts +++ b/packages/client/src/index.tsx @@ -2,23 +2,18 @@ import onChange from './onChange' import renderEditor from './renderEditor' import renderAnnotation from './renderAnnotation' +import renderCursor from './renderCursor' + import { PluginOptions } from './model' export const defaultOpts = { url: 'http://localhost:9000', cursorAnnotationType: 'collaborative_selection', + renderCursor, annotationDataMixin: { - name: 'an collaborator' - }, - renderCursor: data => data.name, - cursorStyle: { - background: 'palevioletred' - }, - caretStyle: { - background: 'palevioletred' - }, - selectionStyle: { - background: 'rgba(233, 30, 99, 0.2)' + name: 'an collaborator name', + color: 'palevioletred', + alphaColor: 'rgba(233, 30, 99, 0.2)' } } diff --git a/packages/client/src/model.ts b/packages/client/src/model.ts index 7edf145..ba98209 100644 --- a/packages/client/src/model.ts +++ b/packages/client/src/model.ts @@ -1,9 +1,12 @@ import { ReactNode } from 'react' -import CSS from 'csstype' import { Editor, Controller, Value } from 'slate' import Connection from './Connection' +type Data = { + [key: string]: any +} + interface FixedController extends Controller { setValue: (value: Value) => void } @@ -32,13 +35,9 @@ export interface PluginOptions { url?: string connectOpts?: SocketIOClient.ConnectOpts cursorAnnotationType?: string - caretStyle?: CSS.Properties - cursorStyle?: CSS.Properties + annotationDataMixin?: Data renderPreloader?: () => ReactNode - annotationDataMixin?: { - [key: string]: any - } - renderCursor?: (data: any) => ReactNode | string | any + renderCursor?: (data: Data) => ReactNode | any onConnect?: (connection: Connection) => void onDisconnect?: (connection: Connection) => void } diff --git a/packages/client/src/renderAnnotation.tsx b/packages/client/src/renderAnnotation.tsx index 5db7aa0..4114f0d 100644 --- a/packages/client/src/renderAnnotation.tsx +++ b/packages/client/src/renderAnnotation.tsx @@ -1,73 +1,28 @@ -import React, { Fragment } from 'react' +import React from 'react' -const wrapStyles = { - background: 'rgba(233, 30, 99, 0.2)', - position: 'relative' -} - -const cursorStyleBase = { - position: 'absolute', - top: -2, - pointerEvents: 'none', - userSelect: 'none', - transform: 'translateY(-100%)', - fontSize: 10, - color: 'white', - background: 'palevioletred', - whiteSpace: 'nowrap' -} as any - -const caretStyleBase = { - position: 'absolute', - top: 0, - pointerEvents: 'none', - userSelect: 'none', - height: '100%', - width: 2, - background: 'palevioletred' -} as any - -const renderAnnotation = ({ - cursorAnnotationType, - renderCursor, - cursorStyle = {}, - caretStyle = {}, - selectionStyle = {} -}) => (props, editor, next) => { +const renderAnnotation = ({ cursorAnnotationType, renderCursor }) => ( + props, + editor, + next +) => { const { children, annotation, attributes, node } = props if (annotation.type !== cursorAnnotationType) return next() - const isBackward = annotation.data.get('isBackward') - const targetPath = annotation.data.get('targetPath') - const cursorText = renderCursor(annotation.data) - - const cursorStyles = { - ...cursorStyleBase, - ...cursorStyle, - left: isBackward ? '0%' : '100%' - } - const caretStyles = { - ...caretStyleBase, - ...caretStyle, - left: isBackward ? '0%' : '100%' - } + const data = annotation.data.toJS() + const { targetPath, alphaColor } = data const { document } = editor.value const targetNode = document.getNode(targetPath) - const isShowCursor = targetNode && targetNode.key === node.key + const showCursor = targetNode && targetNode.key === node.key return ( - - {isShowCursor ? ( - - - {cursorText} - - - - ) : null} + + {showCursor ? renderCursor(data) : null} {children} ) diff --git a/packages/client/src/renderCursor.tsx b/packages/client/src/renderCursor.tsx new file mode 100644 index 0000000..d70c4f4 --- /dev/null +++ b/packages/client/src/renderCursor.tsx @@ -0,0 +1,7 @@ +import React from 'react' + +import Cursor from './Cursor' + +const renderCursor = data => + +export default renderCursor diff --git a/packages/example/package.json b/packages/example/package.json index 60f837d..5a05cd2 100644 --- a/packages/example/package.json +++ b/packages/example/package.json @@ -16,6 +16,7 @@ "concurrently": "^4.1.2", "faker": "^4.1.0", "lodash": "^4.17.15", + "nodemon": "^1.19.2", "randomcolor": "^0.5.4", "react": "^16.9.0", "react-dom": "^16.9.0", @@ -26,10 +27,9 @@ }, "scripts": { "start": "react-scripts start", + "build": "react-scripts build", "dev": "concurrently \"yarn start\" \"yarn serve\"", - "serve": "nodemon --watch ../backend/lib --inspect server.js", - "test": "react-scripts test", - "eject": "react-scripts eject" + "serve": "nodemon --watch ../backend/lib --inspect server.js" }, "eslintConfig": { "extends": "react-app" @@ -45,8 +45,5 @@ "last 1 firefox version", "last 1 safari version" ] - }, - "devDependencies": { - "nodemon": "^1.19.2" } } diff --git a/packages/example/src/App.tsx b/packages/example/src/App.tsx index c1fbd9f..64d00e1 100644 --- a/packages/example/src/App.tsx +++ b/packages/example/src/App.tsx @@ -19,9 +19,11 @@ class App extends Component<{}, { rooms: string[] }> { return ( - - Add Room - + + + Add Room + + {rooms.map(room => ( ))} @@ -46,6 +48,10 @@ export default App const Container = styled.div`` +const Panel = styled.div` + display: flex; +` + const Button = styled.button` padding: 6px 14px; display: block; diff --git a/packages/example/src/Client.tsx b/packages/example/src/Client.tsx index 6c40d9c..21eaea2 100644 --- a/packages/example/src/Client.tsx +++ b/packages/example/src/Client.tsx @@ -45,18 +45,10 @@ class Client extends Component { } }, annotationDataMixin: { - name: this.props.name + name: this.props.name, + color, + alphaColor: color.slice(0, -2) + '0.2)' }, - cursorStyle: { - background: color - }, - caretStyle: { - background: color - }, - selectionStyle: { - background: color.slice(0, -2) + '0.2)' - }, - renderCursor: data => data.get('name'), // renderPreloader: () =>
PRELOADER!!!!!!
, onConnect: this.onConnect, onDisconnect: this.onDisconnect