From 4792fc320048f2239ee1bed08a586205438d28bc Mon Sep 17 00:00:00 2001 From: Hans Pagel Date: Sat, 3 Apr 2021 15:21:30 +0200 Subject: [PATCH] docs: update content --- docs/src/components/Demo/index.vue | 2 +- docs/src/components/DemoMixin/index.js | 6 +- docs/src/components/Demos/index.vue | 5 + docs/src/demos/Examples/Menus/React/index.jsx | 17 +-- docs/src/demos/Examples/Menus/Vue/index.vue | 17 +-- .../Extensions/FloatingMenu/React/index.jsx | 3 +- .../Extensions/FloatingMenu/Vue/index.vue | 3 +- docs/src/docPages/api/commands.md | 41 ++++++- docs/src/docPages/api/concept.md | 1 + docs/src/docPages/api/editor.md | 79 +++++++----- .../api/extensions/collaboration-cursor.md | 2 +- .../docPages/api/extensions/collaboration.md | 2 +- .../docPages/api/nodes/code-block-lowlight.md | 7 ++ docs/src/docPages/api/nodes/code-block.md | 2 +- docs/src/docPages/guide/content.md | 4 +- docs/src/docPages/guide/menus.md | 115 ++++++++++++++++++ docs/src/docPages/guide/toolbar.md | 72 ----------- docs/src/docPages/introduction.md | 2 +- docs/src/docPages/overview/upgrade-guide.md | 3 + docs/src/links.yaml | 8 +- 20 files changed, 256 insertions(+), 135 deletions(-) create mode 100644 docs/src/docPages/api/nodes/code-block-lowlight.md create mode 100644 docs/src/docPages/guide/menus.md delete mode 100644 docs/src/docPages/guide/toolbar.md diff --git a/docs/src/components/Demo/index.vue b/docs/src/components/Demo/index.vue index 1c1e894c..7e33004f 100644 --- a/docs/src/components/Demo/index.vue +++ b/docs/src/components/Demo/index.vue @@ -4,7 +4,7 @@
@@ -29,6 +30,10 @@ export default { type: Object, required: true, }, + hideSource: { + type: Boolean, + default: false, + }, }, data() { diff --git a/docs/src/demos/Examples/Menus/React/index.jsx b/docs/src/demos/Examples/Menus/React/index.jsx index af78c4a5..ec70b28a 100644 --- a/docs/src/demos/Examples/Menus/React/index.jsx +++ b/docs/src/demos/Examples/Menus/React/index.jsx @@ -15,7 +15,10 @@ export default () => { ], content: `

- Hey, try to select some text here. There will popup a menu for selecting some inline styles. Remember: you have full control about content and styling of this menu. + Try to select this text to see what we call the bubble menu. +

+

+ Neat, isn’t it? Add an empty paragraph to see the floating menu.

`, }) @@ -27,19 +30,19 @@ export default () => { onClick={() => editor.chain().focus().toggleBold().run()} className={editor.isActive('bold') ? 'is-active' : ''} > - bold + Bold } @@ -48,19 +51,19 @@ export default () => { onClick={() => editor.chain().focus().toggleHeading({ level: 1 }).run()} className={editor.isActive('heading', { level: 1 }) ? 'is-active' : ''} > - h1 + H1 } diff --git a/docs/src/demos/Examples/Menus/Vue/index.vue b/docs/src/demos/Examples/Menus/Vue/index.vue index d1f1fc69..cfc17cd3 100644 --- a/docs/src/demos/Examples/Menus/Vue/index.vue +++ b/docs/src/demos/Examples/Menus/Vue/index.vue @@ -2,25 +2,25 @@
@@ -57,7 +57,10 @@ export default { ], content: `

- Hey, try to select some text here. You’ll see a formatting menu pop up. And as always, you are in full control about content and styling of this menu. + Try to select this text to see what we call the bubble menu. +

+

+ Neat, isn’t it? Add an empty paragraph to see the floating menu.

`, }) diff --git a/docs/src/demos/Extensions/FloatingMenu/React/index.jsx b/docs/src/demos/Extensions/FloatingMenu/React/index.jsx index 680bdd77..a4bcdf3c 100644 --- a/docs/src/demos/Extensions/FloatingMenu/React/index.jsx +++ b/docs/src/demos/Extensions/FloatingMenu/React/index.jsx @@ -10,8 +10,9 @@ export default () => { ], content: `

- This is an example of a medium-like editor. Enter a new line and some buttons will appear. + This is an example of a Medium-like editor. Enter a new line and some buttons will appear.

+

`, }) diff --git a/docs/src/demos/Extensions/FloatingMenu/Vue/index.vue b/docs/src/demos/Extensions/FloatingMenu/Vue/index.vue index 48f813a3..c8d781c8 100644 --- a/docs/src/demos/Extensions/FloatingMenu/Vue/index.vue +++ b/docs/src/demos/Extensions/FloatingMenu/Vue/index.vue @@ -38,8 +38,9 @@ export default { ], content: `

- This is an example of a medium-like editor. Enter a new line and some buttons will appear. + This is an example of a Medium-like editor. Enter a new line and some buttons will appear.

+

`, }) }, diff --git a/docs/src/docPages/api/commands.md b/docs/src/docPages/api/commands.md index 4419036a..18e723c9 100644 --- a/docs/src/docPages/api/commands.md +++ b/docs/src/docPages/api/commands.md @@ -31,6 +31,26 @@ In the example above two different commands are executed at once. When a user cl All chained commands are kind of queued up. They are combined to one single transaction. That means, the content is only updated once, also the `update` event is only triggered once. +#### Chaining inside custom commands +When chaining a command, the transaction is held back. If you want to chain commands inside your custom commands, you’ll need to use said transaction and add to it. Here is how you would do that: + +```js +addCommands() { + return { + insertTimecode: attributes => ({ chain }) => { + // Doesn’t work: + // return editor.chain() … + + // Does work: + return chain() + .insertNode('timecode', attributes) + .insertText(' ') + .run() + }, + } +} +``` + ### Inline commands In some cases, it’s helpful to put some more logic in a command. That’s why you can execute commands in commands. I know, that sounds crazy, but let’s look at an example: @@ -208,9 +228,26 @@ this.editor .createParagraphNear() .insertHTML('

') .run() -``` --> +``` -## Add your own commands +Add a custom command to insert a node. +```js +addCommands() { + return { + insertTimecode: attributes => ({ chain }) => { + return chain() + .focus() + .insertNode('timecode', attributes) + .insertText(' ') + .run(); + }, + } +}, +``` +--> + +## Add custom commands All extensions can add additional commands (and most do), check out the specific [documentation for the provided nodes](/api/nodes), [marks](/api/marks), and [extensions](/api/extensions) to learn more about those. Of course, you can [add your custom extensions](/guide/build-extensions) with custom commands aswell. + diff --git a/docs/src/docPages/api/concept.md b/docs/src/docPages/api/concept.md index 920750ca..4d26a5eb 100644 --- a/docs/src/docPages/api/concept.md +++ b/docs/src/docPages/api/concept.md @@ -23,3 +23,4 @@ ProseMirror has its own vocabulary and you’ll stumble upon all those words now | Node | Adds blocks, like heading, paragraph. | | Mark | Adds inline formatting, for example bold or italic. | | Command | Execute an action inside the editor, that somehow changes the state. | +| Decoration | Styling on top of the document, for example to highlight mistakes. | diff --git a/docs/src/docPages/api/editor.md b/docs/src/docPages/api/editor.md index 755d821a..616c66d0 100644 --- a/docs/src/docPages/api/editor.md +++ b/docs/src/docPages/api/editor.md @@ -5,8 +5,30 @@ ## Introduction This class is a central building block of tiptap. It does most of the heavy lifting of creating a working [ProseMirror](https://ProseMirror.net/) editor such as creating the [`EditorView`](https://ProseMirror.net/docs/ref/#view.EditorView), setting the initial [`EditorState`](https://ProseMirror.net/docs/ref/#state.Editor_State) and so on. -## List of available settings -Check out the API documentation to see [all available options](/api/editor/). +## Methods +The editor instance will provide a bunch of public methods. They’ll help you to work with the editor. + +Don’t confuse methods with [commands](/api/commands). Commands are used to change the state of editor (content, selection, and so on) and only return `true` or `false`. Methods are regular functions and can return anything. + +| Method | Parameters | Description | +| --------------------- | ----------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------- | +| `can()` | - | Check if a command or a command chain can be executed. Without executing it. | +| `chain()` | - | Create a command chain to call multiple commands at once. | +| `createDocument()` | `content` EditorContent
`parseOptions` | Creates a ProseMirror document. | +| `destroy()` | – | Stops the editor instance and unbinds all events. | +| `getHTML()` | – | Returns the current content as HTML. | +| `getJSON()` | – | Returns the current content as JSON. | +| `getMarkAttributes()` | `name` Name of the mark | Get attributes of the currently selected mark. | +| `getNodeAttributes()` | `name` Name of the node | Get attributes of the currently selected node. | +| `isActive()` | `name` Name of the node or mark
`attrs` Attributes of the node or mark | Returns if the currently selected node or mark is active. | +| `isEditable()` | - | Returns whether the editor is editable. | +| `isEmpty()` | - | Check if there is no content. | +| `getCharacterCount()` | - | Get the number of characters for the current document. | +| `registerPlugin()` | `plugin` A ProseMirror plugin
`handlePlugins` Control how to merge the plugin into the existing plugins. | Register a ProseMirror plugin. | +| `setOptions()` | `options` A list of options | Update editor options. | +| `unregisterPlugin()` | `name` The plugins name | Unregister a ProseMirror plugin. | + +## Settings ### Element The `element` specifies the HTML element the editor will be binded too. The following code will integrate tiptap with an element with the `.element` class: @@ -147,37 +169,28 @@ new Editor({ }) ``` - +### Editor props +For advanced use cases, you can pass `editorProps` which will be handled by [ProseMirror](https://prosemirror.net/docs/ref/#view.EditorProps). Here is an example how you can pass a few [Tailwind](https://tailwindcss.com/) classes to the editor container, but there is a lot more you can do. -## List of available methods -An editor instance will provide the following public methods. They’ll help you to work with the editor. +```js +new Editor({ + // Learn more: https://prosemirror.net/docs/ref/#view.EditorProps + editorProps: { + attributes: { + class: 'prose prose-sm sm:prose lg:prose-lg xl:prose-2xl mx-auto focus:outline-none', + } + }, +}) +``` -Don’t confuse methods with [commands](/api/commands), which are used to change the state of editor (content, selection, and so on) and only return `true` or `false`. +### Parse options +Passed content is parsed by ProseMirror. To hook into the parsing, you can pass `parseOptions` which are then handled by [ProseMirror](https://prosemirror.net/docs/ref/#model.ParseOptions). -| Method | Parameters | Description | -| --------------------- | ----------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------- | -| `can()` | - | Check if a command or a command chain can be executed. Without executing it. | -| `chain()` | - | Create a command chain to call multiple commands at once. | -| `createDocument()` | `content` EditorContent
`parseOptions` | Creates a ProseMirror document. | -| `destroy()` | – | Stops the editor instance and unbinds all events. | -| `getHTML()` | – | Returns the current content as HTML. | -| `getJSON()` | – | Returns the current content as JSON. | -| `getMarkAttributes()` | `name` Name of the mark | Get attributes of the currently selected mark. | -| `getNodeAttributes()` | `name` Name of the node | Get attributes of the currently selected node. | -| `isActive()` | `name` Name of the node or mark
`attrs` Attributes of the node or mark | Returns if the currently selected node or mark is active. | -| `isEditable()` | - | Returns whether the editor is editable. | -| `isEmpty()` | - | Check if there is no content. | -| `getCharacterCount()` | - | Get the number of characters for the current document. | -| `registerPlugin()` | `plugin` A ProseMirror plugin
`handlePlugins` Control how to merge the plugin into the existing plugins. | Register a ProseMirror plugin. | -| `setOptions()` | `options` A list of options | Update editor options. | -| `unregisterPlugin()` | `name` The plugins name | Unregister a ProseMirror plugin. | +```js +new Editor({ + // Learn more: https://prosemirror.net/docs/ref/#model.ParseOptions + parseOptions: { + preserveWhitespace: 'full', + }, +}) +``` diff --git a/docs/src/docPages/api/extensions/collaboration-cursor.md b/docs/src/docPages/api/extensions/collaboration-cursor.md index 271b584a..5c2b0f21 100644 --- a/docs/src/docPages/api/extensions/collaboration-cursor.md +++ b/docs/src/docPages/api/extensions/collaboration-cursor.md @@ -41,5 +41,5 @@ This extension requires the [`Collaboration`](/api/extensions/collaboration) ext The content of this editor is shared with other users. ::: - + diff --git a/docs/src/docPages/api/extensions/collaboration.md b/docs/src/docPages/api/extensions/collaboration.md index ed1365dd..6954c883 100644 --- a/docs/src/docPages/api/extensions/collaboration.md +++ b/docs/src/docPages/api/extensions/collaboration.md @@ -48,5 +48,5 @@ yarn add @tiptap/extension-collaboration yjs y-websocket :::warning Public The content of this editor is shared with other users. ::: - + diff --git a/docs/src/docPages/api/nodes/code-block-lowlight.md b/docs/src/docPages/api/nodes/code-block-lowlight.md new file mode 100644 index 00000000..97fc8537 --- /dev/null +++ b/docs/src/docPages/api/nodes/code-block-lowlight.md @@ -0,0 +1,7 @@ +# CodeBlockLowlight + +:::pro Fund the development ♥ +We need your support to maintain, update, support and develop tiptap 2. If you’re waiting for this extension, [become a sponsor and fund our work](/sponsor). +::: + +TODO diff --git a/docs/src/docPages/api/nodes/code-block.md b/docs/src/docPages/api/nodes/code-block.md index caba885e..646ff68b 100644 --- a/docs/src/docPages/api/nodes/code-block.md +++ b/docs/src/docPages/api/nodes/code-block.md @@ -7,7 +7,7 @@ With the CodeBlock extension you can add fenced code blocks to your documents. I Type ```  (three backticks and a space) or ∼∼∼  (three tildes and a space) and a code block is instantly added for you. You can even specify the language, try writing ```css . That should add a `language-css` class to the ``-tag. ::: warning Restrictions -The CodeBlock extension doesn’t come with styling and has no syntax highlighting built-in. It’s on our roadmap though. +The CodeBlock extension doesn’t come with styling and has no syntax highlighting built-in. It’s [on our roadmap](/api/nodes/code-block-lowlight) though. ::: ## Installation diff --git a/docs/src/docPages/guide/content.md b/docs/src/docPages/guide/content.md index cb23bc28..2d68bc80 100644 --- a/docs/src/docPages/guide/content.md +++ b/docs/src/docPages/guide/content.md @@ -40,7 +40,7 @@ editor.commands.setContent({ Here is an interactive example where you can see that in action: - + ### Option 2: HTML HTML can be easily rendered in other places, for example in emails and it’s wildly used, so it’s probably easier to switch the editor at some point. Anyway, every editor instance provides a method to get HTML from the current document: @@ -64,7 +64,7 @@ editor.commands.setContent(`

Example Text

`) Use this interactive example to fiddle around: - + ### Option 3: Y.js Our editor has amazing support for Y.js, which is amazing to add [realtime collaboration, offline editing, or syncing between devices](/guide/collaborative-editing). diff --git a/docs/src/docPages/guide/menus.md b/docs/src/docPages/guide/menus.md new file mode 100644 index 00000000..16cd8825 --- /dev/null +++ b/docs/src/docPages/guide/menus.md @@ -0,0 +1,115 @@ +# Create menus + +## toc + +## Introduction +tiptap comes very raw, but that’s a good thing. You have full control (and when we say full, we mean full) about the appearance of it. That also means you can (and have to) build a menu on your own. You can start with a few buttons, and we help you to wire everything up. + +## Menus +The editor provides a fluent API to trigger commands and add active states. You can use any markup you like. To make the positioning of line menus easier, we provide a few utilities and components. Let’s go through the most typical use cases one by one. + +### Fixed menu +A fixed menu, for example on top of the editor, can be anything. We don’t provide such menu. Just add a `
` with a few ` +``` + +Oh, that’s a long command, right? Actually, it’s a [chain of commands](/api/commands#chain-commands), so let’s go through this one by one: + +```js +editor.chain().toggleBold().focus().run() +``` + +1. `editor` should be a tiptap instance, +2. `chain()` is used to tell the editor you want to execute multiple commands, +3. `focus()` sets the focus back to the editor, +4. `toggleBold()` marks the selected text bold, or removes the bold mark from the text selection if it’s already applied and +5. `run()` will execute the chain. + +In other words: This will be a typical **Bold** button for your text editor. + +Which commands are available depends on what extensions you have registered with the editor. Most extensions come with a `set…()`, `unset…()` and `toggle…()` command. Read the extension documentation to see what’s actually available or just surf through your code editor’s autocomplete. + +### Keep the focus +You have seen the `focus()` command in the above example already. When you click on the button, the browser focuses that DOM element and the editor loses focus. It’s likely you want to add `focus()` to all your menu buttons, so the writing flow of your users isn’t interrupted. + +### The active state +The editor provides an `isActive()` method to check if something is applied to the selected text already. In Vue.js you can toggle a CSS class with help of that function like that: + +```html + +``` + +This toggles the `.is-active` class accordingly and works for nodes and marks. You can even check for specific attributes, here is an example with the [`Highlight`](/api/marks/highlight) mark, that ignores different attributes: + +```js +editor.isActive('highlight') +``` + +And an example that compares the given attribute(s): + +```js +editor.isActive('highlight', { color: '#ffa8a8' }) +``` + +You can even ignore nodes and marks, but check for the attributes only. Here is an example with the [`TextAlign`](/api/extensions/text-align) extension: + +```js +editor.isActive({ textAlign: 'right' }) +``` + +If your selection spans multiple nodes or marks, or only part of the selection has a mark, `isActive()` will return `false` and indicate nothing is active. This is how it is supposed to be, because it allows people to apply a new node or mark to that selection right-away. + +## User experience +When designing a great user experience you should consider a few things. + +### Accessibility +* Make sure users can navigate the menu with their keyboard +* Use proper [title attributes](https://developer.mozilla.org/de/docs/Web/HTML/Global_attributes/title) +* Use proper [aria attributes](https://developer.mozilla.org/en-US/docs/Learn/Accessibility/WAI-ARIA_basics) +* List available keyboard shortcuts + +:::warning Incomplete +This section needs some work. Do you know what else needs to be taken into account when building an editor menu? Let us know on [GitHub](https://github.com/ueberdosis/tiptap-next) or send us an email to [humans@tiptap.dev](mailto:humans@tiptap.dev)! +::: + +### Icons +Most editor menus use icons for their buttons. In some of our demos, we use the open-source icon set [Remix Icon](https://remixicon.com/), that’s free to use. But it’s totally up to you what you use. Here are a few icon sets you can consider: + +* [Remix Icon](https://remixicon.com/#editor) +* [Font Awesome](https://fontawesome.com/icons?c=editors) +* [UI icons](https://www.ibm.com/design/language/iconography/ui-icons/library/) diff --git a/docs/src/docPages/guide/toolbar.md b/docs/src/docPages/guide/toolbar.md deleted file mode 100644 index 72498040..00000000 --- a/docs/src/docPages/guide/toolbar.md +++ /dev/null @@ -1,72 +0,0 @@ -# Create a toolbar - -## toc - -## Introduction -tiptap comes very raw, but that’s a good thing. You have full control (and when we say full, we mean full) about the appearance of it. That also means you have to build the editor toolbar on your own. Don’t worry though, you can start with a few buttons and we help you with everything else. - -## Commands -Let’s assume you’ve got the editor running already and you want to add your first button. You’ll need a ` -``` - -Oh, that’s a long command, right? Actually, it’s a [chain of commands](/api/commands#chain-commands), so let’s go through this one by one: - -```js -editor.chain().toggleBold().focus().run() -``` - -1. `editor` should be a tiptap instance, -2. `chain()` is used to tell the editor you want to execute multiple commands, -3. `focus()` sets the focus back to the editor, -4. `toggleBold()` marks the selected text bold, or removes the bold mark from the text selection if it’s already applied and -5. `run()` will execute the chain. - -In other words: This will be the typical **Bold** button for your text editor. - -Which commands are available depends on what extensions you’ve registered with the editor. Most of the extensions come with a `set…()`, `unset…()` and `toggle…()` command. Read the extension documentation to see what’s actually available or just surf through your code editor’s autocomplete. - -## Keep the focus -You’ve seen the `focus()` command in the above example already. When you click on the button, the browser focuses that DOM element and the editor loses focus. It’s likely you want to add `focus()` to all your toolbar buttons, so the writing flow of your users isn’t interrupted. - -## The active state -The editor provides an `isActive()` method to check if something is applied to the selected text already. In Vue.js you can toggle a CSS class with help of that function like that: - -```html - -``` - -This toggles the `.is-active` class accordingly. This works for nodes, and marks. You can even check for specific attributes, here is an example with the [`Highlight`](/api/marks/highlight) mark, that ignores different attributes: - -```js -editor.isActive('highlight') -``` - -And an example that compares the given attribute(s): - -```js -editor.isActive('highlight', { color: '#ffa8a8' }) -``` - -You can even ignore nodes and marks, but check for the attributes only. Here is an example with the [`TextAlign`](/api/extensions/text-align) extension: - -```js -editor.isActive({ textAlign: 'right' }) -``` - -If your selection spans multiple nodes or marks, or only part of the selection has a mark, `isActive()` will return `false` and indicate nothing is active. That is how it is supposed to be, because it allows people to apply a new node or mark to that selection right-away. - -## Icons -Most editor toolbars use icons for their buttons. In some of our demos, we use the open-source icon set [Remix Icon](https://remixicon.com/), that’s free to use. But it’s totally up to you what you use. Here are a few icon sets you can consider: - -* [Remix Icon](https://remixicon.com/#editor) -* [Font Awesome](https://fontawesome.com/icons?c=editors) -* [UI icons](https://www.ibm.com/design/language/iconography/ui-icons/library/) - -Also, we’re working on providing a configurable interface for tiptap. If you think that’s a great idea, [become a sponsor](/sponsor) to show us your support. ♥ diff --git a/docs/src/docPages/introduction.md b/docs/src/docPages/introduction.md index 7d26f565..77e55a9b 100644 --- a/docs/src/docPages/introduction.md +++ b/docs/src/docPages/introduction.md @@ -13,7 +13,7 @@ tiptap is a headless wrapper around [ProseMirror](https://ProseMirror.net) – a Create exactly the rich text editor you want out of customizable building blocks. tiptap comes with sensible defaults, a lot of extensions and a friendly API to customize every aspect. It’s backed by a welcoming community, open-source, and free. ## Example - + ## Features **Headless.** We don’t tell you what a menu should look like or where it should be rendered in the DOM. That’s why tiptap is headless and comes without any CSS. You are in full control over markup, styling and behaviour. diff --git a/docs/src/docPages/overview/upgrade-guide.md b/docs/src/docPages/overview/upgrade-guide.md index 03a9cb2c..554fb753 100644 --- a/docs/src/docPages/overview/upgrade-guide.md +++ b/docs/src/docPages/overview/upgrade-guide.md @@ -143,6 +143,9 @@ All new extensions come with specific commands to set, unset and toggle styles. | ~~`.underline()`~~ | `.toggleUnderline()` | | … | … | +### MenuBar, BubbleMenu and FloatingMenu +Read the dedicated [guide on creating menus](/guide/menus) to migrate your menus. + ### Commands can be chained now Most commands can be combined to one call now. That’s shorter than separate function calls in most cases. Here is an example to make the selected text bold: diff --git a/docs/src/links.yaml b/docs/src/links.yaml index 7950055b..13327e77 100644 --- a/docs/src/links.yaml +++ b/docs/src/links.yaml @@ -82,8 +82,9 @@ items: - title: Configure the editor link: /guide/configuration - - title: Create a toolbar - link: /guide/toolbar + - title: Create menus + link: /guide/menus + type: new - title: Custom styling link: /guide/styling - title: Accessibility @@ -131,6 +132,9 @@ link: /api/nodes/bullet-list - title: CodeBlock link: /api/nodes/code-block + - title: CodeBlockLowlight + link: /api/nodes/code-block-lowlight + type: draft - title: Document link: /api/nodes/document - title: Emoji