1.0.0-rc.23 • Published 11 months ago

@bodiless/richtext v1.0.0-rc.23

Weekly downloads
109
License
Apache-2.0
Repository
github
Last release
11 months ago

Rich Text Editor Component

The Rich Text Editor allows you to easily add text content to your site. By default there are three options for the Rich Text Editor: Simple, Basic, and Full. The Rich Text Editor is also a sub component of many higher order components. You can add text to a page on your site via the editor component or you can add a component or components that contain text, which make use of the editor (e.g. Card, Accordion, etc).

Content Editor Details

SimpleBasicFull
npm.ionpm.ionpm.io
The Simple Rich Text Editor offers the following formatting options: SuperscriptBasic Rich Text Editor offers the following formatting options: bold, italic, underline, link, left alignment, right alignment, center alignment, justification alignment, superscriptThe Full Rich Text Editor offers the following formatting options: bold, italic, underline, link, left alignment, right alignment, center alignment, justification alignment, superscript, header

?> Please note that the above configurations are examples of the default options. The site requirements and site builder will determine which rich text editor options are available, where they are available to the editor, and which options are available for each variation.

Site Builder Details

Note this document describes the low-level API of Bodiless's rich text editing support. A new high level API is under active development.

Bodiless RichText provides a Rich Text Component that allows content uses to edit and manipulate text. This package also includes a set of tools for elegant scaffolding and extending Slate editor.

Before using this module it is essential to understand how Slate editor works: Read Slate Walkthroughs and Guides sections.

Architectural Details

Contents

  1. Exports

  2. Plugin Factories

  3. APIs

  4. Guides

Exports

Slate Editor Component - <SlateEditor />

<SlateEditor> - Main Content controller component that provides react context with editor related data and callbacks to nested components.

Basic usage:

import React, { useMemo, useState } from 'react';
import { createEditor } from 'slate';
import { withReact, Slate } from 'slate-react';
import { SlateEditor, Content } from '@bodiless/richtext/lib/core';

const defaultValue = [{
  type: 'paragraph',
  children: [
    { text: '' },
  ],
}];

const MyEditor = () => {
  const editor = useMemo(() => withReact(createEditor()), [])
  const [value, setValue] = useState(defaultValue)
  return (
    <Slate
      editor={editor}
      value={value}
      onChange={newValue => setValue(newValue)}
    >
      <SlateEditor>
        <Content />
      </SlateEditor>
    </Slate>
  );
};

Properties:

NameDescription
initialValueInitial value of the editor that will be used on editor mount.
pluginsAn array of slate editor plugins to be applied to the editor instance on initialization by <Content>.
valueA Value object representing the current value of the editor. Prop value takes priority over initialValue prop and internal value state.
onChangeA change handler that will be called with the change that applied the change. This hook allows you to add persistence logic to your editor.
childrenComponents listed as children will have access to the Content Context. <SlateEditor> requires <Content> to be an immediate children.

Content Component - <Content />

<Content> - Wrapper around <Editable /> which is the main editorial area. <Content> supplies values from props and SlateEditor Context to <Editable />.

Basic usage:

import React, { useMemo, useState } from 'react';
import { createEditor } from 'slate';
import { withReact, Slate } from 'slate-react';
import { Content } from '@bodiless/richtext/lib/core';

const defaultValue = [{
  type: 'paragraph',
  children: [
    { text: '' },
  ],
}];

const MyEditor = () => {
  const editor = useMemo(() => withReact(createEditor()), [])
  const [value, setValue] = useState(defaultValue)
  return (
    <Slate
      editor={editor}
      value={value}
      onChange={newValue => setValue(newValue)}
    >
      <Content
        className='editor' 
        style={{ opacity: '0.5'}}
        spellCheck
        placeholder='Type here...' 
      />
    </Slate>
  );
};

Properties:

See EditableProps type from slate-react/dist/editable.d.ts.

SlateContext Component

SlateContext - an object with editor related data to be used in nested components.

Basic usage:

import React, { useMemo, useState, useContext } from 'react';
import { createEditor } from 'slate';
import { withReact, Slate } from 'slate-react';
import { SlateEditor, Content, SlateEditorContext } from '@bodiless/richtext/lib/core';

const defaultValue = [{
  type: 'paragraph',
  children: [
    { text: '' },
  ],
}];

const Toolbar = () => {
  const { value } = useContext(SlateEditorContext);
  // some logic to render data based on context value
  return <div>{JSON.stringify(value, null, 2)}</div>
} 

const MyEditor = () => {
  const editor = useMemo(() => withReact(createEditor()), [])
  const [value, setValue] = useState(defaultValue)
  return (
    <Slate
      editor={editor}
      value={value}
      onChange={newValue => setValue(newValue)}
    >
      <SlateEditor value={value}>
        <Toolbar />
        <Content />
      </SlateEditor>
    </Slate>
  );
};

Properties:

NameDescription
initialValueInitial value of the editor that will be used on editor mount.
pluginsAn array of slate editor plugins to be applied to the editor instance on initialization by <Content>.
valueA Value object representing the current value of the editor. Prop value takes priority over initialValue prop and internal value state.
onChangeA change handler that will be called with the change that applied the change. This hook allows you to add persistence logic to your editor.

Hover Menu Component - <HoverMenu />

<HoverMenu /> - a hover menu that appears on any selection within editor. <HoverMenu /> passes values of SlateContext to all its children as props.

Basic usage:

import React from "react";
import { SlateEditor, Content, HoverMenu } from "@bodiless/richtext/lib/core";

const Content = (props) => {
  return (
    <SlateEditor {...props} plugins={plugins} >

      <HoverMenu>
        <BoldButton />
        <ItalicButton />
      </HoverMenu>

      <Content />
    </SlateEditor>
  );
};

export default Content;

RichText Component

The RichText Component is built on the SlateJS framework. It takes design object (see @bodiless/Design System) that contain HOC to build out the component that are available in the RichText Editor. Those are then presented to the user using both a contextual hover menu as well as the standard menu. These items can be used by using a set of HOC's.

startWith(Component) lets us know which component should be part of the item

asMark, asInline and asBlock are used to say how the slate editor should use the component.

  • marks are used for basic character-level formatting (eg bold, italic, underline, text=color, etc).
  • inlines may also be used for character formatting, but should generally be reserved for cases where the component requires additional configuration besides the text (for example, a link, which may require href, target or other attributes).
  • blocks should be used for block-level formatting (eg headers, lists, etc).

withKey('mod+k') can be used to add a shortcut key to the component.

withButton("icon") can be used to add a button that will set the text to a component. If the item is asBlock then it will be added to the global menu if not then it will be added to the local hover menu.

There are a set of keys that have defaults that are often used they are the following:

  • SuperScript
  • Bold
  • Italic
  • Underline
  • Link
  • AlignLeft
  • AlignRight
  • AlignCenter
  • AlignJustify
  • H1
  • H2
  • H3

With these one only need to include the key.

Each of this helper return a function that we pass in as items. We can use flow to combine them as such:

const design = {
  Bold: asBold,
  Link: asLink,
  Strikethrough: flow(
    startWith(Span),
    withButton('format_strikethrough'),
    withKey('mod+s'),
    asMark,
  ),
};
const EditorFullFeatured = <P extends object> (props:P) => (
  <RichText design={items2} initialValue={demoValue} {...props} />
);

Plugin Factories

In order to minify boilerplate creating a slate plugin @bodiless/richtext provides factories. There are 3 types of plugins that can be created:

  • Mark plugin - renders provided component wrapping a piece of text. Doesn't have any data and component is togglable.
  • Inline plugin - acts as a mark, but has data and a way to control it. You can provide a Form component that implements Form API along with the component, and plugin with handle the data updates and rendering of both Component and Form.
  • Block plugin - TBD

Mark Plugin Factory

Mark plugin factory reduces boilerplate required to create a plugin to render custom marks in Slate editor. Also, you can generate a button that is going to trigger the mark on and off.

Exports:

  • createMarkButton(markType: string, materialIcon: string): React.ComponentType
    • markType: string - a unique string to identify mark component. Should match markType value of the corresponding mark plugin.
    • materialIcon: string - a string that is converted into a Material Icon glyph

Inline Plugin Factory

Inline plugin factory reduces boilerplate required to create a plugin to render custom inline nodes in Slate editor. You can generate a button for an inline node like for marks. Also, in addition, you can provide a custom form for each inline node to manage its data.

Exports:

  • createInlineButton(inlineType: string, materialIcon: string): React.ComponentType
    • inlineType: string - a unique string to identify inline node component. Should match inlineType value of the corresponding inline plugin.
    • materialIcon: string - a string that is converted into a Material Icon glyph

Block Plugin Factory

Block plugin factory reduces boilerplate required to create a plugin to render custom block nodes in Slate editor. You can generate a button for block node like for marks.

Exports:

  • createBlockButton(inlineType: string, materialIcon: string): React.ComponentType
    • inlineType: string - a unique string to identify inline node component. Should match inlineType value of the corresponding block plugin.
    • materialIcon: string - a string that is converted into a Material Icon glyph

Guides

Creating mark plugin

Mark is a simple wrapper for a specific piece of text in the editor. Marks are the simplest entities of Slate Content and can be only triggered on and off and stack with other marks.

Mark Plugin Factory usage:

import React from 'react';
import { createMarkButton } from '@bodiless/richtext/lib/plugin-factory';

