1
0
mirror of https://github.com/ianstormtaylor/slate.git synced 2025-04-21 13:51:59 +02:00

more stuff, started adding auto-markdown example

This commit is contained in:
Ian Storm Taylor 2016-06-20 19:16:36 -07:00
parent 8bf081d26f
commit eae70f0f17
12 changed files with 389 additions and 22 deletions

@ -27,17 +27,21 @@ dist: ./node_modules $(shell find ./lib)
@ $(babel) --out-dir ./dist ./lib
@ touch ./dist
# Build the auto-markdown example.
example-auto-markdown: ./node_modules
@ $(browserify) --debug --transform babelify --outfile ./examples/auto-markdown/build.js ./examples/auto-markdown/index.js
# Build the basic example.
example-basic: ./node_modules
@ $(browserify) --debug --transform babelify --outfile ./examples/basic/build.js ./examples/basic/index.js
# Build the plaintext example.
example-plaintext: ./node_modules
@ $(browserify) --debug --transform babelify --outfile ./examples/plaintext/build.js ./examples/plaintext/index.js
# Build the plain-text example.
example-plain-text: ./node_modules
@ $(browserify) --debug --transform babelify --outfile ./examples/plain-text/build.js ./examples/plain-text/index.js
# Build the richtext example.
example-richtext: ./node_modules
@ $(browserify) --debug --transform babelify --outfile ./examples/richtext/build.js ./examples/richtext/index.js
# Build the rich-text example.
example-rich-text: ./node_modules
@ $(browserify) --debug --transform babelify --outfile ./examples/rich-text/build.js ./examples/rich-text/index.js
# Lint the sources files with Standard JS.
lint: ./node_modules
@ -63,17 +67,21 @@ test-browser: ./node_modules ./test/support/build.js
test-server: ./node_modules
@ $(mocha) --reporter spec --timeout 5000 ./test/server.js
# Watch the auto-markdown example.
watch-example-auto-markdown: ./node_modules
@ $(MAKE) example-auto-markdown browserify=$(watchify)
# Watch the basic example.
watch-example-basic: ./node_modules
@ $(MAKE) example-basic browserify=$(watchify)
# Watch the plaintext example.
watch-example-plaintext: ./node_modules
@ $(MAKE) example-plaintext browserify=$(watchify)
# Watch the plain-text example.
watch-example-plain-text: ./node_modules
@ $(MAKE) example-plain-text browserify=$(watchify)
# Watch the richtext example.
watch-example-richtext: ./node_modules
@ $(MAKE) example-richtext browserify=$(watchify)
# Watch the rich-text example.
watch-example-rich-text: ./node_modules
@ $(MAKE) example-rich-text browserify=$(watchify)
# Phony targets.
.PHONY: examples

@ -0,0 +1,12 @@
<html>
<head>
<meta charset="utf-8" />
<title>Editor | Auto-markdown Example</title>
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
<link rel="stylesheet" href="index.css">
</head>
<body>
<main></main>
<script src="build.js"></script>
</body>
</html>

@ -0,0 +1,187 @@
import Editor, { Mark, Raw } from '../..'
import React from 'react'
import ReactDOM from 'react-dom'
import keycode from 'keycode'
/**
* State.
*/
const state = {
nodes: [
{
type: 'paragraph',
nodes: [
{
type: 'text',
ranges: [
{
text: 'Since it\'s rich text, you can do things like turn a selection of text ',
}
]
}
]
},
{
type: 'block-quote',
nodes: [
{
type: 'text',
ranges: [
{
text: 'A wise quote.'
}
]
}
]
},
{
type: 'paragraph',
nodes: [
{
type: 'text',
ranges: [
{
text: 'Try it out for yourself!'
}
]
}
]
}
]
}
/**
* App.
*/
class App extends React.Component {
state = {
state: Raw.deserialize(state)
};
render() {
return (
<div className="editor">
<Editor
state={this.state.state}
renderNode={node => this.renderNode(node)}
renderMark={mark => this.renderMark(mark)}
onKeyDown={(e, state) => this.onKeyDown(e, state)}
onChange={(state) => {
console.groupCollapsed('Change!')
console.log('Document:', state.document.toJS())
console.log('Selection:', state.selection.toJS())
console.log('Content:', Raw.serialize(state))
console.groupEnd()
this.setState({ state })
}}
/>
</div>
)
}
renderNode(node) {
switch (node.type) {
case 'block-quote': {
return (props) => <blockquote>{props.children}</blockquote>
}
case 'bulleted-list': {
return (props) => <ul>{props.chidlren}</ul>
}
case 'heading-one': {
return (props) => <h1>{props.children}</h1>
}
case 'heading-two': {
return (props) => <h2>{props.children}</h2>
}
case 'heading-three': {
return (props) => <h3>{props.children}</h3>
}
case 'heading-four': {
return (props) => <h4>{props.children}</h4>
}
case 'heading-five': {
return (props) => <h5>{props.children}</h5>
}
case 'heading-six': {
return (props) => <h6>{props.children}</h6>
}
case 'list-item': {
return (props) => <li>{props.chidlren}</li>
}
case 'numbered-list': {
return (props) => <ol>{props.children}</ol>
}
case 'paragraph': {
return (props) => <p>{props.children}</p>
}
}
}
onKeyDown(e, state) {
const key = keycode(e.which)
if (key != 'space') return
if (state.isCurrentlyExpanded) return
let { selection } = state
const { currentTextNodes, document } = state
const { startOffset } = selection
const node = currentTextNodes.first()
const { text } = node
const chars = text.slice(0, startOffset).replace(/\s*/g, '')
let transform = state.transform()
switch (chars) {
case '#':
transform = transform.setType('header-one')
break
case '##':
transform = transform.setType('header-two')
break
case '###':
transform = transform.setType('header-three')
break
case '####':
transform = transform.setType('header-four')
break
case '#####':
transform = transform.setType('header-five')
break
case '######':
transform = transform.setType('header-six')
break
case '>':
transform = transform.setType('block-quote')
break
case '-':
transform = transform.setType('list-item')
if (wrapper.type == 'paragraph') transform = transform.setType('bulleted-list')
if (wrapper.type == 'bulleted-list') transform = transform.wrap('list-item')
if (wrapper.type == 'list-item') transform = transform.wrap('unordered-list')
break
default:
return
}
state = transform
.deleteAtRange(selection.extendBackwardToStartOf(node))
.apply()
selection = selection.moveToStartOf(node)
state = state.merge({ selection })
e.preventDefault()
return state
}
}
/**
* Attach.
*/
const app = <App />
const root = document.body.querySelector('main')
ReactDOM.render(app, root)

