1
0
mirror of https://github.com/ianstormtaylor/slate.git synced 2025-03-08 23:09:47 +01:00
Jinxuan Zhu 6e6e9cf710 Fix spell check bug (#1753)
* Fix spell check bug by add data-text:true

* Fix spell check bug by spell check add length to a leaf

* Fix tests to use data-text:true for marks

* Rename data-text to data-slate-leaf; Remove setRef; unlift attributes in leaf

* Update examples with data-*

* Add attributes to document

* Fix renderMark in all documents

* Prettier markdown
2018-04-27 14:06:24 -07:00

209 lines
4.0 KiB
JavaScript

import { Editor } from 'slate-react'
import { Value } from 'slate'
import React from 'react'
import ReactDOM from 'react-dom'
import initialValue from './value.json'
/**
* The menu.
*
* @type {Component}
*/
class Menu extends React.Component {
/**
* Check if the current selection has a mark with `type` in it.
*
* @param {String} type
* @return {Boolean}
*/
hasMark(type) {
const { value } = this.props
return value.activeMarks.some(mark => mark.type == type)
}
/**
* When a mark button is clicked, toggle the current mark.
*
* @param {Event} event
* @param {String} type
*/
onClickMark(event, type) {
const { value, onChange } = this.props
event.preventDefault()
const change = value.change().toggleMark(type)
onChange(change)
}
/**
* Render a mark-toggling toolbar button.
*
* @param {String} type
* @param {String} icon
* @return {Element}
*/
renderMarkButton(type, icon) {
const isActive = this.hasMark(type)
const onMouseDown = event => this.onClickMark(event, type)
return (
// eslint-disable-next-line react/jsx-no-bind
<span className="button" onMouseDown={onMouseDown} data-active={isActive}>
<span className="material-icons">{icon}</span>
</span>
)
}
/**
* Render.
*
* @return {Element}
*/
render() {
const root = window.document.getElementById('root')
return ReactDOM.createPortal(
<div className="menu hover-menu" ref={this.props.menuRef}>
{this.renderMarkButton('bold', 'format_bold')}
{this.renderMarkButton('italic', 'format_italic')}
{this.renderMarkButton('underlined', 'format_underlined')}
{this.renderMarkButton('code', 'code')}
</div>,
root
)
}
}
/**
* The hovering menu example.
*
* @type {Component}
*/
class HoveringMenu extends React.Component {
/**
* Deserialize the raw initial value.
*
* @type {Object}
*/
state = {
value: Value.fromJSON(initialValue),
}
/**
* On update, update the menu.
*/
componentDidMount = () => {
this.updateMenu()
}
componentDidUpdate = () => {
this.updateMenu()
}
/**
* Update the menu's absolute position.
*/
updateMenu = () => {
const { value } = this.state
const menu = this.menu
if (!menu) return
if (value.isBlurred || value.isEmpty) {
menu.removeAttribute('style')
return
}
const selection = window.getSelection()
const range = selection.getRangeAt(0)
const rect = range.getBoundingClientRect()
menu.style.opacity = 1
menu.style.top = `${rect.top + window.pageYOffset - menu.offsetHeight}px`
menu.style.left = `${rect.left +
window.pageXOffset -
menu.offsetWidth / 2 +
rect.width / 2}px`
}
/**
* On change.
*
* @param {Change} change
*/
onChange = ({ value }) => {
this.setState({ value })
}
/**
* Save the `menu` ref.
*
* @param {Menu} menu
*/
menuRef = menu => {
this.menu = menu
}
/**
* Render.
*
* @return {Element}
*/
render() {
return (
<div>
<Menu
menuRef={this.menuRef}
value={this.state.value}
onChange={this.onChange}
/>
<div className="editor">
<Editor
placeholder="Enter some text..."
value={this.state.value}
onChange={this.onChange}
renderMark={this.renderMark}
/>
</div>
</div>
)
}
/**
* Render a Slate mark.
*
* @param {Object} props
* @return {Element}
*/
renderMark = props => {
const { children, mark, attributes } = props
switch (mark.type) {
case 'bold':
return <strong {...attributes}>{children}</strong>
case 'code':
return <code {...attributes}>{children}</code>
case 'italic':
return <em {...attributes}>{children}</em>
case 'underlined':
return <u {...attributes}>{children}</u>
}
}
}
/**
* Export.
*/
export default HoveringMenu