mirror of
https://github.com/ianstormtaylor/slate.git
synced 2025-04-22 14:21:54 +02:00
adding forced-layout-example (#954)
This commit is contained in:
parent
f8b103d75e
commit
af84cf2511
BIN
docs/images/forced-layout-example.png
Normal file
BIN
docs/images/forced-layout-example.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 104 KiB |
@ -7,6 +7,7 @@ This directory contains a set of examples that give you an idea for how you migh
|
||||
|
||||
- [**Plain text**](./plain-text) — showing the most basic case: a glorified `<textarea>`.
|
||||
- [**Rich text**](./rich-text) — showing the features you'd expect from a basic editor.
|
||||
- [**Forced Layout**](./forced-layout) - showing how to use schema rules to enforce document structure
|
||||
- [**Auto-markdown**](./auto-markdown) — showing how to add key handlers for Markdown-like shortcuts.
|
||||
- [**Links**](./links) — showing how wrap text in inline nodes with associated data.
|
||||
- [**Images**](./images) — showing how to use void (text-less) nodes to add images.
|
||||
|
8
examples/forced-layout/Readme.md
Normal file
8
examples/forced-layout/Readme.md
Normal file
@ -0,0 +1,8 @@
|
||||
|
||||
# Forced Layout Example
|
||||
|
||||

|
||||
|
||||
This example shows you how you can use Rules in your schema to enforce a document structure. The basic example enforces having one title block that is always at the top, and at least one paragraph block underneath it.
|
||||
|
||||
Check out the [Examples readme](..) to see how to run it!
|
107
examples/forced-layout/index.js
Normal file
107
examples/forced-layout/index.js
Normal file
@ -0,0 +1,107 @@
|
||||
|
||||
import { Editor, Raw, Block } from '../..'
|
||||
import React from 'react'
|
||||
import initialState from './state.json'
|
||||
|
||||
/**
|
||||
* The Forced Layout example.
|
||||
*
|
||||
* @type {Component}
|
||||
*/
|
||||
|
||||
class ForcedLayout extends React.Component {
|
||||
|
||||
/**
|
||||
* Deserialize the initial editor state.
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
|
||||
state = {
|
||||
state: Raw.deserialize(initialState, { terse: true }),
|
||||
schema: {
|
||||
nodes: {
|
||||
'title': props => <h1 {...props.attrs}>{props.children}</h1>,
|
||||
'paragraph': props => <p {...props.attrs}>{props.children}</p>
|
||||
},
|
||||
rules: [
|
||||
/* Rule that always makes the first block a title, normalizes by inserting one if no children, or setting the top to be a title */
|
||||
|
||||
{
|
||||
match: node => node.kind === 'document',
|
||||
validate: document => !document.nodes.size || document.nodes.first().type !== 'title' ? document.nodes : null,
|
||||
normalize: (transform, document, nodes) => {
|
||||
if (!nodes.size) {
|
||||
const title = Block.create({ type: 'title', data: {}})
|
||||
return transform.insertNodeByKey(document.key, 0, title)
|
||||
}
|
||||
|
||||
return transform.setNodeByKey(nodes.first().key, 'title')
|
||||
}
|
||||
},
|
||||
|
||||
/* Rule that only allows for one title, normalizes by making titles paragraphs */
|
||||
|
||||
{
|
||||
match: node => node.kind === 'document',
|
||||
validate: (document) => {
|
||||
const invalidChildren = document.nodes.filter((child, index) => child.type === 'title' && index !== 0)
|
||||
return invalidChildren.size ? invalidChildren : null
|
||||
},
|
||||
normalize: (transform, document, invalidChildren) => {
|
||||
let updatedTransform = transform
|
||||
invalidChildren.forEach((child) => {
|
||||
updatedTransform = transform.setNodeByKey(child.key, 'paragraph')
|
||||
})
|
||||
|
||||
return updatedTransform
|
||||
}
|
||||
},
|
||||
|
||||
/* Rule that forces at least one paragraph, normalizes by inserting an empty paragraph */
|
||||
|
||||
{
|
||||
match: node => node.kind === 'document',
|
||||
validate: document => document.nodes.size < 2 ? true : null,
|
||||
normalize: (transform, document) => {
|
||||
const paragraph = Block.create({ type: 'paragraph', data: {}})
|
||||
return transform.insertNodeByKey(document.key, 1, paragraph)
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* On change.
|
||||
*
|
||||
* @param {State} state
|
||||
*/
|
||||
|
||||
onChange = (state) => {
|
||||
this.setState({ state })
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the editor.
|
||||
*
|
||||
* @return {Component} component
|
||||
*/
|
||||
|
||||
render = () => {
|
||||
return (
|
||||
<Editor
|
||||
state={this.state.state}
|
||||
schema={this.state.schema}
|
||||
onChange={this.onChange}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Export.
|
||||
*/
|
||||
|
||||
export default ForcedLayout
|
32
examples/forced-layout/state.json
Normal file
32
examples/forced-layout/state.json
Normal file
@ -0,0 +1,32 @@
|
||||
{
|
||||
"nodes": [
|
||||
{
|
||||
"kind": "block",
|
||||
"type": "title",
|
||||
"nodes": [
|
||||
{
|
||||
"kind": "text",
|
||||
"ranges": [
|
||||
{
|
||||
"text": "This example shows how to enforce your layout with rules."
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"kind": "block",
|
||||
"type": "paragraph",
|
||||
"nodes": [
|
||||
{
|
||||
"kind": "text",
|
||||
"ranges": [
|
||||
{
|
||||
"text": "This document will always have one title at the top, and at least one paragraph"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
@ -8,6 +8,7 @@ import CodeHighlighting from './code-highlighting'
|
||||
import Embeds from './embeds'
|
||||
import Emojis from './emojis'
|
||||
import FocusBlur from './focus-blur'
|
||||
import ForcedLayout from './forced-layout'
|
||||
import HoveringMenu from './hovering-menu'
|
||||
import Iframes from './iframes'
|
||||
import Images from './images'
|
||||
@ -59,6 +60,7 @@ const EXAMPLES = [
|
||||
['Plugins', Plugins, '/plugins'],
|
||||
['Iframes', Iframes, '/iframes'],
|
||||
['Focus & Blur', FocusBlur, '/focus-blur'],
|
||||
['Forced Layout', ForcedLayout, '/forced-layout'],
|
||||
|
||||
['DEV:Large', DevLargeDocument, '/dev-large', true],
|
||||
['DEV:Plain', DevPerformancePlain, '/dev-performance-plain', true],
|
||||
|
Loading…
x
Reference in New Issue
Block a user