Adam Zion
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights New
    • Engagement control
    • Make a copy
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Note Insights Versions and GitHub Sync Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Make a copy Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       Owned this note    Owned this note      
    Published Linked with GitHub
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    # Rich Text Editor Component The Rich Text Editor allows a site editor to easily add text content to a Web site. There are three options for the Rich Text Editor: Simple, Basic, and Full. The Rich Text Editor is also a part 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. Accordion, Card, Table, etc). ## Insert a Rich Text Editor into a Site Click in an empty space in a Flow Container on a Web site and click the "Add" button under Component. Click the check box next to "Rich Text" in the left side of the "Insert Component" window. ![Insert a Rich Text Editor](https://i.imgur.com/LnD5qa6.png) ## Content Editor Details Next, select the type of Rich Text Editor that you wish to insert. ### Simple Rich Text Editor ![Simple Rich Text Editor](https://i.imgur.com/iLq41jx.png) The Simple Rich Text Editor offers basic text entry and Superscript. ### Basic Rich Text Editor ![Basic Rich Text Editor](https://i.imgur.com/joX5OZU.png) Basic Rich Text Editor offers the same features as the Simple Editor, plus bold, italic, underline, link, left alignment, right alignment, center alignment, justification alignment. ### Full Rich Text Editor ![Full Rich Text Editor](https://i.imgur.com/ifitIXu.png) The Full Rich Text Editor offers the same formatting options as the Basic Editor, plus header levels 1 through 3 and blockquote. ### Using the Rich Text Editor A user enters text into a Rich Text Editor, and can bring up the formatting toolbar by highlighting text. ![Formatting Text](https://i.imgur.com/oPEniMW.png) ![Italic Text](https://i.imgur.com/p5X3VDT.png) Please note that the above are examples of the default editors. Individual needs and site builder will determine which rich text editor options are available, where they are available to the editor, and which optionsare 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](https://docs.slatejs.org/).** ## Architectural Details ### Contents 1. **Exports** - [Slate Editor Component](#slateeditor) - [Content Component](#slatecontent) - [SlateContext Component](#slateeditorcontext) - [Hover Menu Component](#hovermenu) - [RichText Items](#rich-text-items) 2. **Plugin Factories** - [Mark Factory](#mark-factory) - [Inline Factory](#inline-factory) - [Block Factory](#block-factory) 3. **APIs** - [Node Component API](#node-component-api) - [Node Form API](#node-form-api) 4. **Guides** - [How to create mark plugin](#creating-mark-plugin) - [How to create inline plugin. ](#creating-inline-plugin) - [TBD] Creating a block plugin ### Exports <a name="slateeditor"></a> #### Slate Editor Component - `<SlateEditor />` `<SlateEditor>` - Main Content controller component that provides react context with editor related data and callbacks to nested components. **Basic usage:** ```js 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:** |Name| Description | |---|---| |`initialValue`|Initial value of the editor that will be used on editor mount.| |`plugins` | An array of slate editor plugins to be applied to the editor instance on initialization by `<Content>`.| |`value` |A Value object representing the current value of the editor. Prop `value` takes priority over `initialValue` prop and internal `value` state. | |`onChange` |A change handler that will be called with the `change` that applied the change. This hook allows you to add persistence logic to your editor. |`children`| Components listed as children will have access to the Content Context. `<SlateEditor>` requires `<Content>` to be an immediate children. <a name="slatecontent"></a> ### Content Component - `<Content />` `<Content>` - Wrapper around [`<Editable />`](https://docs.slatejs.org/libraries/slate-react#editable) which is the main editorial area. `<Content>` supplies values from props and SlateEditor Context to [`<Editable />`](https://docs.slatejs.org/libraries/slate-react#editable). **Basic usage:** ```js 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`. <a name="slateeditorcontext"></a> ### SlateContext Component `SlateContext` - an object with editor related data to be used in nested components. **Basic usage:** ```js 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:** |Name | Description | |---|---| |`initialValue`|Initial value of the editor that will be used on editor mount.| |`plugins` | An array of slate editor plugins to be applied to the editor instance on initialization by `<Content>`.| |`value` |A Value object representing the current value of the editor. Prop `value` takes priority over `initialValue` prop and internal `value` state. | |`onChange` |A change handler that will be called with the `change` that applied the change. This hook allows you to add persistence logic to your editor. <a name="hovermenu"></a> ### 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:** ```js 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; ``` <a name="rich-text-items"></a> #### RichText Component The RichText Component is built on the [SlateJS](https://docs.slatejs.org/) 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: ```js 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](#using-form-api) along with the component, and plugin with handle the data updates and rendering of both Component and Form. - **Block plugin** - TBD <a name="mark-factory"></a> #### 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](https://material.io/tools/icons/?style=baseline) glyph <a name="inline-factory"></a> ### 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](https://material.io/tools/icons/?style=baseline) glyph <a name="block-factory"></a> ### 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](https://material.io/tools/icons/?style=baseline) glyph ### Guides <a name="creating-mark-plugin"></a> #### 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:** ```js 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, }; ``` <a name="creating-inline-plugin"></a> #### Creating Inline Plugin **Inline Plugin Factory usage:** ```js 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, };

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully