mirror of
https://github.com/ianstormtaylor/slate.git
synced 2025-07-31 04:20:26 +02:00
Improve and refactor examples (#1930)
This just refactors the examples to make the styled defined inline with each example, to make it easier to follow for folks. And in the process fixes a few issues that people brought up. Fixes https://github.com/ianstormtaylor/slate/issues/1920 Fixes https://github.com/ianstormtaylor/slate/issues/1925
This commit is contained in:
@@ -119,7 +119,6 @@
|
||||
"radix": "error",
|
||||
"react/jsx-boolean-value": ["error", "never"],
|
||||
"react/jsx-key": "error",
|
||||
"react/jsx-no-bind": "error",
|
||||
"react/jsx-no-duplicate-props": "error",
|
||||
"react/jsx-no-target-blank": "error",
|
||||
"react/jsx-no-undef": "error",
|
||||
|
199
examples/app.js
199
examples/app.js
@@ -1,5 +1,12 @@
|
||||
import React from 'react'
|
||||
import { HashRouter, NavLink, Route, Redirect, Switch } from 'react-router-dom'
|
||||
import styled from 'react-emotion'
|
||||
import {
|
||||
HashRouter,
|
||||
Link as RouterLink,
|
||||
Route,
|
||||
Redirect,
|
||||
Switch,
|
||||
} from 'react-router-dom'
|
||||
|
||||
import CheckLists from './check-lists'
|
||||
import CodeHighlighting from './code-highlighting'
|
||||
@@ -53,6 +60,83 @@ const EXAMPLES = [
|
||||
['History', History, '/history'],
|
||||
]
|
||||
|
||||
/**
|
||||
* Some styled components.
|
||||
*
|
||||
* @type {Component}
|
||||
*/
|
||||
|
||||
const Nav = styled('div')`
|
||||
padding: 10px 15px;
|
||||
color: #aaa;
|
||||
background: #000;
|
||||
`
|
||||
|
||||
const Title = styled('span')`
|
||||
margin-right: 0.5em;
|
||||
`
|
||||
|
||||
const LinkList = styled('div')`
|
||||
float: right;
|
||||
`
|
||||
|
||||
const Link = styled('a')`
|
||||
margin-left: 1em;
|
||||
color: #aaa;
|
||||
text-decoration: none;
|
||||
|
||||
&:hover {
|
||||
color: #fff;
|
||||
text-decoration: underline;
|
||||
}
|
||||
`
|
||||
|
||||
const TabList = styled('div')`
|
||||
padding: 15px 15px;
|
||||
background-color: #222;
|
||||
text-align: center;
|
||||
margin-bottom: 30px;
|
||||
|
||||
& > * + * {
|
||||
margin-left: 0.5em;
|
||||
}
|
||||
`
|
||||
|
||||
const Tab = styled(RouterLink)`
|
||||
display: inline-block;
|
||||
margin-bottom: 0.2em;
|
||||
padding: 0.2em 0.5em;
|
||||
border-radius: 0.2em;
|
||||
text-decoration: none;
|
||||
color: ${props => (props.active ? 'white' : '#777')};
|
||||
background: ${props => (props.active ? '#333' : 'transparent')};
|
||||
|
||||
&:hover {
|
||||
background: #333;
|
||||
}
|
||||
`
|
||||
|
||||
const Wrapper = styled('div')`
|
||||
max-width: 42em;
|
||||
margin: 0 auto 20px;
|
||||
padding: 20px;
|
||||
`
|
||||
|
||||
const Example = styled(Wrapper)`
|
||||
background: #fff;
|
||||
`
|
||||
|
||||
const Warning = styled(Wrapper)`
|
||||
background: #fffae0;
|
||||
|
||||
& > pre {
|
||||
background: #fbf1bd;
|
||||
white-space: pre;
|
||||
overflow-x: scroll;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
`
|
||||
|
||||
/**
|
||||
* App.
|
||||
*
|
||||
@@ -60,76 +144,81 @@ const EXAMPLES = [
|
||||
*/
|
||||
|
||||
export default class App extends React.Component {
|
||||
/**
|
||||
* Initial state.
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
|
||||
state = {
|
||||
error: null,
|
||||
info: null,
|
||||
}
|
||||
|
||||
/**
|
||||
* Catch the `error` and `info`.
|
||||
*
|
||||
* @param {Error} error
|
||||
* @param {Object} info
|
||||
*/
|
||||
|
||||
componentDidCatch(error, info) {
|
||||
this.setState({ error, info })
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the example app.
|
||||
*
|
||||
* @return {Element}
|
||||
*/
|
||||
|
||||
render() {
|
||||
return (
|
||||
<HashRouter>
|
||||
<div className="app">
|
||||
<div className="nav">
|
||||
<span className="nav-title">Slate Examples</span>
|
||||
<div className="nav-links">
|
||||
<a
|
||||
className="nav-link"
|
||||
href="https://github.com/ianstormtaylor/slate"
|
||||
>
|
||||
GitHub
|
||||
</a>
|
||||
<a className="nav-link" href="https://docs.slatejs.org/">
|
||||
Docs
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div className="tabs">
|
||||
<div>
|
||||
<Nav>
|
||||
<Title>Slate Examples</Title>
|
||||
<LinkList>
|
||||
<Link href="https://github.com/ianstormtaylor/slate">GitHub</Link>
|
||||
<Link href="https://docs.slatejs.org/">Docs</Link>
|
||||
</LinkList>
|
||||
</Nav>
|
||||
<TabList>
|
||||
{EXAMPLES.map(([name, Component, path]) => (
|
||||
<NavLink
|
||||
key={path}
|
||||
to={path}
|
||||
className="tab"
|
||||
activeClassName="active"
|
||||
>
|
||||
{name}
|
||||
</NavLink>
|
||||
<Route key={path} exact path={path}>
|
||||
{({ match }) => (
|
||||
<Tab to={path} active={match && match.isExact}>
|
||||
{name}
|
||||
</Tab>
|
||||
)}
|
||||
</Route>
|
||||
))}
|
||||
</div>
|
||||
{this.state.error ? this.renderError() : this.renderExample()}
|
||||
</TabList>
|
||||
{this.state.error ? (
|
||||
<Warning>
|
||||
<p>
|
||||
An error was thrown by one of the example's React components!
|
||||
</p>
|
||||
<pre>
|
||||
<code>
|
||||
{this.state.error.stack}
|
||||
{'\n'}
|
||||
{this.state.info.componentStack}
|
||||
</code>
|
||||
</pre>
|
||||
</Warning>
|
||||
) : (
|
||||
<Example>
|
||||
<Switch>
|
||||
{EXAMPLES.map(([name, Component, path]) => (
|
||||
<Route key={path} path={path} component={Component} />
|
||||
))}
|
||||
<Redirect from="/" to="/rich-text" />
|
||||
</Switch>
|
||||
</Example>
|
||||
)}
|
||||
</div>
|
||||
</HashRouter>
|
||||
)
|
||||
}
|
||||
|
||||
renderExample() {
|
||||
return (
|
||||
<div className="example">
|
||||
<Switch>
|
||||
{EXAMPLES.map(([name, Component, path]) => (
|
||||
<Route key={path} path={path} component={Component} />
|
||||
))}
|
||||
<Redirect from="/" to="/rich-text" />
|
||||
</Switch>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
renderError() {
|
||||
return (
|
||||
<div className="error">
|
||||
<p>An error was thrown by one of the example's React components!</p>
|
||||
<pre className="info">
|
||||
<code>
|
||||
{this.state.error.stack}
|
||||
{'\n'}
|
||||
{this.state.info.componentStack}
|
||||
</code>
|
||||
</pre>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@@ -3,6 +3,37 @@ import { Value } from 'slate'
|
||||
|
||||
import React from 'react'
|
||||
import initialValue from './value.json'
|
||||
import styled from 'react-emotion'
|
||||
|
||||
/**
|
||||
* Create a few styling components.
|
||||
*
|
||||
* @type {Component}
|
||||
*/
|
||||
|
||||
const ItemWrapper = styled('div')`
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
|
||||
& + & {
|
||||
margin-top: 0;
|
||||
}
|
||||
`
|
||||
|
||||
const CheckboxWrapper = styled('span')`
|
||||
margin-right: 0.75em;
|
||||
`
|
||||
|
||||
const ContentWrapper = styled('span')`
|
||||
flex: 1;
|
||||
opacity: ${props => (props.checked ? 0.666 : 1)};
|
||||
text-decoration: ${props => (props.checked ? 'none' : 'line-through')};
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
}
|
||||
`
|
||||
|
||||
/**
|
||||
* Check list item.
|
||||
@@ -34,18 +65,18 @@ class CheckListItem extends React.Component {
|
||||
const { attributes, children, node, readOnly } = this.props
|
||||
const checked = node.data.get('checked')
|
||||
return (
|
||||
<div
|
||||
className={`check-list-item ${checked ? 'checked' : ''}`}
|
||||
contentEditable={false}
|
||||
{...attributes}
|
||||
>
|
||||
<span>
|
||||
<ItemWrapper {...attributes}>
|
||||
<CheckboxWrapper contentEditable={false}>
|
||||
<input type="checkbox" checked={checked} onChange={this.onChange} />
|
||||
</span>
|
||||
<span contentEditable={!readOnly} suppressContentEditableWarning>
|
||||
</CheckboxWrapper>
|
||||
<ContentWrapper
|
||||
checked={checked}
|
||||
contentEditable={!readOnly}
|
||||
suppressContentEditableWarning
|
||||
>
|
||||
{children}
|
||||
</span>
|
||||
</div>
|
||||
</ContentWrapper>
|
||||
</ItemWrapper>
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -67,6 +98,39 @@ class CheckLists extends React.Component {
|
||||
value: Value.fromJSON(initialValue),
|
||||
}
|
||||
|
||||
/**
|
||||
* Render.
|
||||
*
|
||||
* @return {Element}
|
||||
*/
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Editor
|
||||
spellCheck
|
||||
placeholder="Get to work..."
|
||||
value={this.state.value}
|
||||
onChange={this.onChange}
|
||||
onKeyDown={this.onKeyDown}
|
||||
renderNode={this.renderNode}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a Slate node.
|
||||
*
|
||||
* @param {Object} props
|
||||
* @return {Element}
|
||||
*/
|
||||
|
||||
renderNode = props => {
|
||||
switch (props.node.type) {
|
||||
case 'check-list-item':
|
||||
return <CheckListItem {...props} />
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* On change, save the new value.
|
||||
*
|
||||
@@ -109,43 +173,6 @@ class CheckLists extends React.Component {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Render.
|
||||
*
|
||||
* @return {Element}
|
||||
*/
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<div className="editor">
|
||||
<Editor
|
||||
spellCheck
|
||||
placeholder="Get to work..."
|
||||
value={this.state.value}
|
||||
onChange={this.onChange}
|
||||
onKeyDown={this.onKeyDown}
|
||||
renderNode={this.renderNode}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a Slate node.
|
||||
*
|
||||
* @param {Object} props
|
||||
* @return {Element}
|
||||
*/
|
||||
|
||||
renderNode = props => {
|
||||
switch (props.node.type) {
|
||||
case 'check-list-item':
|
||||
return <CheckListItem {...props} />
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -45,6 +45,23 @@ function CodeBlockLine(props) {
|
||||
return <div {...props.attributes}>{props.children}</div>
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper function to return the content of a Prism `token`.
|
||||
*
|
||||
* @param {Object} token
|
||||
* @return {String}
|
||||
*/
|
||||
|
||||
function getContent(token) {
|
||||
if (typeof token == 'string') {
|
||||
return token
|
||||
} else if (typeof token.content == 'string') {
|
||||
return token.content
|
||||
} else {
|
||||
return token.content.map(getContent).join('')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The code highlighting example.
|
||||
*
|
||||
@@ -62,53 +79,23 @@ class CodeHighlighting extends React.Component {
|
||||
value: Value.fromJSON(initialValue),
|
||||
}
|
||||
|
||||
/**
|
||||
* On change, save the new value.
|
||||
*
|
||||
* @param {Change} change
|
||||
*/
|
||||
|
||||
onChange = ({ value }) => {
|
||||
this.setState({ value })
|
||||
}
|
||||
|
||||
/**
|
||||
* On key down inside code blocks, insert soft new lines.
|
||||
*
|
||||
* @param {Event} event
|
||||
* @param {Change} change
|
||||
* @return {Change}
|
||||
*/
|
||||
|
||||
onKeyDown = (event, change) => {
|
||||
const { value } = change
|
||||
const { startBlock } = value
|
||||
if (event.key != 'Enter') return
|
||||
if (startBlock.type != 'code') return
|
||||
if (value.isExpanded) change.delete()
|
||||
change.insertText('\n')
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* Render.
|
||||
*
|
||||
* @return {Component}
|
||||
*/
|
||||
|
||||
render = () => {
|
||||
render() {
|
||||
return (
|
||||
<div className="editor">
|
||||
<Editor
|
||||
placeholder="Write some code..."
|
||||
value={this.state.value}
|
||||
onChange={this.onChange}
|
||||
onKeyDown={this.onKeyDown}
|
||||
renderNode={this.renderNode}
|
||||
renderMark={this.renderMark}
|
||||
decorateNode={this.decorateNode}
|
||||
/>
|
||||
</div>
|
||||
<Editor
|
||||
placeholder="Write some code..."
|
||||
value={this.state.value}
|
||||
onChange={this.onChange}
|
||||
onKeyDown={this.onKeyDown}
|
||||
renderNode={this.renderNode}
|
||||
renderMark={this.renderMark}
|
||||
decorateNode={this.decorateNode}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -166,14 +153,32 @@ class CodeHighlighting extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
tokenToContent = token => {
|
||||
if (typeof token == 'string') {
|
||||
return token
|
||||
} else if (typeof token.content == 'string') {
|
||||
return token.content
|
||||
} else {
|
||||
return token.content.map(this.tokenToContent).join('')
|
||||
}
|
||||
/**
|
||||
* On change, save the new value.
|
||||
*
|
||||
* @param {Change} change
|
||||
*/
|
||||
|
||||
onChange = ({ value }) => {
|
||||
this.setState({ value })
|
||||
}
|
||||
|
||||
/**
|
||||
* On key down inside code blocks, insert soft new lines.
|
||||
*
|
||||
* @param {Event} event
|
||||
* @param {Change} change
|
||||
* @return {Change}
|
||||
*/
|
||||
|
||||
onKeyDown = (event, change) => {
|
||||
const { value } = change
|
||||
const { startBlock } = value
|
||||
if (event.key != 'Enter') return
|
||||
if (startBlock.type != 'code') return
|
||||
if (value.isExpanded) change.delete()
|
||||
change.insertText('\n')
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -202,7 +207,7 @@ class CodeHighlighting extends React.Component {
|
||||
startText = endText
|
||||
startOffset = endOffset
|
||||
|
||||
const content = this.tokenToContent(token)
|
||||
const content = getContent(token)
|
||||
const newlines = content.split('\n').length - 1
|
||||
const length = content.length - newlines
|
||||
const end = start + length
|
||||
|
35
examples/components.js
Normal file
35
examples/components.js
Normal file
@@ -0,0 +1,35 @@
|
||||
import React from 'react'
|
||||
import styled from 'react-emotion'
|
||||
|
||||
export const Button = styled('span')`
|
||||
cursor: pointer;
|
||||
color: ${props =>
|
||||
props.reversed
|
||||
? props.active ? 'white' : '#aaa'
|
||||
: props.active ? 'black' : '#ccc'};
|
||||
`
|
||||
|
||||
export const Icon = styled(({ className, ...rest }) => {
|
||||
return <span className={`material-icons ${className}`} {...rest} />
|
||||
})`
|
||||
font-size: 18px;
|
||||
vertical-align: text-bottom;
|
||||
`
|
||||
|
||||
export const Menu = styled('div')`
|
||||
& > * {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
& > * + * {
|
||||
margin-left: 15px;
|
||||
}
|
||||
`
|
||||
|
||||
export const Toolbar = styled(Menu)`
|
||||
position: relative;
|
||||
padding: 1px 18px 17px;
|
||||
margin: 0 -20px;
|
||||
border-bottom: 2px solid #eee;
|
||||
margin-bottom: 20px;
|
||||
`
|
@@ -22,16 +22,6 @@ class Embeds extends React.Component {
|
||||
value: Value.fromJSON(initialValue),
|
||||
}
|
||||
|
||||
/**
|
||||
* On change.
|
||||
*
|
||||
* @param {Change} change
|
||||
*/
|
||||
|
||||
onChange = ({ value }) => {
|
||||
this.setState({ value })
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the app.
|
||||
*
|
||||
@@ -40,14 +30,12 @@ class Embeds extends React.Component {
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="editor">
|
||||
<Editor
|
||||
placeholder="Enter some text..."
|
||||
value={this.state.value}
|
||||
onChange={this.onChange}
|
||||
renderNode={this.renderNode}
|
||||
/>
|
||||
</div>
|
||||
<Editor
|
||||
placeholder="Enter some text..."
|
||||
value={this.state.value}
|
||||
onChange={this.onChange}
|
||||
renderNode={this.renderNode}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -64,6 +52,16 @@ class Embeds extends React.Component {
|
||||
return <Video {...props} />
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* On change.
|
||||
*
|
||||
* @param {Change} change
|
||||
*/
|
||||
|
||||
onChange = ({ value }) => {
|
||||
this.setState({ value })
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -3,6 +3,18 @@ import { Value } from 'slate'
|
||||
|
||||
import React from 'react'
|
||||
import initialValue from './value.json'
|
||||
import styled from 'react-emotion'
|
||||
import { Button, Icon, Toolbar } from '../components'
|
||||
|
||||
/**
|
||||
* A styled emoji inline component.
|
||||
*
|
||||
* @type {Component}
|
||||
*/
|
||||
|
||||
const Emoji = styled('span')`
|
||||
outline: ${props => (props.selected ? '2px solid blue' : 'none')};
|
||||
`
|
||||
|
||||
/**
|
||||
* Emojis.
|
||||
@@ -27,7 +39,6 @@ const EMOJIS = [
|
||||
'👻',
|
||||
'🍔',
|
||||
'🍑',
|
||||
'🍆',
|
||||
'🔑',
|
||||
]
|
||||
|
||||
@@ -56,6 +67,62 @@ class Emojis extends React.Component {
|
||||
value: Value.fromJSON(initialValue),
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the app.
|
||||
*
|
||||
* @return {Element} element
|
||||
*/
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<Toolbar>
|
||||
{EMOJIS.map((emoji, i) => (
|
||||
<Button key={i} onMouseDown={e => this.onClickEmoji(e, emoji)}>
|
||||
<Icon>{emoji}</Icon>
|
||||
</Button>
|
||||
))}
|
||||
</Toolbar>
|
||||
<Editor
|
||||
placeholder="Write some 😍👋🎉..."
|
||||
value={this.state.value}
|
||||
onChange={this.onChange}
|
||||
renderNode={this.renderNode}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a Slate node.
|
||||
*
|
||||
* @param {Object} props
|
||||
* @return {Element}
|
||||
*/
|
||||
|
||||
renderNode = props => {
|
||||
const { attributes, children, node, isSelected } = props
|
||||
|
||||
switch (node.type) {
|
||||
case 'paragraph': {
|
||||
return <p {...attributes}>{children}</p>
|
||||
}
|
||||
case 'emoji': {
|
||||
const code = node.data.get('code')
|
||||
return (
|
||||
<Emoji
|
||||
{...props.attributes}
|
||||
selected={isSelected}
|
||||
contentEditable={false}
|
||||
onDrop={noop}
|
||||
>
|
||||
{code}
|
||||
</Emoji>
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* On change.
|
||||
*
|
||||
@@ -88,93 +155,6 @@ class Emojis extends React.Component {
|
||||
|
||||
this.onChange(change)
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the app.
|
||||
*
|
||||
* @return {Element} element
|
||||
*/
|
||||
|
||||
render = () => {
|
||||
return (
|
||||
<div>
|
||||
{this.renderToolbar()}
|
||||
{this.renderEditor()}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the toolbar.
|
||||
*
|
||||
* @return {Element} element
|
||||
*/
|
||||
|
||||
renderToolbar = () => {
|
||||
return (
|
||||
<div className="menu toolbar-menu">
|
||||
{EMOJIS.map((emoji, i) => {
|
||||
const onMouseDown = e => this.onClickEmoji(e, emoji)
|
||||
return (
|
||||
// eslint-disable-next-line react/jsx-no-bind
|
||||
<span key={i} className="button" onMouseDown={onMouseDown}>
|
||||
<span className="material-icons">{emoji}</span>
|
||||
</span>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the editor.
|
||||
*
|
||||
* @return {Element} element
|
||||
*/
|
||||
|
||||
renderEditor = () => {
|
||||
return (
|
||||
<div className="editor">
|
||||
<Editor
|
||||
placeholder="Write some 😍👋🎉..."
|
||||
value={this.state.value}
|
||||
onChange={this.onChange}
|
||||
renderNode={this.renderNode}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a Slate node.
|
||||
*
|
||||
* @param {Object} props
|
||||
* @return {Element}
|
||||
*/
|
||||
|
||||
renderNode = props => {
|
||||
const { attributes, children, node, isSelected } = props
|
||||
|
||||
switch (node.type) {
|
||||
case 'paragraph': {
|
||||
return <p {...attributes}>{children}</p>
|
||||
}
|
||||
case 'emoji': {
|
||||
const { data } = node
|
||||
const code = data.get('code')
|
||||
return (
|
||||
<span
|
||||
className={`emoji ${isSelected ? 'selected' : ''}`}
|
||||
{...props.attributes}
|
||||
contentEditable={false}
|
||||
onDrop={noop}
|
||||
>
|
||||
{code}
|
||||
</span>
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -51,16 +51,6 @@ class ForcedLayout extends React.Component {
|
||||
value: Value.fromJSON(initialValue),
|
||||
}
|
||||
|
||||
/**
|
||||
* On change.
|
||||
*
|
||||
* @param {Change} change
|
||||
*/
|
||||
|
||||
onChange = ({ value }) => {
|
||||
this.setState({ value })
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the editor.
|
||||
*
|
||||
@@ -69,15 +59,13 @@ class ForcedLayout extends React.Component {
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="editor">
|
||||
<Editor
|
||||
placeholder="Enter a title..."
|
||||
value={this.state.value}
|
||||
schema={schema}
|
||||
onChange={this.onChange}
|
||||
renderNode={this.renderNode}
|
||||
/>
|
||||
</div>
|
||||
<Editor
|
||||
placeholder="Enter a title..."
|
||||
value={this.state.value}
|
||||
schema={schema}
|
||||
onChange={this.onChange}
|
||||
renderNode={this.renderNode}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -98,6 +86,16 @@ class ForcedLayout extends React.Component {
|
||||
return <p {...attributes}>{children}</p>
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* On change.
|
||||
*
|
||||
* @param {Change} change
|
||||
*/
|
||||
|
||||
onChange = ({ value }) => {
|
||||
this.setState({ value })
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -3,18 +3,7 @@ import { Editor } from 'slate-react'
|
||||
|
||||
import React from 'react'
|
||||
import initialValue from './value.json'
|
||||
|
||||
/**
|
||||
* Toolbar button component.
|
||||
*
|
||||
* @type {Function}
|
||||
*/
|
||||
|
||||
const ToolbarButton = props => (
|
||||
<span className="button" onMouseDown={props.onMouseDown}>
|
||||
<span className="material-icons">{props.icon}</span>
|
||||
</span>
|
||||
)
|
||||
import { Button, Icon, Toolbar } from '../components'
|
||||
|
||||
/**
|
||||
* The history example.
|
||||
@@ -33,6 +22,36 @@ class History extends React.Component {
|
||||
value: Value.fromJSON(initialValue),
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the editor.
|
||||
*
|
||||
* @return {Component} component
|
||||
*/
|
||||
|
||||
render() {
|
||||
const { value } = this.state
|
||||
const { history } = value
|
||||
return (
|
||||
<div>
|
||||
<Toolbar>
|
||||
<Button onMouseDown={this.onClickUndo}>
|
||||
<Icon>undo</Icon>
|
||||
</Button>
|
||||
<Button onMouseDown={this.onClickRedo}>
|
||||
<Icon>redo</Icon>
|
||||
</Button>
|
||||
<span>Undos: {history.undos.size}</span>
|
||||
<span>Redos: {history.redos.size}</span>
|
||||
</Toolbar>
|
||||
<Editor
|
||||
placeholder="Enter some text..."
|
||||
value={this.state.value}
|
||||
onChange={this.onChange}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* On change.
|
||||
*
|
||||
@@ -66,57 +85,6 @@ class History extends React.Component {
|
||||
const change = value.change().undo()
|
||||
this.onChange(change)
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the editor.
|
||||
*
|
||||
* @return {Component} component
|
||||
*/
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="editor">
|
||||
{this.renderToolbar()}
|
||||
{this.renderEditor()}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the toolbar.
|
||||
*
|
||||
* @return {Element}
|
||||
*/
|
||||
|
||||
renderToolbar = () => {
|
||||
const { value } = this.state
|
||||
return (
|
||||
<div className="menu toolbar-menu">
|
||||
<ToolbarButton icon="undo" onMouseDown={this.onClickUndo} />
|
||||
<ToolbarButton icon="redo" onMouseDown={this.onClickRedo} />
|
||||
<span className="button">Undos: {value.history.undos.size}</span>
|
||||
<span className="button">Redos: {value.history.redos.size}</span>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the Slate editor.
|
||||
*
|
||||
* @return {Element}
|
||||
*/
|
||||
|
||||
renderEditor = () => {
|
||||
return (
|
||||
<div className="editor">
|
||||
<Editor
|
||||
placeholder="Enter some text..."
|
||||
value={this.state.value}
|
||||
onChange={this.onChange}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -4,24 +4,76 @@ import { Value } from 'slate'
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import initialValue from './value.json'
|
||||
import styled from 'react-emotion'
|
||||
import { Button, Icon, Menu } from '../components'
|
||||
|
||||
/**
|
||||
* The menu.
|
||||
* Give the menu some styles.
|
||||
*
|
||||
* @type {Component}
|
||||
*/
|
||||
|
||||
class Menu extends React.Component {
|
||||
const StyledMenu = styled(Menu)`
|
||||
padding: 8px 7px 6px;
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
top: -10000px;
|
||||
left: -10000px;
|
||||
margin-top: -6px;
|
||||
opacity: 0;
|
||||
background-color: #222;
|
||||
border-radius: 4px;
|
||||
transition: opacity 0.75s;
|
||||
`
|
||||
|
||||
/**
|
||||
* The hovering menu.
|
||||
*
|
||||
* @type {Component}
|
||||
*/
|
||||
|
||||
class HoverMenu extends React.Component {
|
||||
/**
|
||||
* Check if the current selection has a mark with `type` in it.
|
||||
* Render.
|
||||
*
|
||||
* @param {String} type
|
||||
* @return {Boolean}
|
||||
* @return {Element}
|
||||
*/
|
||||
|
||||
hasMark(type) {
|
||||
render() {
|
||||
const { className, innerRef } = this.props
|
||||
const root = window.document.getElementById('root')
|
||||
|
||||
return ReactDOM.createPortal(
|
||||
<StyledMenu className={className} innerRef={innerRef}>
|
||||
{this.renderMarkButton('bold', 'format_bold')}
|
||||
{this.renderMarkButton('italic', 'format_italic')}
|
||||
{this.renderMarkButton('underlined', 'format_underlined')}
|
||||
{this.renderMarkButton('code', 'code')}
|
||||
</StyledMenu>,
|
||||
root
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a mark-toggling toolbar button.
|
||||
*
|
||||
* @param {String} type
|
||||
* @param {String} icon
|
||||
* @return {Element}
|
||||
*/
|
||||
|
||||
renderMarkButton(type, icon) {
|
||||
const { value } = this.props
|
||||
return value.activeMarks.some(mark => mark.type == type)
|
||||
const isActive = value.activeMarks.some(mark => mark.type == type)
|
||||
return (
|
||||
<Button
|
||||
reversed
|
||||
active={isActive}
|
||||
onMouseDown={event => this.onClickMark(event, type)}
|
||||
>
|
||||
<Icon>{icon}</Icon>
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -37,46 +89,6 @@ class Menu extends React.Component {
|
||||
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
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -134,26 +146,6 @@ class HoveringMenu extends React.Component {
|
||||
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.
|
||||
*
|
||||
@@ -163,19 +155,17 @@ class HoveringMenu extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<Menu
|
||||
menuRef={this.menuRef}
|
||||
<HoverMenu
|
||||
innerRef={menu => (this.menu = menu)}
|
||||
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>
|
||||
<Editor
|
||||
placeholder="Enter some text..."
|
||||
value={this.state.value}
|
||||
onChange={this.onChange}
|
||||
renderMark={this.renderMark}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -201,6 +191,16 @@ class HoveringMenu extends React.Component {
|
||||
return <u {...attributes}>{children}</u>
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* On change.
|
||||
*
|
||||
* @param {Change} change
|
||||
*/
|
||||
|
||||
onChange = ({ value }) => {
|
||||
this.setState({ value })
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -48,22 +48,7 @@ class HugeDocument extends React.Component {
|
||||
* @type {Object}
|
||||
*/
|
||||
|
||||
constructor() {
|
||||
super()
|
||||
console.time('deserializeHugeDocument')
|
||||
this.state = { value: Value.fromJSON(json, { normalize: false }) }
|
||||
console.timeEnd('deserializeHugeDocument')
|
||||
}
|
||||
|
||||
/**
|
||||
* On change.
|
||||
*
|
||||
* @param {Change} change
|
||||
*/
|
||||
|
||||
onChange = ({ value }) => {
|
||||
this.setState({ value })
|
||||
}
|
||||
state = { value: Value.fromJSON(json, { normalize: false }) }
|
||||
|
||||
/**
|
||||
* Render the editor.
|
||||
@@ -73,17 +58,14 @@ class HugeDocument extends React.Component {
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="editor">
|
||||
<Editor
|
||||
placeholder="Enter some text..."
|
||||
spellCheck={false}
|
||||
value={this.state.value}
|
||||
onChange={this.onChange}
|
||||
onKeyDown={this.onKeyDown}
|
||||
renderNode={this.renderNode}
|
||||
renderMark={this.renderMark}
|
||||
/>
|
||||
</div>
|
||||
<Editor
|
||||
placeholder="Enter some text..."
|
||||
spellCheck={false}
|
||||
value={this.state.value}
|
||||
onChange={this.onChange}
|
||||
renderNode={this.renderNode}
|
||||
renderMark={this.renderMark}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -124,6 +106,16 @@ class HugeDocument extends React.Component {
|
||||
return <u {...attributes}>{children}</u>
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* On change.
|
||||
*
|
||||
* @param {Change} change
|
||||
*/
|
||||
|
||||
onChange = ({ value }) => {
|
||||
this.setState({ value })
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -6,6 +6,21 @@ import React from 'react'
|
||||
import initialValue from './value.json'
|
||||
import imageExtensions from 'image-extensions'
|
||||
import isUrl from 'is-url'
|
||||
import styled from 'react-emotion'
|
||||
import { Button, Icon, Toolbar } from '../components'
|
||||
|
||||
/**
|
||||
* A styled image block component.
|
||||
*
|
||||
* @type {Component}
|
||||
*/
|
||||
|
||||
const Image = styled('img')`
|
||||
display: block;
|
||||
max-width: 100%;
|
||||
max-height: 20em;
|
||||
box-shadow: ${props => (props.selected ? '0 0 0 2px blue;' : 'none')};
|
||||
`
|
||||
|
||||
/*
|
||||
* A function to determine whether a URL has an image extension.
|
||||
@@ -84,37 +99,11 @@ class Images extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
{this.renderToolbar()}
|
||||
{this.renderEditor()}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the toolbar.
|
||||
*
|
||||
* @return {Element} element
|
||||
*/
|
||||
|
||||
renderToolbar = () => {
|
||||
return (
|
||||
<div className="menu toolbar-menu">
|
||||
<span className="button" onMouseDown={this.onClickImage}>
|
||||
<span className="material-icons">image</span>
|
||||
</span>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the editor.
|
||||
*
|
||||
* @return {Element} element
|
||||
*/
|
||||
|
||||
renderEditor = () => {
|
||||
return (
|
||||
<div className="editor">
|
||||
<Toolbar>
|
||||
<Button onMouseDown={this.onClickImage}>
|
||||
<Icon>image</Icon>
|
||||
</Button>
|
||||
</Toolbar>
|
||||
<Editor
|
||||
placeholder="Enter some text..."
|
||||
value={this.state.value}
|
||||
@@ -141,11 +130,7 @@ class Images extends React.Component {
|
||||
switch (node.type) {
|
||||
case 'image': {
|
||||
const src = node.data.get('src')
|
||||
const className = isSelected ? 'active' : null
|
||||
const style = { display: 'block' }
|
||||
return (
|
||||
<img src={src} className={className} style={style} {...attributes} />
|
||||
)
|
||||
return <Image src={src} selected={isSelected} {...attributes} />
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -31,10 +31,6 @@ img {
|
||||
max-height: 20em;
|
||||
}
|
||||
|
||||
img.active {
|
||||
box-shadow: 0 0 0 2px blue;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
border-left: 2px solid #ddd;
|
||||
margin-left: 0;
|
||||
@@ -74,199 +70,6 @@ input:focus {
|
||||
border-color: blue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Icons.
|
||||
*/
|
||||
|
||||
.material-icons {
|
||||
font-size: 18px;
|
||||
vertical-align: text-bottom;
|
||||
}
|
||||
|
||||
/**
|
||||
* App.
|
||||
*/
|
||||
|
||||
.nav {
|
||||
padding: 10px 15px;
|
||||
color: #aaa;
|
||||
background: #000;
|
||||
}
|
||||
|
||||
.nav-title {
|
||||
margin-right: 0.5em;
|
||||
}
|
||||
|
||||
.nav-links {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.nav-link {
|
||||
margin-left: 1em;
|
||||
color: #aaa;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.nav-link:hover {
|
||||
color: #fff;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.tabs {
|
||||
padding: 15px 15px;
|
||||
background-color: #222;
|
||||
text-align: center;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.tab {
|
||||
color: #777;
|
||||
display: inline-block;
|
||||
text-decoration: none;
|
||||
padding: 0.2em 0.5em;
|
||||
border-radius: 0.2em;
|
||||
margin-bottom: 0.2em;
|
||||
}
|
||||
|
||||
.tab:hover {
|
||||
background: #333;
|
||||
}
|
||||
|
||||
.tab + .tab {
|
||||
margin-left: 0.5em;
|
||||
}
|
||||
|
||||
.tab.active {
|
||||
color: white;
|
||||
background: #333;
|
||||
}
|
||||
|
||||
/**
|
||||
* Example.
|
||||
*/
|
||||
|
||||
.example,
|
||||
.error {
|
||||
max-width: 42em;
|
||||
margin: 0 auto 20px;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.example {
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.error {
|
||||
background: #fffae0;
|
||||
}
|
||||
|
||||
.error .info {
|
||||
background: #fbf1bd;
|
||||
white-space: pre;
|
||||
overflow-x: scroll;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.editor > * > * + * {
|
||||
[data-slate-editor] > * + * {
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
.menu > * {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.menu > * + * {
|
||||
margin-left: 15px;
|
||||
}
|
||||
|
||||
.button {
|
||||
color: #ccc;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.button[data-active='true'] {
|
||||
color: black;
|
||||
}
|
||||
|
||||
.toolbar-menu {
|
||||
position: relative;
|
||||
padding: 1px 18px 17px;
|
||||
margin: 0 -20px;
|
||||
border-bottom: 2px solid #eee;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.toolbar-menu .search {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.toolbar-menu .search-icon {
|
||||
position: absolute;
|
||||
top: 0.5em;
|
||||
left: 0.5em;
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
.toolbar-menu .search-box {
|
||||
padding-left: 2em;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.hover-menu {
|
||||
padding: 8px 7px 6px;
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
top: -10000px;
|
||||
left: -10000px;
|
||||
margin-top: -6px;
|
||||
opacity: 0;
|
||||
background-color: #222;
|
||||
border-radius: 4px;
|
||||
transition: opacity 0.75s;
|
||||
}
|
||||
|
||||
.hover-menu .button {
|
||||
color: #aaa;
|
||||
}
|
||||
|
||||
.hover-menu .button[data-active='true'] {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.emoji.selected {
|
||||
outline: 2px solid blue;
|
||||
}
|
||||
|
||||
.check-list-item + .check-list-item {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.check-list-item {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.check-list-item.checked {
|
||||
opacity: 0.666;
|
||||
text-decoration: line-through;
|
||||
}
|
||||
|
||||
.check-list-item > span:first-child {
|
||||
margin-right: 0.75em;
|
||||
}
|
||||
|
||||
.check-list-item > span:last-child {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.check-list-item > span:last-child:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.word-counter {
|
||||
margin-top: 10px;
|
||||
padding: 12px;
|
||||
background-color: #ebebeb;
|
||||
display: inline-block;
|
||||
}
|
||||
|
@@ -5,7 +5,7 @@ import App from './app'
|
||||
import './index.css'
|
||||
|
||||
/**
|
||||
* Mount the router.
|
||||
* Render the app.
|
||||
*/
|
||||
|
||||
const root = window.document.createElement('div')
|
||||
@@ -23,7 +23,10 @@ const render = Component => {
|
||||
|
||||
render(App)
|
||||
|
||||
// Webpack Hot Module Replacement API
|
||||
/**
|
||||
* Re-render for hot module replacement in development.
|
||||
*/
|
||||
|
||||
if (module.hot) {
|
||||
module.hot.accept('./app', () => render(App))
|
||||
}
|
||||
|
@@ -4,6 +4,7 @@ import { Value } from 'slate'
|
||||
import React from 'react'
|
||||
import initialValue from './value.json'
|
||||
import isUrl from 'is-url'
|
||||
import { Button, Icon, Toolbar } from '../components'
|
||||
|
||||
/**
|
||||
* A change helper to standardize wrapping links.
|
||||
@@ -59,6 +60,54 @@ class Links extends React.Component {
|
||||
return value.inlines.some(inline => inline.type == 'link')
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the app.
|
||||
*
|
||||
* @return {Element} element
|
||||
*/
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<Toolbar>
|
||||
<Button active={this.hasLinks()} onMouseDown={this.onClickLink}>
|
||||
<Icon>link</Icon>
|
||||
</Button>
|
||||
</Toolbar>
|
||||
<Editor
|
||||
placeholder="Enter some text..."
|
||||
value={this.state.value}
|
||||
onChange={this.onChange}
|
||||
onPaste={this.onPaste}
|
||||
renderNode={this.renderNode}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a Slate node.
|
||||
*
|
||||
* @param {Object} props
|
||||
* @return {Element}
|
||||
*/
|
||||
|
||||
renderNode = props => {
|
||||
const { attributes, children, node } = props
|
||||
|
||||
switch (node.type) {
|
||||
case 'link': {
|
||||
const { data } = node
|
||||
const href = data.get('href')
|
||||
return (
|
||||
<a {...attributes} href={href}>
|
||||
{children}
|
||||
</a>
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* On change.
|
||||
*
|
||||
@@ -122,85 +171,6 @@ class Links extends React.Component {
|
||||
change.call(wrapLink, text)
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the app.
|
||||
*
|
||||
* @return {Element} element
|
||||
*/
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
{this.renderToolbar()}
|
||||
{this.renderEditor()}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the toolbar.
|
||||
*
|
||||
* @return {Element} element
|
||||
*/
|
||||
|
||||
renderToolbar = () => {
|
||||
const hasLinks = this.hasLinks()
|
||||
return (
|
||||
<div className="menu toolbar-menu">
|
||||
<span
|
||||
className="button"
|
||||
onMouseDown={this.onClickLink}
|
||||
data-active={hasLinks}
|
||||
>
|
||||
<span className="material-icons">link</span>
|
||||
</span>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the editor.
|
||||
*
|
||||
* @return {Element} element
|
||||
*/
|
||||
|
||||
renderEditor = () => {
|
||||
return (
|
||||
<div className="editor">
|
||||
<Editor
|
||||
placeholder="Enter some text..."
|
||||
value={this.state.value}
|
||||
onChange={this.onChange}
|
||||
onPaste={this.onPaste}
|
||||
renderNode={this.renderNode}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a Slate node.
|
||||
*
|
||||
* @param {Object} props
|
||||
* @return {Element}
|
||||
*/
|
||||
|
||||
renderNode = props => {
|
||||
const { attributes, children, node } = props
|
||||
|
||||
switch (node.type) {
|
||||
case 'link': {
|
||||
const { data } = node
|
||||
const href = data.get('href')
|
||||
return (
|
||||
<a {...attributes} href={href}>
|
||||
{children}
|
||||
</a>
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -30,16 +30,6 @@ class MarkdownPreview extends React.Component {
|
||||
),
|
||||
}
|
||||
|
||||
/**
|
||||
* On change.
|
||||
*
|
||||
* @param {Change} change
|
||||
*/
|
||||
|
||||
onChange = ({ value }) => {
|
||||
this.setState({ value })
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Render the example.
|
||||
@@ -49,15 +39,13 @@ class MarkdownPreview extends React.Component {
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="editor">
|
||||
<Editor
|
||||
placeholder="Write some markdown..."
|
||||
value={this.state.value}
|
||||
onChange={this.onChange}
|
||||
renderMark={this.renderMark}
|
||||
decorateNode={this.decorateNode}
|
||||
/>
|
||||
</div>
|
||||
<Editor
|
||||
placeholder="Write some markdown..."
|
||||
value={this.state.value}
|
||||
onChange={this.onChange}
|
||||
renderMark={this.renderMark}
|
||||
decorateNode={this.decorateNode}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -133,6 +121,16 @@ class MarkdownPreview extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* On change.
|
||||
*
|
||||
* @param {Change} change
|
||||
*/
|
||||
|
||||
onChange = ({ value }) => {
|
||||
this.setState({ value })
|
||||
}
|
||||
|
||||
/**
|
||||
* Define a decorator for markdown styles.
|
||||
*
|
||||
|
@@ -62,15 +62,13 @@ class MarkdownShortcuts extends React.Component {
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="editor">
|
||||
<Editor
|
||||
placeholder="Write some markdown..."
|
||||
value={this.state.value}
|
||||
onChange={this.onChange}
|
||||
onKeyDown={this.onKeyDown}
|
||||
renderNode={this.renderNode}
|
||||
/>
|
||||
</div>
|
||||
<Editor
|
||||
placeholder="Write some markdown..."
|
||||
value={this.state.value}
|
||||
onChange={this.onChange}
|
||||
onKeyDown={this.onKeyDown}
|
||||
renderNode={this.renderNode}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
|
@@ -4,6 +4,7 @@ import { Value } from 'slate'
|
||||
|
||||
import React from 'react'
|
||||
import initialValue from './value.json'
|
||||
import styled from 'react-emotion'
|
||||
|
||||
/**
|
||||
* Tags to blocks.
|
||||
@@ -40,6 +41,19 @@ const MARK_TAGS = {
|
||||
code: 'code',
|
||||
}
|
||||
|
||||
/**
|
||||
* A styled image block component.
|
||||
*
|
||||
* @type {Component}
|
||||
*/
|
||||
|
||||
const Image = styled('img')`
|
||||
display: block;
|
||||
max-width: 100%;
|
||||
max-height: 20em;
|
||||
box-shadow: ${props => (props.selected ? '0 0 0 2px blue;' : 'none')};
|
||||
`
|
||||
|
||||
/**
|
||||
* Serializer rules.
|
||||
*
|
||||
@@ -149,31 +163,6 @@ class PasteHtml extends React.Component {
|
||||
value: Value.fromJSON(initialValue),
|
||||
}
|
||||
|
||||
/**
|
||||
* On change, save the new value.
|
||||
*
|
||||
* @param {Change} change
|
||||
*/
|
||||
|
||||
onChange = ({ value }) => {
|
||||
this.setState({ value })
|
||||
}
|
||||
|
||||
/**
|
||||
* On paste, deserialize the HTML and then insert the fragment.
|
||||
*
|
||||
* @param {Event} event
|
||||
* @param {Change} change
|
||||
*/
|
||||
|
||||
onPaste = (event, change) => {
|
||||
const transfer = getEventTransfer(event)
|
||||
if (transfer.type != 'html') return
|
||||
const { document } = serializer.deserialize(transfer.html)
|
||||
change.insertFragment(document)
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* Render.
|
||||
*
|
||||
@@ -182,16 +171,14 @@ class PasteHtml extends React.Component {
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="editor">
|
||||
<Editor
|
||||
placeholder="Paste in some HTML..."
|
||||
value={this.state.value}
|
||||
onPaste={this.onPaste}
|
||||
onChange={this.onChange}
|
||||
renderNode={this.renderNode}
|
||||
renderMark={this.renderMark}
|
||||
/>
|
||||
</div>
|
||||
<Editor
|
||||
placeholder="Paste in some HTML..."
|
||||
value={this.state.value}
|
||||
onPaste={this.onPaste}
|
||||
onChange={this.onChange}
|
||||
renderNode={this.renderNode}
|
||||
renderMark={this.renderMark}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -243,11 +230,7 @@ class PasteHtml extends React.Component {
|
||||
}
|
||||
case 'image': {
|
||||
const src = node.data.get('src')
|
||||
const className = isSelected ? 'active' : null
|
||||
const style = { display: 'block' }
|
||||
return (
|
||||
<img src={src} className={className} style={style} {...attributes} />
|
||||
)
|
||||
return <Image src={src} selected={isSelected} {...attributes} />
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -273,6 +256,31 @@ class PasteHtml extends React.Component {
|
||||
return <u {...attributes}>{children}</u>
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* On change, save the new value.
|
||||
*
|
||||
* @param {Change} change
|
||||
*/
|
||||
|
||||
onChange = ({ value }) => {
|
||||
this.setState({ value })
|
||||
}
|
||||
|
||||
/**
|
||||
* On paste, deserialize the HTML and then insert the fragment.
|
||||
*
|
||||
* @param {Event} event
|
||||
* @param {Change} change
|
||||
*/
|
||||
|
||||
onPaste = (event, change) => {
|
||||
const transfer = getEventTransfer(event)
|
||||
if (transfer.type != 'html') return
|
||||
const { document } = serializer.deserialize(transfer.html)
|
||||
change.insertFragment(document)
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -22,6 +22,22 @@ class PlainText extends React.Component {
|
||||
),
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the editor.
|
||||
*
|
||||
* @return {Component} component
|
||||
*/
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Editor
|
||||
placeholder="Enter some plain text..."
|
||||
value={this.state.value}
|
||||
onChange={this.onChange}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* On change.
|
||||
*
|
||||
@@ -31,24 +47,6 @@ class PlainText extends React.Component {
|
||||
onChange = ({ value }) => {
|
||||
this.setState({ value })
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the editor.
|
||||
*
|
||||
* @return {Component} component
|
||||
*/
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="editor">
|
||||
<Editor
|
||||
placeholder="Enter some plain text..."
|
||||
value={this.state.value}
|
||||
onChange={this.onChange}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -4,6 +4,20 @@ import { Editor } from 'slate-react'
|
||||
import React from 'react'
|
||||
import CollapseOnEscape from 'slate-collapse-on-escape'
|
||||
import SoftBreak from 'slate-soft-break'
|
||||
import styled from 'react-emotion'
|
||||
|
||||
/**
|
||||
* A styled word counter component.
|
||||
*
|
||||
* @type {Component}
|
||||
*/
|
||||
|
||||
const WordCounter = styled('span')`
|
||||
margin-top: 10px;
|
||||
padding: 12px;
|
||||
background-color: #ebebeb;
|
||||
display: inline-block;
|
||||
`
|
||||
|
||||
/**
|
||||
* A simple word count plugin.
|
||||
@@ -18,9 +32,9 @@ function WordCount(options) {
|
||||
return (
|
||||
<div>
|
||||
<div>{props.children}</div>
|
||||
<span className="word-counter">
|
||||
<WordCounter>
|
||||
Word Count: {props.value.document.text.split(' ').length}
|
||||
</span>
|
||||
</WordCounter>
|
||||
</div>
|
||||
)
|
||||
},
|
||||
@@ -53,6 +67,23 @@ The second is another simple plugin that inserts a "soft" break when enter is pr
|
||||
The third is an example of using the plugin.render property to create a higher-order-component.`),
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the editor.
|
||||
*
|
||||
* @return {Component} component
|
||||
*/
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Editor
|
||||
placeholder="Enter some text..."
|
||||
plugins={plugins}
|
||||
value={this.state.value}
|
||||
onChange={this.onChange}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* On change.
|
||||
*
|
||||
@@ -62,25 +93,6 @@ The third is an example of using the plugin.render property to create a higher-o
|
||||
onChange = ({ value }) => {
|
||||
this.setState({ value })
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the editor.
|
||||
*
|
||||
* @return {Component} component
|
||||
*/
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="editor">
|
||||
<Editor
|
||||
placeholder="Enter some text..."
|
||||
plugins={plugins}
|
||||
value={this.state.value}
|
||||
onChange={this.onChange}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -22,6 +22,23 @@ class ReadOnly extends React.Component {
|
||||
),
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the editor.
|
||||
*
|
||||
* @return {Component} component
|
||||
*/
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Editor
|
||||
readOnly
|
||||
placeholder="Enter some text..."
|
||||
value={this.state.value}
|
||||
onChange={this.onChange}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* On change.
|
||||
*
|
||||
@@ -31,25 +48,6 @@ class ReadOnly extends React.Component {
|
||||
onChange = ({ value }) => {
|
||||
this.setState({ value })
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the editor.
|
||||
*
|
||||
* @return {Component} component
|
||||
*/
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="editor">
|
||||
<Editor
|
||||
readOnly
|
||||
placeholder="Enter some text..."
|
||||
value={this.state.value}
|
||||
onChange={this.onChange}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -4,6 +4,7 @@ import { Value } from 'slate'
|
||||
import React from 'react'
|
||||
import initialValue from './value.json'
|
||||
import { isKeyHotkey } from 'is-hotkey'
|
||||
import { Button, Icon, Toolbar } from '../components'
|
||||
|
||||
/**
|
||||
* Define the default node type.
|
||||
@@ -65,6 +66,136 @@ class RichTextExample extends React.Component {
|
||||
return value.blocks.some(node => node.type == type)
|
||||
}
|
||||
|
||||
/**
|
||||
* Render.
|
||||
*
|
||||
* @return {Element}
|
||||
*/
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<Toolbar>
|
||||
{this.renderMarkButton('bold', 'format_bold')}
|
||||
{this.renderMarkButton('italic', 'format_italic')}
|
||||
{this.renderMarkButton('underlined', 'format_underlined')}
|
||||
{this.renderMarkButton('code', 'code')}
|
||||
{this.renderBlockButton('heading-one', 'looks_one')}
|
||||
{this.renderBlockButton('heading-two', 'looks_two')}
|
||||
{this.renderBlockButton('block-quote', 'format_quote')}
|
||||
{this.renderBlockButton('numbered-list', 'format_list_numbered')}
|
||||
{this.renderBlockButton('bulleted-list', 'format_list_bulleted')}
|
||||
</Toolbar>
|
||||
<Editor
|
||||
spellCheck
|
||||
autoFocus
|
||||
placeholder="Enter some rich text..."
|
||||
value={this.state.value}
|
||||
onChange={this.onChange}
|
||||
onKeyDown={this.onKeyDown}
|
||||
renderNode={this.renderNode}
|
||||
renderMark={this.renderMark}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a mark-toggling toolbar button.
|
||||
*
|
||||
* @param {String} type
|
||||
* @param {String} icon
|
||||
* @return {Element}
|
||||
*/
|
||||
|
||||
renderMarkButton = (type, icon) => {
|
||||
const isActive = this.hasMark(type)
|
||||
|
||||
return (
|
||||
<Button
|
||||
active={isActive}
|
||||
onMouseDown={event => this.onClickMark(event, type)}
|
||||
>
|
||||
<Icon>{icon}</Icon>
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a block-toggling toolbar button.
|
||||
*
|
||||
* @param {String} type
|
||||
* @param {String} icon
|
||||
* @return {Element}
|
||||
*/
|
||||
|
||||
renderBlockButton = (type, icon) => {
|
||||
let isActive = this.hasBlock(type)
|
||||
|
||||
if (['numbered-list', 'bulleted-list'].includes(type)) {
|
||||
const { value } = this.state
|
||||
const parent = value.document.getParent(value.blocks.first().key)
|
||||
isActive = this.hasBlock('list-item') && parent && parent.type === type
|
||||
}
|
||||
|
||||
return (
|
||||
<Button
|
||||
active={isActive}
|
||||
onMouseDown={event => this.onClickBlock(event, type)}
|
||||
>
|
||||
<Icon>{icon}</Icon>
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a Slate node.
|
||||
*
|
||||
* @param {Object} props
|
||||
* @return {Element}
|
||||
*/
|
||||
|
||||
renderNode = props => {
|
||||
const { attributes, children, node } = props
|
||||
|
||||
switch (node.type) {
|
||||
case 'block-quote':
|
||||
return <blockquote {...attributes}>{children}</blockquote>
|
||||
case 'bulleted-list':
|
||||
return <ul {...attributes}>{children}</ul>
|
||||
case 'heading-one':
|
||||
return <h1 {...attributes}>{children}</h1>
|
||||
case 'heading-two':
|
||||
return <h2 {...attributes}>{children}</h2>
|
||||
case 'list-item':
|
||||
return <li {...attributes}>{children}</li>
|
||||
case 'numbered-list':
|
||||
return <ol {...attributes}>{children}</ol>
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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>
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* On change, save the new `value`.
|
||||
*
|
||||
@@ -168,161 +299,6 @@ class RichTextExample extends React.Component {
|
||||
|
||||
this.onChange(change)
|
||||
}
|
||||
|
||||
/**
|
||||
* Render.
|
||||
*
|
||||
* @return {Element}
|
||||
*/
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
{this.renderToolbar()}
|
||||
{this.renderEditor()}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the toolbar.
|
||||
*
|
||||
* @return {Element}
|
||||
*/
|
||||
|
||||
renderToolbar = () => {
|
||||
return (
|
||||
<div className="menu toolbar-menu">
|
||||
{this.renderMarkButton('bold', 'format_bold')}
|
||||
{this.renderMarkButton('italic', 'format_italic')}
|
||||
{this.renderMarkButton('underlined', 'format_underlined')}
|
||||
{this.renderMarkButton('code', 'code')}
|
||||
{this.renderBlockButton('heading-one', 'looks_one')}
|
||||
{this.renderBlockButton('heading-two', 'looks_two')}
|
||||
{this.renderBlockButton('block-quote', 'format_quote')}
|
||||
{this.renderBlockButton('numbered-list', 'format_list_numbered')}
|
||||
{this.renderBlockButton('bulleted-list', 'format_list_bulleted')}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 a block-toggling toolbar button.
|
||||
*
|
||||
* @param {String} type
|
||||
* @param {String} icon
|
||||
* @return {Element}
|
||||
*/
|
||||
|
||||
renderBlockButton = (type, icon) => {
|
||||
let isActive = this.hasBlock(type)
|
||||
|
||||
if (['numbered-list', 'bulleted-list'].includes(type)) {
|
||||
const { value } = this.state
|
||||
const parent = value.document.getParent(value.blocks.first().key)
|
||||
isActive = this.hasBlock('list-item') && parent && parent.type === type
|
||||
}
|
||||
|
||||
const onMouseDown = event => this.onClickBlock(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 the Slate editor.
|
||||
*
|
||||
* @return {Element}
|
||||
*/
|
||||
|
||||
renderEditor = () => {
|
||||
return (
|
||||
<div className="editor">
|
||||
<Editor
|
||||
placeholder="Enter some rich text..."
|
||||
value={this.state.value}
|
||||
onChange={this.onChange}
|
||||
onKeyDown={this.onKeyDown}
|
||||
renderNode={this.renderNode}
|
||||
renderMark={this.renderMark}
|
||||
spellCheck
|
||||
autoFocus
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a Slate node.
|
||||
*
|
||||
* @param {Object} props
|
||||
* @return {Element}
|
||||
*/
|
||||
|
||||
renderNode = props => {
|
||||
const { attributes, children, node } = props
|
||||
|
||||
switch (node.type) {
|
||||
case 'block-quote':
|
||||
return <blockquote {...attributes}>{children}</blockquote>
|
||||
case 'bulleted-list':
|
||||
return <ul {...attributes}>{children}</ul>
|
||||
case 'heading-one':
|
||||
return <h1 {...attributes}>{children}</h1>
|
||||
case 'heading-two':
|
||||
return <h2 {...attributes}>{children}</h2>
|
||||
case 'list-item':
|
||||
return <li {...attributes}>{children}</li>
|
||||
case 'numbered-list':
|
||||
return <ol {...attributes}>{children}</ol>
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -5,7 +5,7 @@ import React from 'react'
|
||||
import initialValue from './value.json'
|
||||
|
||||
/**
|
||||
* The plain text example.
|
||||
* A right-to-left text example.
|
||||
*
|
||||
* @type {Component}
|
||||
*/
|
||||
@@ -21,6 +21,40 @@ class RTL extends React.Component {
|
||||
value: Value.fromJSON(initialValue),
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the editor.
|
||||
*
|
||||
* @return {Component} component
|
||||
*/
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Editor
|
||||
placeholder="Enter some plain text..."
|
||||
value={this.state.value}
|
||||
onChange={this.onChange}
|
||||
onKeyDown={this.onKeyDown}
|
||||
renderNode={this.renderNode}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a Slate node.
|
||||
*
|
||||
* @param {Object} props
|
||||
* @return {Element}
|
||||
*/
|
||||
|
||||
renderNode = props => {
|
||||
const { attributes, children, node } = props
|
||||
|
||||
switch (node.type) {
|
||||
case 'block-quote':
|
||||
return <blockquote {...attributes}>{children}</blockquote>
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* On change.
|
||||
*
|
||||
@@ -45,42 +79,6 @@ class RTL extends React.Component {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the editor.
|
||||
*
|
||||
* @return {Component} component
|
||||
*/
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="editor">
|
||||
<Editor
|
||||
placeholder="Enter some plain text..."
|
||||
value={this.state.value}
|
||||
onChange={this.onChange}
|
||||
onKeyDown={this.onKeyDown}
|
||||
renderNode={this.renderNode}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a Slate node.
|
||||
*
|
||||
* @param {Object} props
|
||||
* @return {Element}
|
||||
*/
|
||||
|
||||
renderNode = props => {
|
||||
const { attributes, children, node } = props
|
||||
|
||||
switch (node.type) {
|
||||
case 'block-quote':
|
||||
return <blockquote {...attributes}>{children}</blockquote>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -3,9 +3,33 @@ import { Value } from 'slate'
|
||||
|
||||
import React from 'react'
|
||||
import initialValue from './value.json'
|
||||
import styled from 'react-emotion'
|
||||
import { Toolbar } from '../components'
|
||||
|
||||
/**
|
||||
* The rich text example.
|
||||
* Some styled components for the search box.
|
||||
*
|
||||
* @type {Component}
|
||||
*/
|
||||
|
||||
const SearchWrapper = styled('div')`
|
||||
position: relative;
|
||||
`
|
||||
|
||||
const SearchIcon = styled('icon')`
|
||||
position: absolute;
|
||||
top: 0.5em;
|
||||
left: 0.5em;
|
||||
color: #ccc;
|
||||
`
|
||||
|
||||
const SearchInput = styled('input')`
|
||||
padding-left: 2em;
|
||||
width: 100%;
|
||||
`
|
||||
|
||||
/**
|
||||
* The search highlighting example.
|
||||
*
|
||||
* @type {Component}
|
||||
*/
|
||||
@@ -21,6 +45,56 @@ class SearchHighlighting extends React.Component {
|
||||
value: Value.fromJSON(initialValue),
|
||||
}
|
||||
|
||||
/**
|
||||
* Render.
|
||||
*
|
||||
* @return {Element}
|
||||
*/
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<Toolbar>
|
||||
<SearchWrapper>
|
||||
<SearchIcon>search</SearchIcon>
|
||||
<SearchInput
|
||||
type="search"
|
||||
placeholder="Search the text..."
|
||||
onChange={this.onInputChange}
|
||||
/>
|
||||
</SearchWrapper>
|
||||
</Toolbar>
|
||||
<Editor
|
||||
placeholder="Enter some rich text..."
|
||||
value={this.state.value}
|
||||
onChange={this.onChange}
|
||||
renderMark={this.renderMark}
|
||||
spellCheck
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a Slate mark.
|
||||
*
|
||||
* @param {Object} props
|
||||
* @return {Element}
|
||||
*/
|
||||
|
||||
renderMark = props => {
|
||||
const { children, mark, attributes } = props
|
||||
|
||||
switch (mark.type) {
|
||||
case 'highlight':
|
||||
return (
|
||||
<span {...attributes} style={{ backgroundColor: '#ffeeba' }}>
|
||||
{children}
|
||||
</span>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* On change, save the new `value`.
|
||||
*
|
||||
@@ -64,94 +138,17 @@ class SearchHighlighting extends React.Component {
|
||||
})
|
||||
})
|
||||
|
||||
// setting the `save` option to false prevents this change from being added
|
||||
// Setting the `save` option to false prevents this change from being added
|
||||
// to the undo/redo stack and clearing the redo stack if the user has undone
|
||||
// changes.
|
||||
|
||||
const change = value
|
||||
.change()
|
||||
.setOperationFlag('save', false)
|
||||
.setValue({ decorations })
|
||||
.setOperationFlag('save', true)
|
||||
|
||||
this.onChange(change)
|
||||
}
|
||||
|
||||
/**
|
||||
* Render.
|
||||
*
|
||||
* @return {Element}
|
||||
*/
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
{this.renderToolbar()}
|
||||
{this.renderEditor()}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the toolbar.
|
||||
*
|
||||
* @return {Element}
|
||||
*/
|
||||
|
||||
renderToolbar = () => {
|
||||
return (
|
||||
<div className="menu toolbar-menu">
|
||||
<div className="search">
|
||||
<span className="search-icon material-icons">search</span>
|
||||
<input
|
||||
className="search-box"
|
||||
type="search"
|
||||
placeholder="Search the text..."
|
||||
onChange={this.onInputChange}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the Slate editor.
|
||||
*
|
||||
* @return {Element}
|
||||
*/
|
||||
|
||||
renderEditor = () => {
|
||||
return (
|
||||
<div className="editor">
|
||||
<Editor
|
||||
placeholder="Enter some rich text..."
|
||||
value={this.state.value}
|
||||
onChange={this.onChange}
|
||||
renderMark={this.renderMark}
|
||||
spellCheck
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a Slate mark.
|
||||
*
|
||||
* @param {Object} props
|
||||
* @return {Element}
|
||||
*/
|
||||
|
||||
renderMark = props => {
|
||||
const { children, mark, attributes } = props
|
||||
|
||||
switch (mark.type) {
|
||||
case 'highlight':
|
||||
return (
|
||||
<span {...attributes} style={{ backgroundColor: '#ffeeba' }}>
|
||||
{children}
|
||||
</span>
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -3,7 +3,21 @@ import { Value } from 'slate'
|
||||
|
||||
import React from 'react'
|
||||
import initialValue from './value.json'
|
||||
import styled from 'react-emotion'
|
||||
import { isKeyHotkey } from 'is-hotkey'
|
||||
import { Button, Icon, Toolbar } from '../components'
|
||||
|
||||
/**
|
||||
* A spacer component.
|
||||
*
|
||||
* @type {Component}
|
||||
*/
|
||||
|
||||
const Spacer = styled('div')`
|
||||
height: 20px;
|
||||
background-color: #eee;
|
||||
margin: 20px -20px;
|
||||
`
|
||||
|
||||
/**
|
||||
* Hotkey matchers.
|
||||
@@ -58,6 +72,74 @@ class SyncingEditor extends React.Component {
|
||||
return value.activeMarks.some(mark => mark.type == type)
|
||||
}
|
||||
|
||||
/**
|
||||
* Render.
|
||||
*
|
||||
* @return {Element}
|
||||
*/
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<Toolbar>
|
||||
{this.renderMarkButton('bold', 'format_bold')}
|
||||
{this.renderMarkButton('italic', 'format_italic')}
|
||||
{this.renderMarkButton('underlined', 'format_underlined')}
|
||||
{this.renderMarkButton('code', 'code')}
|
||||
</Toolbar>
|
||||
<Editor
|
||||
placeholder="Enter some text..."
|
||||
value={this.state.value}
|
||||
onChange={this.onChange}
|
||||
onKeyDown={this.onKeyDown}
|
||||
renderMark={this.renderMark}
|
||||
spellCheck
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a mark-toggling toolbar button.
|
||||
*
|
||||
* @param {String} type
|
||||
* @param {String} icon
|
||||
* @return {Element}
|
||||
*/
|
||||
|
||||
renderMarkButton = (type, icon) => {
|
||||
return (
|
||||
<Button
|
||||
active={this.hasMark(type)}
|
||||
onMouseDown={event => this.onClickMark(event, type)}
|
||||
>
|
||||
<Icon>{icon}</Icon>
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 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>
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* On change, save the new `value`. And if it's a local change, call the
|
||||
* passed-in `onChange` handler.
|
||||
@@ -115,101 +197,6 @@ class SyncingEditor extends React.Component {
|
||||
const change = value.change().toggleMark(type)
|
||||
this.onChange(change)
|
||||
}
|
||||
|
||||
/**
|
||||
* Render.
|
||||
*
|
||||
* @return {Element}
|
||||
*/
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
{this.renderToolbar()}
|
||||
{this.renderEditor()}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the toolbar.
|
||||
*
|
||||
* @return {Element}
|
||||
*/
|
||||
|
||||
renderToolbar = () => {
|
||||
return (
|
||||
<div className="menu toolbar-menu">
|
||||
{this.renderButton('bold', 'format_bold')}
|
||||
{this.renderButton('italic', 'format_italic')}
|
||||
{this.renderButton('underlined', 'format_underlined')}
|
||||
{this.renderButton('code', 'code')}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a mark-toggling toolbar button.
|
||||
*
|
||||
* @param {String} type
|
||||
* @param {String} icon
|
||||
* @return {Element}
|
||||
*/
|
||||
|
||||
renderButton = (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 the editor.
|
||||
*
|
||||
* @return {Element}
|
||||
*/
|
||||
|
||||
renderEditor = () => {
|
||||
return (
|
||||
<div className="editor">
|
||||
<Editor
|
||||
placeholder="Enter some text..."
|
||||
value={this.state.value}
|
||||
onChange={this.onChange}
|
||||
onKeyDown={this.onKeyDown}
|
||||
renderMark={this.renderMark}
|
||||
spellCheck
|
||||
/>
|
||||
</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>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -220,23 +207,25 @@ class SyncingEditor extends React.Component {
|
||||
|
||||
class SyncingOperationsExample extends React.Component {
|
||||
/**
|
||||
* Save a reference to editor `one`.
|
||||
* Render both editors.
|
||||
*
|
||||
* @param {SyncingEditor} one
|
||||
* @return {Element}
|
||||
*/
|
||||
|
||||
oneRef = one => {
|
||||
this.one = one
|
||||
}
|
||||
|
||||
/**
|
||||
* Save a reference to editor `two`.
|
||||
*
|
||||
* @param {SyncingEditor} two
|
||||
*/
|
||||
|
||||
twoRef = two => {
|
||||
this.two = two
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<SyncingEditor
|
||||
ref={one => (this.one = one)}
|
||||
onChange={this.onOneChange}
|
||||
/>
|
||||
<Spacer />
|
||||
<SyncingEditor
|
||||
ref={two => (this.two = two)}
|
||||
onChange={this.onTwoChange}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -270,28 +259,6 @@ class SyncingOperationsExample extends React.Component {
|
||||
this.one.applyOperations(ops)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Render both editors.
|
||||
*
|
||||
* @return {Element}
|
||||
*/
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<SyncingEditor ref={this.oneRef} onChange={this.onOneChange} />
|
||||
<div
|
||||
style={{
|
||||
height: '20px',
|
||||
backgroundColor: '#eee',
|
||||
margin: '20px -20px',
|
||||
}}
|
||||
/>
|
||||
<SyncingEditor ref={this.twoRef} onChange={this.onTwoChange} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -1,4 +1,5 @@
|
||||
import { Editor } from 'slate-react'
|
||||
import Plain from 'slate-plain-serializer'
|
||||
import { Editor, getEventTransfer } from 'slate-react'
|
||||
import { Value } from 'slate'
|
||||
|
||||
import React from 'react'
|
||||
@@ -21,97 +22,6 @@ class Tables extends React.Component {
|
||||
value: Value.fromJSON(initialValue),
|
||||
}
|
||||
|
||||
/**
|
||||
* On backspace, do nothing if at the start of a table cell.
|
||||
*
|
||||
* @param {Event} event
|
||||
* @param {Change} change
|
||||
*/
|
||||
|
||||
onBackspace = (event, change) => {
|
||||
const { value } = change
|
||||
if (value.startOffset != 0) return
|
||||
event.preventDefault()
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* On change.
|
||||
*
|
||||
* @param {Change} change
|
||||
*/
|
||||
|
||||
onChange = ({ value }) => {
|
||||
this.setState({ value })
|
||||
}
|
||||
|
||||
/**
|
||||
* On delete, do nothing if at the end of a table cell.
|
||||
*
|
||||
* @param {Event} event
|
||||
* @param {Change} change
|
||||
*/
|
||||
|
||||
onDelete = (event, change) => {
|
||||
const { value } = change
|
||||
if (value.endOffset != value.startText.text.length) return
|
||||
event.preventDefault()
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* On return, do nothing if inside a table cell.
|
||||
*
|
||||
* @param {Event} event
|
||||
* @param {Change} change
|
||||
*/
|
||||
|
||||
onEnter = (event, change) => {
|
||||
event.preventDefault()
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* On key down, check for our specific key shortcuts.
|
||||
*
|
||||
* @param {Event} event
|
||||
* @param {Change} change
|
||||
*/
|
||||
|
||||
onKeyDown = (event, change) => {
|
||||
const { value } = change
|
||||
const { document, selection } = value
|
||||
const { startKey } = selection
|
||||
const startNode = document.getDescendant(startKey)
|
||||
|
||||
if (selection.isAtStartOf(startNode)) {
|
||||
const previous = document.getPreviousText(startNode.key)
|
||||
const prevBlock = document.getClosestBlock(previous.key)
|
||||
|
||||
if (prevBlock.type == 'table-cell') {
|
||||
if (['Backspace', 'Delete', 'Enter'].includes(event.key)) {
|
||||
event.preventDefault()
|
||||
return true
|
||||
} else {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (value.startBlock.type != 'table-cell') {
|
||||
return
|
||||
}
|
||||
|
||||
switch (event.key) {
|
||||
case 'Backspace':
|
||||
return this.onBackspace(event, change)
|
||||
case 'Delete':
|
||||
return this.onDelete(event, change)
|
||||
case 'Enter':
|
||||
return this.onEnter(event, change)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the example.
|
||||
*
|
||||
@@ -120,16 +30,16 @@ class Tables extends React.Component {
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="editor">
|
||||
<Editor
|
||||
placeholder="Enter some text..."
|
||||
value={this.state.value}
|
||||
onChange={this.onChange}
|
||||
onKeyDown={this.onKeyDown}
|
||||
renderNode={this.renderNode}
|
||||
renderMark={this.renderMark}
|
||||
/>
|
||||
</div>
|
||||
<Editor
|
||||
placeholder="Enter some text..."
|
||||
value={this.state.value}
|
||||
onChange={this.onChange}
|
||||
onKeyDown={this.onKeyDown}
|
||||
onDrop={this.onDropOrPaste}
|
||||
onPaste={this.onDropOrPaste}
|
||||
renderNode={this.renderNode}
|
||||
renderMark={this.renderMark}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -172,6 +82,123 @@ class Tables extends React.Component {
|
||||
return <strong {...attributes}>{children}</strong>
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* On backspace, do nothing if at the start of a table cell.
|
||||
*
|
||||
* @param {Event} event
|
||||
* @param {Change} change
|
||||
*/
|
||||
|
||||
onBackspace = (event, change) => {
|
||||
const { value } = change
|
||||
if (value.startOffset != 0) return
|
||||
event.preventDefault()
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* On change.
|
||||
*
|
||||
* @param {Change} change
|
||||
*/
|
||||
|
||||
onChange = ({ value }) => {
|
||||
this.setState({ value })
|
||||
}
|
||||
|
||||
/**
|
||||
* On delete, do nothing if at the end of a table cell.
|
||||
*
|
||||
* @param {Event} event
|
||||
* @param {Change} change
|
||||
*/
|
||||
|
||||
onDelete = (event, change) => {
|
||||
const { value } = change
|
||||
if (value.endOffset != value.startText.text.length) return
|
||||
event.preventDefault()
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* On paste or drop, only support plain text for this example.
|
||||
*
|
||||
* @param {Event} event
|
||||
* @param {Change} change
|
||||
*/
|
||||
|
||||
onDropOrPaste = (event, change) => {
|
||||
const transfer = getEventTransfer(event)
|
||||
const { value } = change
|
||||
const { text = '' } = transfer
|
||||
|
||||
if (value.startBlock.type !== 'table-cell') {
|
||||
return
|
||||
}
|
||||
|
||||
if (!text) {
|
||||
return
|
||||
}
|
||||
|
||||
const lines = text.split('\n')
|
||||
const { document } = Plain.deserialize(lines[0] || '')
|
||||
change.insertFragment(document)
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* On return, do nothing if inside a table cell.
|
||||
*
|
||||
* @param {Event} event
|
||||
* @param {Change} change
|
||||
*/
|
||||
|
||||
onEnter = (event, change) => {
|
||||
event.preventDefault()
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* On key down, check for our specific key shortcuts.
|
||||
*
|
||||
* @param {Event} event
|
||||
* @param {Change} change
|
||||
*/
|
||||
|
||||
onKeyDown = (event, change) => {
|
||||
const { value } = change
|
||||
const { document, selection } = value
|
||||
const { startKey } = selection
|
||||
const startNode = document.getDescendant(startKey)
|
||||
|
||||
if (selection.isAtStartOf(startNode)) {
|
||||
const previous = document.getPreviousText(startNode.key)
|
||||
const prevBlock = document.getClosestBlock(previous.key)
|
||||
|
||||
if (prevBlock.type === 'table-cell') {
|
||||
if (['Backspace', 'Delete', 'Enter'].includes(event.key)) {
|
||||
event.preventDefault()
|
||||
return true
|
||||
} else {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (value.startBlock.type !== 'table-cell') {
|
||||
return
|
||||
}
|
||||
|
||||
switch (event.key) {
|
||||
case 'Backspace':
|
||||
return this.onBackspace(event, change)
|
||||
case 'Delete':
|
||||
return this.onDelete(event, change)
|
||||
case 'Enter':
|
||||
return this.onEnter(event, change)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
11
package.json
11
package.json
@@ -19,6 +19,7 @@
|
||||
"copy-webpack-plugin": "^4.4.1",
|
||||
"cross-env": "^5.1.3",
|
||||
"css-loader": "^0.28.9",
|
||||
"emotion": "^9.2.4",
|
||||
"eslint": "^4.19.1",
|
||||
"eslint-config-prettier": "^2.9.0",
|
||||
"eslint-plugin-import": "^2.8.0",
|
||||
@@ -42,12 +43,12 @@
|
||||
"npm-run-all": "^4.1.2",
|
||||
"prettier": "^1.10.2",
|
||||
"prismjs": "^1.5.1",
|
||||
"react": "^16.0.0",
|
||||
"react-dom": "^16.0.0",
|
||||
"react": "^16.4.1",
|
||||
"react-dom": "^16.4.1",
|
||||
"react-emotion": "^9.2.4",
|
||||
"react-hot-loader": "^3.1.3",
|
||||
"react-portal": "^3.1.0",
|
||||
"react-router": "^2.5.1",
|
||||
"react-router-dom": "^4.1.1",
|
||||
"react-portal": "^4.1.5",
|
||||
"react-router-dom": "^4.3.1",
|
||||
"read-metadata": "^1.0.0",
|
||||
"rollup": "^0.55.1",
|
||||
"rollup-plugin-alias": "^1.4.0",
|
||||
|
307
yarn.lock
307
yarn.lock
@@ -24,6 +24,13 @@
|
||||
dependencies:
|
||||
"@babel/types" "7.0.0-beta.36"
|
||||
|
||||
"@babel/helper-module-imports@7.0.0-beta.40":
|
||||
version "7.0.0-beta.40"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.0.0-beta.40.tgz#251cbb6404599282e8f7356a5b32c9381bef5d2d"
|
||||
dependencies:
|
||||
"@babel/types" "7.0.0-beta.40"
|
||||
lodash "^4.2.0"
|
||||
|
||||
"@babel/template@7.0.0-beta.36":
|
||||
version "7.0.0-beta.36"
|
||||
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.0.0-beta.36.tgz#02e903de5d68bd7899bce3c5b5447e59529abb00"
|
||||
@@ -54,6 +61,60 @@
|
||||
lodash "^4.2.0"
|
||||
to-fast-properties "^2.0.0"
|
||||
|
||||
"@babel/types@7.0.0-beta.40":
|
||||
version "7.0.0-beta.40"
|
||||
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.0.0-beta.40.tgz#25c3d7aae14126abe05fcb098c65a66b6d6b8c14"
|
||||
dependencies:
|
||||
esutils "^2.0.2"
|
||||
lodash "^4.2.0"
|
||||
to-fast-properties "^2.0.0"
|
||||
|
||||
"@emotion/babel-utils@^0.6.4":
|
||||
version "0.6.4"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/babel-utils/-/babel-utils-0.6.4.tgz#2eac69eb31ae944fbe4a2a0e736a35db5f810866"
|
||||
dependencies:
|
||||
"@emotion/hash" "^0.6.3"
|
||||
"@emotion/memoize" "^0.6.2"
|
||||
"@emotion/serialize" "^0.8.2"
|
||||
convert-source-map "^1.5.1"
|
||||
find-root "^1.1.0"
|
||||
source-map "^0.7.2"
|
||||
|
||||
"@emotion/hash@^0.6.2", "@emotion/hash@^0.6.3":
|
||||
version "0.6.3"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.6.3.tgz#0e7a5604626fc6c6d4ac4061a2f5ac80d50262a4"
|
||||
|
||||
"@emotion/is-prop-valid@^0.6.1":
|
||||
version "0.6.2"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-0.6.2.tgz#a76a16b174ff03f8e3a27faf6259bacd21a02adc"
|
||||
dependencies:
|
||||
"@emotion/memoize" "^0.6.2"
|
||||
|
||||
"@emotion/memoize@^0.6.1", "@emotion/memoize@^0.6.2":
|
||||
version "0.6.2"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.6.2.tgz#138e00b332d519b4e307bded6159e5ba48aba3ae"
|
||||
|
||||
"@emotion/serialize@^0.8.2":
|
||||
version "0.8.2"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-0.8.2.tgz#d3b2caddfc93107d63c79fc6bbc11e555e3b762e"
|
||||
dependencies:
|
||||
"@emotion/hash" "^0.6.3"
|
||||
"@emotion/memoize" "^0.6.2"
|
||||
"@emotion/unitless" "^0.6.3"
|
||||
"@emotion/utils" "^0.7.1"
|
||||
|
||||
"@emotion/stylis@^0.6.10":
|
||||
version "0.6.10"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/stylis/-/stylis-0.6.10.tgz#7d321e639ebc8ba23ace5990c20e94dcebb8f3dd"
|
||||
|
||||
"@emotion/unitless@^0.6.2", "@emotion/unitless@^0.6.3":
|
||||
version "0.6.3"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.6.3.tgz#65682e68a82701c70eefb38d7f941a2c0bfa90de"
|
||||
|
||||
"@emotion/utils@^0.7.1":
|
||||
version "0.7.1"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-0.7.1.tgz#e44e596d03c9f16ba3b127ad333a8a072bcb5a0a"
|
||||
|
||||
"@types/node@^6.0.46":
|
||||
version "6.0.83"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-6.0.83.tgz#dd022db01ac2c01c1057775e88ccffce96d1d6fe"
|
||||
@@ -628,12 +689,35 @@ babel-plugin-check-es2015-constants@^6.22.0:
|
||||
dependencies:
|
||||
babel-runtime "^6.22.0"
|
||||
|
||||
babel-plugin-emotion@^9.2.4:
|
||||
version "9.2.4"
|
||||
resolved "https://registry.yarnpkg.com/babel-plugin-emotion/-/babel-plugin-emotion-9.2.4.tgz#a4e54a8097f6ba06cbbc7a9063927afafe9fe73a"
|
||||
dependencies:
|
||||
"@babel/helper-module-imports" "7.0.0-beta.40"
|
||||
"@emotion/babel-utils" "^0.6.4"
|
||||
"@emotion/hash" "^0.6.2"
|
||||
"@emotion/memoize" "^0.6.1"
|
||||
"@emotion/stylis" "^0.6.10"
|
||||
babel-plugin-macros "^2.0.0"
|
||||
babel-plugin-syntax-jsx "^6.18.0"
|
||||
convert-source-map "^1.5.0"
|
||||
find-root "^1.1.0"
|
||||
mkdirp "^0.5.1"
|
||||
source-map "^0.5.7"
|
||||
touch "^1.0.0"
|
||||
|
||||
babel-plugin-external-helpers@^6.22.0:
|
||||
version "6.22.0"
|
||||
resolved "https://registry.yarnpkg.com/babel-plugin-external-helpers/-/babel-plugin-external-helpers-6.22.0.tgz#2285f48b02bd5dede85175caf8c62e86adccefa1"
|
||||
dependencies:
|
||||
babel-runtime "^6.22.0"
|
||||
|
||||
babel-plugin-macros@^2.0.0:
|
||||
version "2.2.2"
|
||||
resolved "https://registry.yarnpkg.com/babel-plugin-macros/-/babel-plugin-macros-2.2.2.tgz#049c93f4b934453688a6ec38bba529c55bf0fa1f"
|
||||
dependencies:
|
||||
cosmiconfig "^4.0.0"
|
||||
|
||||
babel-plugin-syntax-async-functions@^6.8.0:
|
||||
version "6.13.0"
|
||||
resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95"
|
||||
@@ -678,7 +762,7 @@ babel-plugin-syntax-function-bind@^6.8.0:
|
||||
version "6.13.0"
|
||||
resolved "https://registry.yarnpkg.com/babel-plugin-syntax-function-bind/-/babel-plugin-syntax-function-bind-6.13.0.tgz#48c495f177bdf31a981e732f55adc0bdd2601f46"
|
||||
|
||||
babel-plugin-syntax-jsx@^6.3.13, babel-plugin-syntax-jsx@^6.8.0:
|
||||
babel-plugin-syntax-jsx@^6.18.0, babel-plugin-syntax-jsx@^6.3.13, babel-plugin-syntax-jsx@^6.8.0:
|
||||
version "6.18.0"
|
||||
resolved "https://registry.yarnpkg.com/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz#0af32a9a6e13ca7a3fd5069e62d7b0f58d0d8946"
|
||||
|
||||
@@ -2079,7 +2163,7 @@ conventional-recommended-bump@^1.0.1:
|
||||
meow "^3.3.0"
|
||||
object-assign "^4.0.1"
|
||||
|
||||
convert-source-map@^1.5.0:
|
||||
convert-source-map@^1.5.0, convert-source-map@^1.5.1:
|
||||
version "1.5.1"
|
||||
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.1.tgz#b8278097b9bc229365de5c62cf5fcaed8b5599e5"
|
||||
|
||||
@@ -2135,6 +2219,15 @@ core-util-is@~1.0.0:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
|
||||
|
||||
cosmiconfig@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-4.0.0.tgz#760391549580bbd2df1e562bc177b13c290972dc"
|
||||
dependencies:
|
||||
is-directory "^0.3.1"
|
||||
js-yaml "^3.9.0"
|
||||
parse-json "^4.0.0"
|
||||
require-from-string "^2.0.1"
|
||||
|
||||
create-ecdh@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.0.tgz#888c723596cdf7612f6498233eebd7a35301737d"
|
||||
@@ -2142,6 +2235,24 @@ create-ecdh@^4.0.0:
|
||||
bn.js "^4.1.0"
|
||||
elliptic "^6.0.0"
|
||||
|
||||
create-emotion-styled@^9.2.3:
|
||||
version "9.2.3"
|
||||
resolved "https://registry.yarnpkg.com/create-emotion-styled/-/create-emotion-styled-9.2.3.tgz#17fb13b3ae4c165ea6e5a11356ab8b9ca1dad9c5"
|
||||
dependencies:
|
||||
"@emotion/is-prop-valid" "^0.6.1"
|
||||
|
||||
create-emotion@^9.2.4:
|
||||
version "9.2.4"
|
||||
resolved "https://registry.yarnpkg.com/create-emotion/-/create-emotion-9.2.4.tgz#0a4379f6bf0708c54fe26bfcd6b6bd3592e8cf23"
|
||||
dependencies:
|
||||
"@emotion/hash" "^0.6.2"
|
||||
"@emotion/memoize" "^0.6.1"
|
||||
"@emotion/stylis" "^0.6.10"
|
||||
"@emotion/unitless" "^0.6.2"
|
||||
csstype "^2.5.2"
|
||||
stylis "^3.5.0"
|
||||
stylis-rule-sheet "^0.0.10"
|
||||
|
||||
create-error-class@^3.0.0:
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/create-error-class/-/create-error-class-3.0.2.tgz#06be7abef947a3f14a30fd610671d401bca8b7b6"
|
||||
@@ -2313,6 +2424,10 @@ cssom@0.3.x, "cssom@>= 0.3.2 < 0.4.0":
|
||||
dependencies:
|
||||
cssom "0.3.x"
|
||||
|
||||
csstype@^2.5.2:
|
||||
version "2.5.5"
|
||||
resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.5.5.tgz#4125484a3d42189a863943f23b9e4b80fedfa106"
|
||||
|
||||
currently-unhandled@^0.4.1:
|
||||
version "0.4.1"
|
||||
resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea"
|
||||
@@ -2388,7 +2503,7 @@ dedent@^0.7.0:
|
||||
version "0.7.0"
|
||||
resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c"
|
||||
|
||||
deep-equal@^1.0.0, deep-equal@^1.0.1:
|
||||
deep-equal@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5"
|
||||
|
||||
@@ -2681,6 +2796,13 @@ emojis-list@^2.0.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389"
|
||||
|
||||
emotion@^9.2.4:
|
||||
version "9.2.4"
|
||||
resolved "https://registry.yarnpkg.com/emotion/-/emotion-9.2.4.tgz#0139e7cc154b2845f4b9afaa996dd4de13bb90e3"
|
||||
dependencies:
|
||||
babel-plugin-emotion "^9.2.4"
|
||||
create-emotion "^9.2.4"
|
||||
|
||||
encodeurl@~1.0.1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
|
||||
@@ -3305,6 +3427,10 @@ find-cache-dir@^1.0.0:
|
||||
make-dir "^1.0.0"
|
||||
pkg-dir "^2.0.0"
|
||||
|
||||
find-root@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4"
|
||||
|
||||
find-up@^1.0.0:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f"
|
||||
@@ -3871,23 +3997,14 @@ he@1.1.x:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd"
|
||||
|
||||
history@^2.1.2:
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/history/-/history-2.1.2.tgz#4aa2de897a0e4867e4539843be6ecdb2986bfdec"
|
||||
dependencies:
|
||||
deep-equal "^1.0.0"
|
||||
invariant "^2.0.0"
|
||||
query-string "^3.0.0"
|
||||
warning "^2.0.0"
|
||||
|
||||
history@^4.5.1, history@^4.6.0:
|
||||
version "4.6.1"
|
||||
resolved "https://registry.yarnpkg.com/history/-/history-4.6.1.tgz#911cf8eb65728555a94f2b12780a0c531a14d2fd"
|
||||
history@^4.7.2:
|
||||
version "4.7.2"
|
||||
resolved "https://registry.yarnpkg.com/history/-/history-4.7.2.tgz#22b5c7f31633c5b8021c7f4a8a954ac139ee8d5b"
|
||||
dependencies:
|
||||
invariant "^2.2.1"
|
||||
loose-envify "^1.2.0"
|
||||
resolve-pathname "^2.0.0"
|
||||
value-equal "^0.2.0"
|
||||
resolve-pathname "^2.2.0"
|
||||
value-equal "^0.4.0"
|
||||
warning "^3.0.0"
|
||||
|
||||
hmac-drbg@^1.0.0:
|
||||
@@ -3906,9 +4023,9 @@ hoek@4.x.x:
|
||||
version "4.2.0"
|
||||
resolved "https://registry.yarnpkg.com/hoek/-/hoek-4.2.0.tgz#72d9d0754f7fe25ca2d01ad8f8f9a9449a89526d"
|
||||
|
||||
hoist-non-react-statics@^1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-1.2.0.tgz#aa448cf0986d55cc40773b17174b7dd066cb7cfb"
|
||||
hoist-non-react-statics@^2.5.0:
|
||||
version "2.5.5"
|
||||
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-2.5.5.tgz#c5903cf409c0dfd908f388e619d86b9c1174cb47"
|
||||
|
||||
home-or-tmp@^2.0.0:
|
||||
version "2.0.0"
|
||||
@@ -4163,12 +4280,18 @@ interpret@^1.0.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.1.0.tgz#7ed1b1410c6a0e0f78cf95d3b8440c63f78b8614"
|
||||
|
||||
invariant@^2.0.0, invariant@^2.2.0, invariant@^2.2.1, invariant@^2.2.2:
|
||||
invariant@^2.2.0, invariant@^2.2.1, invariant@^2.2.2:
|
||||
version "2.2.2"
|
||||
resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.2.tgz#9e1f56ac0acdb6bf303306f338be3b204ae60360"
|
||||
dependencies:
|
||||
loose-envify "^1.0.0"
|
||||
|
||||
invariant@^2.2.4:
|
||||
version "2.2.4"
|
||||
resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6"
|
||||
dependencies:
|
||||
loose-envify "^1.0.0"
|
||||
|
||||
invert-kv@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6"
|
||||
@@ -4259,6 +4382,10 @@ is-descriptor@^1.0.0:
|
||||
is-data-descriptor "^1.0.0"
|
||||
kind-of "^6.0.2"
|
||||
|
||||
is-directory@^0.3.1:
|
||||
version "0.3.1"
|
||||
resolved "https://registry.yarnpkg.com/is-directory/-/is-directory-0.3.1.tgz#61339b6f2475fc772fd9c9d83f5c8575dc154ae1"
|
||||
|
||||
is-dotfile@^1.0.0:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.2.tgz#2c132383f39199f8edc268ca01b9b007d205cc4d"
|
||||
@@ -4537,7 +4664,7 @@ js-tokens@^3.0.0, js-tokens@^3.0.2:
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b"
|
||||
|
||||
js-yaml@^3.9.1:
|
||||
js-yaml@^3.9.0, js-yaml@^3.9.1:
|
||||
version "3.12.0"
|
||||
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.12.0.tgz#eaed656ec8344f10f527c6bfa1b6e2244de167d1"
|
||||
dependencies:
|
||||
@@ -5458,6 +5585,12 @@ nopt@^4.0.1:
|
||||
abbrev "1"
|
||||
osenv "^0.1.4"
|
||||
|
||||
nopt@~1.0.10:
|
||||
version "1.0.10"
|
||||
resolved "https://registry.yarnpkg.com/nopt/-/nopt-1.0.10.tgz#6ddd21bd2a31417b92727dd585f8a6f37608ebee"
|
||||
dependencies:
|
||||
abbrev "1"
|
||||
|
||||
normalize-package-data@^2.3.0, normalize-package-data@^2.3.2, normalize-package-data@^2.3.4, normalize-package-data@^2.3.5:
|
||||
version "2.4.0"
|
||||
resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.4.0.tgz#12f95a307d58352075a04907b84ac8be98ac012f"
|
||||
@@ -5824,7 +5957,7 @@ path-to-regexp@0.1.7:
|
||||
version "0.1.7"
|
||||
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"
|
||||
|
||||
path-to-regexp@^1.5.3:
|
||||
path-to-regexp@^1.7.0:
|
||||
version "1.7.0"
|
||||
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.7.0.tgz#59fde0f435badacba103a84e9d3bc64e96b9937d"
|
||||
dependencies:
|
||||
@@ -6262,6 +6395,13 @@ prop-types@^15.6.0:
|
||||
loose-envify "^1.3.1"
|
||||
object-assign "^4.1.1"
|
||||
|
||||
prop-types@^15.6.1:
|
||||
version "15.6.2"
|
||||
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.2.tgz#05d5ca77b4453e985d60fc7ff8c859094a497102"
|
||||
dependencies:
|
||||
loose-envify "^1.3.1"
|
||||
object-assign "^4.1.1"
|
||||
|
||||
proxy-addr@~2.0.2:
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.2.tgz#6571504f47bb988ec8180253f85dd7e14952bdec"
|
||||
@@ -6362,12 +6502,6 @@ qs@~6.4.0:
|
||||
version "6.4.0"
|
||||
resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233"
|
||||
|
||||
query-string@^3.0.0:
|
||||
version "3.0.3"
|
||||
resolved "https://registry.yarnpkg.com/query-string/-/query-string-3.0.3.tgz#ae2e14b4d05071d4e9b9eb4873c35b0dcd42e638"
|
||||
dependencies:
|
||||
strict-uri-encode "^1.0.0"
|
||||
|
||||
query-string@^4.1.0:
|
||||
version "4.3.4"
|
||||
resolved "https://registry.yarnpkg.com/query-string/-/query-string-4.3.4.tgz#bbb693b9ca915c232515b228b1a02b609043dbeb"
|
||||
@@ -6446,15 +6580,22 @@ react-deep-force-update@^2.1.1:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/react-deep-force-update/-/react-deep-force-update-2.1.1.tgz#8ea4263cd6455a050b37445b3f08fd839d86e909"
|
||||
|
||||
react-dom@^16.0.0:
|
||||
version "16.0.0"
|
||||
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.0.0.tgz#9cc3079c3dcd70d4c6e01b84aab2a7e34c303f58"
|
||||
react-dom@^16.4.1:
|
||||
version "16.4.1"
|
||||
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.4.1.tgz#7f8b0223b3a5fbe205116c56deb85de32685dad6"
|
||||
dependencies:
|
||||
fbjs "^0.8.16"
|
||||
loose-envify "^1.1.0"
|
||||
object-assign "^4.1.1"
|
||||
prop-types "^15.6.0"
|
||||
|
||||
react-emotion@^9.2.4:
|
||||
version "9.2.4"
|
||||
resolved "https://registry.yarnpkg.com/react-emotion/-/react-emotion-9.2.4.tgz#98e00f70ce2ca4ee13923460123e763e492c013a"
|
||||
dependencies:
|
||||
babel-plugin-emotion "^9.2.4"
|
||||
create-emotion-styled "^9.2.3"
|
||||
|
||||
react-hot-loader@^3.1.3:
|
||||
version "3.1.3"
|
||||
resolved "https://registry.yarnpkg.com/react-hot-loader/-/react-hot-loader-3.1.3.tgz#6f92877326958c7cb0134b512474517869126082"
|
||||
@@ -6475,46 +6616,44 @@ react-portal@^3.1.0:
|
||||
dependencies:
|
||||
prop-types "^15.5.8"
|
||||
|
||||
react-portal@^4.1.5:
|
||||
version "4.1.5"
|
||||
resolved "https://registry.yarnpkg.com/react-portal/-/react-portal-4.1.5.tgz#6665d4d2a92d47d6f8b07a6529e26fc52d5cccde"
|
||||
dependencies:
|
||||
prop-types "^15.5.8"
|
||||
|
||||
react-proxy@^3.0.0-alpha.0:
|
||||
version "3.0.0-alpha.1"
|
||||
resolved "https://registry.yarnpkg.com/react-proxy/-/react-proxy-3.0.0-alpha.1.tgz#4400426bcfa80caa6724c7755695315209fa4b07"
|
||||
dependencies:
|
||||
lodash "^4.6.1"
|
||||
|
||||
react-router-dom@^4.1.1:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-4.1.1.tgz#3021ade1f2c160af97cf94e25594c5f294583025"
|
||||
react-router-dom@^4.3.1:
|
||||
version "4.3.1"
|
||||
resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-4.3.1.tgz#4c2619fc24c4fa87c9fd18f4fb4a43fe63fbd5c6"
|
||||
dependencies:
|
||||
history "^4.5.1"
|
||||
history "^4.7.2"
|
||||
invariant "^2.2.4"
|
||||
loose-envify "^1.3.1"
|
||||
prop-types "^15.5.4"
|
||||
react-router "^4.1.1"
|
||||
prop-types "^15.6.1"
|
||||
react-router "^4.3.1"
|
||||
warning "^4.0.1"
|
||||
|
||||
react-router@^2.5.1:
|
||||
version "2.8.1"
|
||||
resolved "https://registry.yarnpkg.com/react-router/-/react-router-2.8.1.tgz#73e9491f6ceb316d0f779829081863e378ee4ed7"
|
||||
react-router@^4.3.1:
|
||||
version "4.3.1"
|
||||
resolved "https://registry.yarnpkg.com/react-router/-/react-router-4.3.1.tgz#aada4aef14c809cb2e686b05cee4742234506c4e"
|
||||
dependencies:
|
||||
history "^2.1.2"
|
||||
hoist-non-react-statics "^1.2.0"
|
||||
invariant "^2.2.1"
|
||||
loose-envify "^1.2.0"
|
||||
warning "^3.0.0"
|
||||
|
||||
react-router@^4.1.1:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/react-router/-/react-router-4.1.1.tgz#d448f3b7c1b429a6fbb03395099949c606b1fe95"
|
||||
dependencies:
|
||||
history "^4.6.0"
|
||||
hoist-non-react-statics "^1.2.0"
|
||||
invariant "^2.2.2"
|
||||
history "^4.7.2"
|
||||
hoist-non-react-statics "^2.5.0"
|
||||
invariant "^2.2.4"
|
||||
loose-envify "^1.3.1"
|
||||
path-to-regexp "^1.5.3"
|
||||
prop-types "^15.5.4"
|
||||
warning "^3.0.0"
|
||||
path-to-regexp "^1.7.0"
|
||||
prop-types "^15.6.1"
|
||||
warning "^4.0.1"
|
||||
|
||||
react@^16.0.0:
|
||||
version "16.0.0"
|
||||
resolved "https://registry.yarnpkg.com/react/-/react-16.0.0.tgz#ce7df8f1941b036f02b2cca9dbd0cb1f0e855e2d"
|
||||
react@^16.4.1:
|
||||
version "16.4.1"
|
||||
resolved "https://registry.yarnpkg.com/react/-/react-16.4.1.tgz#de51ba5764b5dbcd1f9079037b862bd26b82fe32"
|
||||
dependencies:
|
||||
fbjs "^0.8.16"
|
||||
loose-envify "^1.1.0"
|
||||
@@ -6848,6 +6987,10 @@ require-directory@^2.1.1:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
|
||||
|
||||
require-from-string@^2.0.1:
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909"
|
||||
|
||||
require-main-filename@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1"
|
||||
@@ -6877,9 +7020,9 @@ resolve-from@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748"
|
||||
|
||||
resolve-pathname@^2.0.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/resolve-pathname/-/resolve-pathname-2.1.0.tgz#e8358801b86b83b17560d4e3c382d7aef2100944"
|
||||
resolve-pathname@^2.2.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/resolve-pathname/-/resolve-pathname-2.2.0.tgz#7e9ae21ed815fd63ab189adeee64dc831eefa879"
|
||||
|
||||
resolve-url@^0.2.1:
|
||||
version "0.2.1"
|
||||
@@ -7345,7 +7488,7 @@ source-map@0.5.6, source-map@^0.5.6:
|
||||
version "0.5.6"
|
||||
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412"
|
||||
|
||||
source-map@0.5.x, source-map@^0.5.3, source-map@~0.5.1, source-map@~0.5.6:
|
||||
source-map@0.5.x, source-map@^0.5.3, source-map@^0.5.7, source-map@~0.5.1, source-map@~0.5.6:
|
||||
version "0.5.7"
|
||||
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
|
||||
|
||||
@@ -7359,6 +7502,10 @@ source-map@^0.6.1, source-map@~0.6.1:
|
||||
version "0.6.1"
|
||||
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
|
||||
|
||||
source-map@^0.7.2:
|
||||
version "0.7.3"
|
||||
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383"
|
||||
|
||||
sourcemapped-stacktrace@^1.1.6:
|
||||
version "1.1.8"
|
||||
resolved "https://registry.yarnpkg.com/sourcemapped-stacktrace/-/sourcemapped-stacktrace-1.1.8.tgz#6b7a3f1a6fb15f6d40e701e23ce404553480d688"
|
||||
@@ -7618,6 +7765,14 @@ style-loader@^0.20.2:
|
||||
loader-utils "^1.1.0"
|
||||
schema-utils "^0.4.3"
|
||||
|
||||
stylis-rule-sheet@^0.0.10:
|
||||
version "0.0.10"
|
||||
resolved "https://registry.yarnpkg.com/stylis-rule-sheet/-/stylis-rule-sheet-0.0.10.tgz#44e64a2b076643f4b52e5ff71efc04d8c3c4a430"
|
||||
|
||||
stylis@^3.5.0:
|
||||
version "3.5.1"
|
||||
resolved "https://registry.yarnpkg.com/stylis/-/stylis-3.5.1.tgz#fd341d59f57f9aeb412bc14c9d8a8670b438e03b"
|
||||
|
||||
supports-color@1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-1.2.0.tgz#ff1ed1e61169d06b3cf2d588e188b18d8847e17e"
|
||||
@@ -7854,6 +8009,12 @@ toposort@^1.0.0:
|
||||
version "1.0.6"
|
||||
resolved "https://registry.yarnpkg.com/toposort/-/toposort-1.0.6.tgz#c31748e55d210effc00fdcdc7d6e68d7d7bb9cec"
|
||||
|
||||
touch@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/touch/-/touch-1.0.0.tgz#449cbe2dbae5a8c8038e30d71fa0ff464947c4de"
|
||||
dependencies:
|
||||
nopt "~1.0.10"
|
||||
|
||||
tough-cookie@>=2.3.3, tough-cookie@^2.3.3, tough-cookie@~2.3.0, tough-cookie@~2.3.3:
|
||||
version "2.3.3"
|
||||
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.3.tgz#0b618a5565b6dea90bf3425d04d55edc475a7561"
|
||||
@@ -8140,9 +8301,9 @@ validate-npm-package-license@^3.0.1:
|
||||
spdx-correct "~1.0.0"
|
||||
spdx-expression-parse "~1.0.0"
|
||||
|
||||
value-equal@^0.2.0:
|
||||
version "0.2.1"
|
||||
resolved "https://registry.yarnpkg.com/value-equal/-/value-equal-0.2.1.tgz#c220a304361fce6994dbbedaa3c7e1a1b895871d"
|
||||
value-equal@^0.4.0:
|
||||
version "0.4.0"
|
||||
resolved "https://registry.yarnpkg.com/value-equal/-/value-equal-0.4.0.tgz#c5bdd2f54ee093c04839d71ce2e4758a6890abc7"
|
||||
|
||||
vary@~1.1.2:
|
||||
version "1.1.2"
|
||||
@@ -8168,18 +8329,18 @@ vm-browserify@0.0.4:
|
||||
dependencies:
|
||||
indexof "0.0.1"
|
||||
|
||||
warning@^2.0.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/warning/-/warning-2.1.0.tgz#21220d9c63afc77a8c92111e011af705ce0c6901"
|
||||
dependencies:
|
||||
loose-envify "^1.0.0"
|
||||
|
||||
warning@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/warning/-/warning-3.0.0.tgz#32e5377cb572de4ab04753bdf8821c01ed605b7c"
|
||||
dependencies:
|
||||
loose-envify "^1.0.0"
|
||||
|
||||
warning@^4.0.1:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/warning/-/warning-4.0.1.tgz#66ce376b7fbfe8a887c22bdf0e7349d73d397745"
|
||||
dependencies:
|
||||
loose-envify "^1.0.0"
|
||||
|
||||
watchpack@^1.4.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.4.0.tgz#4a1472bcbb952bd0a9bb4036801f954dfb39faac"
|
||||
|
Reference in New Issue
Block a user