const MARK_TYPE = 'custom_mark';
const CustomMarkButton = createMarkButton(MARK_TYPE, 'format_underline');

export {
  CustomMarkButton,
};

Creating Inline Plugin

Inline Plugin Factory usage:

import React from 'react';
import { createInlineButton } from '@bodiless/richtext/lib/plugin-factory';

const INLINE_TYPE = 'custom_inline';
const CustomInlineButton = createInlineButton(INLINE_TYPE, 'link');

export {
  CustomInlineButton,
};
1.0.0-rc.42

11 months ago

1.0.0-rc.41

11 months ago

1.0.0-rc.40

11 months ago

1.0.0-rc.39

11 months ago

1.0.0-rc.38

12 months ago

1.0.0-rc.35

1 year ago

1.0.0-rc.34

1 year ago

1.0.0-rc.37

1 year ago

1.0.0-rc.36

1 year ago

1.0.0-rc.24

1 year ago

1.0.0-rc.28

1 year ago

1.0.0-rc.27

1 year ago

1.0.0-rc.26

1 year ago

1.0.0-rc.25

1 year ago

1.0.0-rc.29

1 year ago

1.0.0-rc.31

1 year ago

1.0.0-rc.30

1 year ago

1.0.0-rc.33

1 year ago

1.0.0-rc.32

1 year ago

1.0.0-rc.23

1 year ago

1.0.0-rc.19

2 years ago

1.0.0-rc.18

2 years ago

1.0.0-rc.20

2 years ago

1.0.0-rc.22

2 years ago

1.0.0-rc.21

2 years ago

1.0.0-rc.17

2 years ago

1.0.0-rc.16

2 years ago

1.0.0-rc.15

2 years ago

1.0.0-rc.13

2 years ago

1.0.0-rc.12

2 years ago

1.0.0-rc.11

2 years ago

1.0.0-rc.10

2 years ago

1.0.0-rc.14

2 years ago

1.0.0-rc.9

2 years ago

1.0.0-rc.7

2 years ago

1.0.0-rc.8

2 years ago

1.0.0-rc.5

2 years ago

1.0.0-rc.6

2 years ago

1.0.0-rc.3

2 years ago

1.0.0-rc.4

2 years ago

1.0.0-rc.2

2 years ago

1.0.0-rc.1

2 years ago

1.0.0-beta.11

2 years ago

1.0.0-beta.12

2 years ago

1.0.0-beta.10

2 years ago

1.0.0-beta.17

2 years ago

1.0.0-beta.18

2 years ago

1.0.0-beta.15

2 years ago

1.0.0-beta.16

2 years ago

1.0.0-beta.2

2 years ago

1.0.0-beta.3

2 years ago

1.0.0-beta.4

2 years ago

1.0.0-beta.5

2 years ago

1.0.0-beta.0

2 years ago

1.0.0-beta.1

2 years ago

1.0.0-beta.6

2 years ago

1.0.0-beta.7

2 years ago

1.0.0-beta.8

2 years ago

1.0.0-beta.9

2 years ago

0.3.6

2 years ago

0.3.5

2 years ago

0.3.7

2 years ago

0.3.2

2 years ago

0.3.4

2 years ago

0.3.3

2 years ago

0.3.1

2 years ago

0.3.0

3 years ago

0.2.10

3 years ago

0.1.2

3 years ago

0.2.9

3 years ago

0.2.8

3 years ago

0.2.7

3 years ago

0.2.6

3 years ago

0.2.5

3 years ago

0.2.4

3 years ago

0.2.3

3 years ago

0.2.2

3 years ago

0.2.1

3 years ago

0.2.0

3 years ago

0.1.1

3 years ago

0.1.0

3 years ago

0.0.72

3 years ago

0.0.71

3 years ago

0.0.70

3 years ago

0.0.69

3 years ago

0.0.68

3 years ago

0.0.67

3 years ago

0.0.66

3 years ago

0.0.65

3 years ago

0.0.64

3 years ago

0.0.63

3 years ago

0.0.62

3 years ago

0.0.61

3 years ago

0.0.60

3 years ago

0.0.59

4 years ago

0.0.58

4 years ago

0.0.57

4 years ago

0.0.56

4 years ago

0.0.55

4 years ago

0.0.54

4 years ago

0.0.53

4 years ago

0.0.52

4 years ago

0.0.51

4 years ago

0.0.50

4 years ago

0.0.49

4 years ago

0.0.48

4 years ago

0.0.47

4 years ago

0.0.45

4 years ago

0.0.46

4 years ago

0.0.44

4 years ago

0.0.43

4 years ago

0.0.42

4 years ago

0.0.41

4 years ago

0.0.40

4 years ago

0.0.39

4 years ago

0.0.38

4 years ago

0.0.37

4 years ago

0.0.36

4 years ago