1
0
mirror of https://github.com/ianstormtaylor/slate.git synced 2025-01-18 22:08:18 +01:00

more work on richtext

This commit is contained in:
Ian Storm Taylor 2016-06-19 00:41:36 -07:00
parent 7435c4019c
commit e293c9794c
6 changed files with 128 additions and 31 deletions

View File

@ -15,6 +15,34 @@ p {
margin: 0;
}
p + p {
.editor p + p {
margin-top: 1em;
}
.menu {
margin: 0 -10px;
padding: 1px 0 9px 7px;
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;
}

View File

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

View File

@ -17,18 +17,7 @@ const state = {
type: 'text',
ranges: [
{
text: 'This is '
},
{
text: 'editable',
marks: [
{
type: 'italic'
}
]
},
{
text: ' '
text: 'This is editable '
},
{
text: 'rich',
@ -39,7 +28,18 @@ const state = {
]
},
{
text: ' text, much better than a '
text: ' text, '
},
{
text: 'much',
marks: [
{
type: 'italic'
}
]
},
{
text: ' better than a '
},
{
text: '<textarea>',
@ -69,18 +69,77 @@ class App extends React.Component {
state: Raw.deserialize(state)
};
isMarkActive(type) {
const { state } = this.state
const { document, selection } = state
const { startKey, startOffset } = selection
const startNode = document.getNode(startKey)
if (!startNode) return false
const { characters } = startNode
const character = characters.get(startOffset)
const { marks } = character
return marks.some(mark => mark.type == type)
}
onClickMark(e, type) {
e.preventDefault()
let { state } = this.state
const { marks } = state
const isActive = this.isMarkActive(type)
state = state
.transform()
[isActive ? 'unmark' : 'mark']()
.apply()
this.onChange(state)
}
render() {
return (
<Editor
state={this.state.state}
renderNode={node => this.renderNode(node)}
renderMark={mark => this.renderMark(mark)}
onChange={(state) => {
console.log('Document:', state.document.toJS())
console.log('Content:', Raw.serialize(state))
this.setState({ state })
}}
/>
<div>
{this.renderToolbar()}
{this.renderEditor()}
</div>
)
}
renderToolbar() {
const isBold = this.isMarkActive('bold')
const isItalic = this.isMarkActive('italic')
const isCode = this.isMarkActive('code')
return (
<div className="menu">
<span className="button" onClick={e => this.onClickMark(e, 'bold')} data-active={isBold}>
<span className="material-icons">format_bold</span>
</span>
<span className="button" onClick={e => this.onClickMark(e, 'italic')} data-active={isItalic}>
<span className="material-icons">format_italic</span>
</span>
<span className="button" onClick={e => this.onClickMark(e, 'code')} data-active={isCode}>
<span className="material-icons">code</span>
</span>
</div>
)
}
renderEditor() {
return (
<div className="editor">
<Editor
state={this.state.state}
renderNode={node => this.renderNode(node)}
renderMark={mark => this.renderMark(mark)}
onChange={(state) => {
console.log('Document:', state.document.toJS())
console.log('Content:', Raw.serialize(state))
this.setState({ state })
}}
/>
</div>
)
}

View File

@ -39,7 +39,7 @@ class Text extends React.Component {
: ranges.map((range, i, ranges) => {
const previous = ranges.slice(0, i)
const offset = previous.size
? previous.map(range => range.get('text')).join('').length
? previous.map(range => range.text).join('').length
: 0
return this.renderLeaf(range, offset)
})
@ -47,8 +47,8 @@ class Text extends React.Component {
renderLeaf(range, offset) {
const { node, renderMark, state } = this.props
const text = range.get('text')
const marks = range.get('marks')
const text = range.text
const marks = range.marks
const start = offset
const end = offset + text.length
const offsetKey = OffsetKey.stringify({

View File

@ -64,7 +64,7 @@ function serializeCharacters(characters) {
.map((range) => {
return {
text: range.text,
mark: serializeMark(range.mark)
marks: range.marks.map(serializeMark)
}
})
}

View File

@ -1,5 +1,14 @@
import { List, Map } from 'immutable'
import { List, Map, Record } from 'immutable'
/**
* Range.
*/
const Range = new Record({
text: '',
marks: new List()
})
/**
* Group a list of `characters` into ranges by the marks they have.
@ -16,7 +25,7 @@ function groupByMarks(characters) {
// The first one can always just be created.
if (i == 0) {
return ranges.push(new Map({ text, marks }))
return ranges.push(new Range({ text, marks }))
}
// Otherwise, compare to the previous and see if a new range should be
@ -37,7 +46,7 @@ function groupByMarks(characters) {
}
// Otherwise, create a new range.
return ranges.push(new Map({ text, marks }))
return ranges.push(new Range({ text, marks }))
}, new List())
}