0.0.36 • Published 4 years ago

@wirelineio/editor v0.0.36

Weekly downloads
1
License
GPL-3.0
Repository
github
Last release
4 years ago

Editor

Helpers

YJS helpers to handle editor content.

getXmlFragmentContent(doc: Y.Doc) => XmlFragment

Get XmlFragment that holds document content.

getContentAsMarkdown(doc: Y.Doc) => string

Get document content as markdown string.

registerContentObserver(doc: Y.Doc, callback: function)

Add a listener (callback function) for content changes.

unregisterContentObserver(doc: Y.Doc, callback: function)

Remove callback function listener for content changes.

Channel

EventEmitter based channel for share/sync data.

Usage

import Channel from '@wirelineio/editor/Channel';

const contentChannel = new Channel();

contentChannel.on('local', data => {
  console.log(data);
});

contentChannel.on('remote', data => {
  console.log(data);
});

contentChannel.send({ some: 'local data' });
// Console: 'local data'

contentChannel.receive({ some: 'remote data' });
// Console: 'remote data'

Editor

Usage

import React, { Component } from 'react';
import * as Y from 'yjs';

import Editor from '@wirelineio/editor/Editor';
import Channel from '@wirelineio/editor/Channel';

import { withStyles } from '@material-ui/core/styles';

import { grey } from '@material-ui/core/colors';

import ListItemText from '@material-ui/core/ListItemText';

const style = () => ({
  contextMenuItemText: {
    fontSize: 12,
    padding: 0
  },

  contextMenuItemTextRight: {
    float: 'right',
    marginLeft: 5,
    color: grey[500],
    textTransform: 'Capitalize'
  }
});

class BasicEditor extends Component {
  render() {
    const {
      id,
      doc,
      contentChannel,
      statusChannel,
      onGetUsername,
      onContextMenuGetOptions,
      onContextMenuOptionSelect,
      onContextMenuRenderItem
    } = this.props;

    if (!doc) return 'Loading...';

    return (
      <Editor
        sync={{
          doc: doc,
          content: {
            channel: contentChannel
          },
          status: {
            id,
            getUsername: onGetUsername,
            channel: statusChannel
          }
        }}
        contextMenu={{
          getOptions: onContextMenuGetOptions,
          onSelect: onContextMenuOptionSelect,
          renderItem: onContextMenuRenderItem
        }}
        nodeViews={nodeViews}
        schemaEnhancers={schemaEnhancers}
        onViewCreated={onViewCreated}
      />
    );
  }
}

class BasicSync extends Component {
  state = {
    editors: undefined
  };

  componentDidMount() {
    const { editorsCount } = this.props;

    const editors = Array.from({ length: editorsCount }).reduce(
      (editors, _, idx) => {
        editors[idx] = this.createEditor(idx, `editor-${idx}`);
        return editors;
      },
      {}
    );

    this.setState({ editors });
  }

  createEditor = (id, username) => {
    const doc = new Y.Doc();
    const contentChannel = new Channel();
    const statusChannel = new Channel();

    contentChannel.on('local', data => {
      const { editors } = this.state;

      Object.values(editors)
        .filter(editor => editor.id !== id)
        .forEach(editor => {
          editor.contentChannel.receive({ ...data, author: editor.id });
        });
    });

    statusChannel.on('local', data => {
      const { editors } = this.state;

      Object.values(editors)
        .filter(editor => editor.id !== id)
        .forEach(editor => {
          editor.statusChannel.receive(data);
        });
    });

    return {
      id,
      username,
      doc,
      contentChannel,
      statusChannel
    };
  };

  handleGetUsername = editorId => id => {
    const { editors } = this.state;

    if (!id) return editors[editorId].username;

    return editors[id].username;
  };

  handleContextMenuGetOptions = () => {
    return [
      { id: 1, label: 'Insert some text' },
      { id: 2, label: 'Insert some text 2' }
    ];
  };

  handleContextMenuRenderItem = ({ option }) => {
    const { classes } = this.props;

    return (
      <ListItemText
        primary={<>{option.label}</>}
        className={classes.contextMenuItemText}
      />
    );
  };

  handleContextMenuOptionSelect = async (option, view) => {
    const { tr } = view.state;

    view.state.selection.replaceWith(tr, view.state.schema.text('-SOME TEXT-'));

    view.dispatch(tr);
  };

  render() {
    const { editors } = this.state;

    if (!editors) return 'Loading...';

    return Object.values(editors).map(editor => {
      return (
        <BasicEditor
          key={editor.id}
          onGetUsername={this.handleGetUsername(editor.id)}
          onContextMenuGetOptions={this.handleContextMenuGetOptions}
          onContextMenuOptionSelect={this.handleContextMenuOptionSelect}
          onContextMenuRenderItem={this.handleContextMenuRenderItem}
          {...editor}
        />
      );
    });
  }
}
1.0.0-beta.0

4 years ago

1.0.0-beta.1

4 years ago

0.0.36

4 years ago

0.0.35

4 years ago

0.0.34

4 years ago

0.0.33

4 years ago

0.0.32

4 years ago

0.0.30

4 years ago

0.0.31

4 years ago

0.0.29

4 years ago

0.0.28

4 years ago

0.0.27

4 years ago

0.0.26

4 years ago

0.0.25

4 years ago

0.0.24

4 years ago

0.0.23

4 years ago

0.0.22

4 years ago

0.0.21

4 years ago

0.0.20

4 years ago

0.0.19

4 years ago

0.0.18

4 years ago

0.0.16

4 years ago

0.0.15

4 years ago

0.0.14

4 years ago

0.0.13

4 years ago

0.0.10

4 years ago

0.0.9

4 years ago

0.0.8

4 years ago

0.0.7

4 years ago

0.0.6

4 years ago

0.0.5

4 years ago

0.0.4

4 years ago

0.0.3

4 years ago

0.0.2

4 years ago