question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Create a showcase for a controlled editor

See original GitHub issue

Description

I mentioned in https://github.com/ifiokjr/remirror/issues/23 that I was attempting to try my hand at creating a controlled editor, and looking for guidance from the documentation. I’m going to post my code below to see if this is either helpful for people on a similar path to me, and also see if anyone who has been down this path can help.

My usecase is that I’d like the user to be able to click a button outside of the editor, and the editor to respond with an updated value. Essentially, an HTML string should be turned into a state object for prose mirror.

Blocker

This code is a work in progress, and is not yet functional.

I am getting this error:

Uncaught TypeError: _this.state.newState.applyTransaction is not a function
    at EditorView.<anonymous> (react.esm.js:608)
    at EditorView.dispatch (index.js:4637)
    at readDOMChange (index.js:2576)
    at DOMObserver.handleDOMChange (index.js:3013)
    at DOMObserver.flush (index.js:2959)
    at MutationObserver.DOMObserver.observer (index.js:2874)

Proposed

I’ve based this code off of the markdown/wysiwg editor showcase.

import { logger } from '@myOrg/utils';
import {
  createDocumentNode,
  EditorState,
  ProsemirrorNode,
} from '@remirror/core';
import { BoldExtension, LinkExtension } from '@remirror/core-extensions';
import {
  ManagedRemirrorProvider,
  RemirrorExtension,
  RemirrorManager,
  RemirrorManagerProps,
  RemirrorProviderProps,
  useRemirrorManager,
} from '@remirror/react';
import React, { FC, ReactElement, useEffect } from 'react';
import { useSetState } from 'react-hanger';
import { MirrorEditorInner } from './MirrorEditorInner';

export type InternalEditorProps = Omit<
  RemirrorProviderProps,
  'childAsRoot' | 'children'
>;

interface IMirrorEditorProps {
  value: string;
  onChange: (val: string) => void;
  disabled?: boolean;
}

const defaultPlaceholder: RemirrorManagerProps['placeholder'] = [
  'Start typing...',
  {
    color: '#aaa',
    fontStyle: 'normal',
    fontWeight: 300,
    letterSpacing: '0.5px',
    position: 'absolute',
  },
];

interface IMirrorEditorProviderProps extends IMirrorEditorProps {
  children: ReactElement;
}

const MirrorEditorProvider: React.FC<IMirrorEditorProviderProps> = ({
  children,
  value,
  disabled,
  onChange,
  ...props
}) => {
  const { schema } = useRemirrorManager();
  const initalContent = createDocumentNode({ content: value, schema });
  const raw = useSetState<ProsemirrorNode>(initalContent);
  const editor = useSetState<EditorState<any>>(null);

  useEffect(() => {
    editor.setState({
      ...editor.state,
      doc: createDocumentNode({ content: value, schema }),
    });
  }, [value]);

  return (
    <>
      <ManagedRemirrorProvider
        onStateChange={({ newState, getText }) => {
          logger.info('onStateChange', { text: getText() });
          editor.setState(newState);
          raw.setState(newState.doc);
          onChange(getText());
        }}
        value={editor.state}
        initialContent={raw.state}
        withoutEmotion
        editable={!disabled}
      >
        {children}
      </ManagedRemirrorProvider>
    </>
  );
};

export const MirrorEditor: FC<IMirrorEditorProps> = props => {
  return (
    <RemirrorManager placeholder={defaultPlaceholder}>
      <RemirrorExtension Constructor={BoldExtension} />
      <RemirrorExtension Constructor={LinkExtension} />
      <MirrorEditorProvider {...props}>
        <MirrorEditorInner />
      </MirrorEditorProvider>
    </RemirrorManager>
  );
};
import { faBold } from '@fortawesome/pro-light-svg-icons';
import { logger, Button } from '@myOrg/utils';
import { useRemirror } from '@remirror/react';
import React, { FC } from 'react';

export const MirrorEditorInner: FC<IProps> = ({}) => {
  const { getRootProps, actions } = useRemirror();
  return (
    <div className="mirror-outer">
      <div className="mirror-menu">
        <Button
          active={actions.bold.isActive()}
          disabled={!actions.bold.isEnabled()}
          onClick={() => {
            actions.bold.command();
          }}
          icon={faBold}
        />
      </div>

      <div {...getRootProps()} className="mirror-root" />
    </div>
  );
};

I will throw this into one of those great code sandbox tools out there so that others can reproduce.

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Comments:28 (27 by maintainers)

github_iconTop GitHub Comments

2reactions
ifiokjrcommented, Aug 26, 2019

I had some time today to look at the controlled editor and I think I’ve managed to fix all the bugs mentioned above. You can watch my progress in #149

There’s still a fair bit of work to go into that branch, but the markdown editor will be part of the next major release.

2019-08-26 20 18 49

2reactions
benjiecommented, Aug 16, 2019

No problem at all. We’re hoping to use Remirror using markdown as the interchange format in our app. Previously we were using DraftJS and had a custom markup (inspired by Slack’s markup) for simple text that just had tags/mentions/etc, and we were just storing the DraftJS content object for everything else. We’d like to use Markdown as the interchange format, whilst still allowing features like collaboration - the plan is to use Prosemirror with markdown import/export and to use raw prosemirror transactions with the collaboration plugin when we need that. At this point we’re still experimenting with remirror (which seems very promising, and certainly beats us building our own bundle of prosemirror which I had previously started on), and are keen to help get it to production-readiness for our needs.

Read more comments on GitHub >

github_iconTop Results From Across the Web

MT Showcase Tutorial 2 - Creating an application - YouTube
In this MT Showcase tutorial we cover the steps for creating a simple application.
Read more >
Showcase Presentation Software from MultiTaction
The Showcase editor is where the stage is set, providing a powerful and flexible tool to create the desired experience. You simply drag...
Read more >
How to develop better web widgets with showcase applications
A showcase application can help you to anticipate integration problems and define what is the input and output of a widget.
Read more >
Showcase control - Kumu Help Docs
Showcase control. Use. Add a control to activate showcase for a given field or set of selectors via a list of labels, buttons...
Read more >
Social Editor - Remirror
The <SocialEditor> provides a state of the art editor with mention and tag support. import { SocialEditor } from '@remirror/react-editors/social'; ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found