@ -1,7 +1,7 @@
<html>
<head>
<meta charset="utf-8" />
<title>Editor | Plaintext Example</title>
<title>Editor | Plain Text Example</title>
<link rel="stylesheet" href="index.css">
</head>
<body>

@ -0,0 +1,56 @@
html {
background: #eee;
padding: 20px;
}
main {
background: #fff;
padding: 10px;
max-width: 40em;
margin: 0 auto;
}
p {
margin: 0;
}
blockquote {
border-left: 2px solid #ddd;
margin-left: 0;
padding-left: 10px;
color: #aaa;
font-style: italic;
}
.editor > * > * + * {
margin-top: 1em;
}
.menu {
margin: 0 -10px;
padding: 1px 0 9px 8px;
border-bottom: 2px solid #eee;
margin-bottom: 10px;
}
.menu > * {
display: inline-block;
}
.menu > * + * {
margin-left: 10px;
}
.button {
color: #ccc;
cursor: pointer;
}
.button[data-active="true"] {
color: black;
}
.material-icons {
font-size: 18px;
}

@ -1,7 +1,7 @@
<html>
<head>
<meta charset="utf-8" />
<title>Editor | Richtext Example</title>
<title>Editor | Rich Text Example</title>
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
<link rel="stylesheet" href="index.css">
</head>

@ -54,6 +54,55 @@ const state = {
]
}
]
},
{
type: 'paragraph',
nodes: [
{
type: 'text',
ranges: [
{
text: 'Since it\'s rich text, you can do things like turn a selection of text ',
},
{
text: 'bold',
marks: [
{
type: 'bold'
}
]
},{
text: ', or add a semanticlly rendered block quote in the middle of the page, like this:'
}
]
}
]
},
{
type: 'block-quote',
nodes: [
{
type: 'text',
ranges: [
{
text: 'A wise quote.'
}
]
}
]
},
{
type: 'paragraph',
nodes: [
{
type: 'text',
ranges: [
{
text: 'Try it out for yourself!'
}
]
}
]
}
]
}

39
examples/test/index.html Normal file

@ -0,0 +1,39 @@
<html>
<head>
<meta charset="utf-8" />
<title>Editor | Basic Example</title>
<link rel="stylesheet" href="index.css">
</head>
<body>
<main>
<div contenteditable>
<p>
Some text.
</p>
<p>
Some text.
</p>
<blockquote>
<p>
Some text.
</p>
<p>
Some text.
</p>
</blockquote>
<p></p>
<p></p>
<table border>
<tr>
<td>1</td>
<td>one</td>
</tr>
<tr>
<td>2</td>
<td>two</td>
</tr>
</table>
</div>
</main>
</body>
</html>

@ -53,6 +53,26 @@ class State extends Record(DEFAULTS) {
return new State(properties)
}
/**
* Is the current selection collapsed?
*
* @return {Boolean} isCollapsed
*/
get isCurrentlyCollapsed() {
return this.selection.isCollapsed
}
/**
* Is the current selection expanded?
*
* @return {Boolean} isExpanded
*/
get isCurrentlyExpanded() {
return this.selection.isExpanded
}
/**
* Get the characters in the current selection.
*
@ -60,8 +80,7 @@ class State extends Record(DEFAULTS) {
*/
get currentCharacters() {
const { document, selection } = this
return document.getCharactersAtRange(selection)
return this.document.getCharactersAtRange(this.selection)
}
/**
@ -71,8 +90,7 @@ class State extends Record(DEFAULTS) {
*/
get currentMarks() {
const { document, selection } = this
return document.getMarksAtRange(selection)
return this.document.getMarksAtRange(this.selection)
}
/**
@ -82,8 +100,7 @@ class State extends Record(DEFAULTS) {
*/
get currentWrappingNodes() {
const { document, selection, textNodes } = this
return document.getWrappingNodesAtRange(selection)
return this.document.getWrappingNodesAtRange(this.selection)
}
/**
@ -93,8 +110,7 @@ class State extends Record(DEFAULTS) {
*/
get currentTextNodes() {
const { document, selection } = this
return document.getTextNodesAtRange(selection)
return this.document.getTextNodesAtRange(this.selection)
}
/**