2018-02-21 20:19:56 -05:00
|
|
|
import React from 'react'
|
2018-07-01 15:13:29 -06:00
|
|
|
import styled from 'react-emotion'
|
|
|
|
import {
|
|
|
|
HashRouter,
|
|
|
|
Link as RouterLink,
|
|
|
|
Route,
|
|
|
|
Redirect,
|
|
|
|
Switch,
|
|
|
|
} from 'react-router-dom'
|
2018-02-21 20:19:56 -05:00
|
|
|
|
2019-01-11 10:32:06 -08:00
|
|
|
import { Icon } from './components'
|
2018-02-21 20:19:56 -05:00
|
|
|
import CheckLists from './check-lists'
|
|
|
|
import CodeHighlighting from './code-highlighting'
|
|
|
|
import Embeds from './embeds'
|
|
|
|
import Emojis from './emojis'
|
|
|
|
import ForcedLayout from './forced-layout'
|
|
|
|
import History from './history'
|
2018-09-25 22:33:11 +02:00
|
|
|
import Versions from './versions'
|
2018-02-21 20:19:56 -05:00
|
|
|
import HoveringMenu from './hovering-menu'
|
|
|
|
import HugeDocument from './huge-document'
|
|
|
|
import Images from './images'
|
|
|
|
import Links from './links'
|
|
|
|
import MarkdownPreview from './markdown-preview'
|
|
|
|
import MarkdownShortcuts from './markdown-shortcuts'
|
|
|
|
import PasteHtml from './paste-html'
|
|
|
|
import PlainText from './plain-text'
|
|
|
|
import Plugins from './plugins'
|
|
|
|
import RTL from './rtl'
|
|
|
|
import ReadOnly from './read-only'
|
|
|
|
import RichText from './rich-text'
|
|
|
|
import SearchHighlighting from './search-highlighting'
|
2019-03-08 10:14:52 -08:00
|
|
|
import Composition from './composition'
|
2018-08-09 20:30:23 -07:00
|
|
|
import InputTester from './input-tester'
|
2018-02-21 20:19:56 -05:00
|
|
|
import SyncingOperations from './syncing-operations'
|
|
|
|
import Tables from './tables'
|
2018-10-16 20:14:22 -07:00
|
|
|
import Mentions from './mentions'
|
2019-04-02 14:23:50 +01:00
|
|
|
import Placeholder from './placeholder'
|
2018-02-21 20:19:56 -05:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Examples.
|
|
|
|
*
|
|
|
|
* @type {Array}
|
|
|
|
*/
|
|
|
|
|
|
|
|
const EXAMPLES = [
|
2019-01-11 10:32:06 -08:00
|
|
|
['Check Lists', CheckLists, '/check-lists'],
|
|
|
|
['Code Highlighting', CodeHighlighting, '/code-highlighting'],
|
2019-03-08 10:14:52 -08:00
|
|
|
['Composition', Composition, '/composition/:subpage?'],
|
2018-02-21 20:19:56 -05:00
|
|
|
['Embeds', Embeds, '/embeds'],
|
|
|
|
['Emojis', Emojis, '/emojis'],
|
2019-01-11 10:32:06 -08:00
|
|
|
['Forced Layout', ForcedLayout, '/forced-layout'],
|
|
|
|
['History', History, '/history'],
|
|
|
|
['Hovering Menu', HoveringMenu, '/hovering-menu'],
|
|
|
|
['Huge Document', HugeDocument, '/huge-document'],
|
|
|
|
['Images', Images, '/images'],
|
|
|
|
['Input Tester', InputTester, '/input-tester'],
|
|
|
|
['Links', Links, '/links'],
|
2018-02-21 20:19:56 -05:00
|
|
|
['Markdown Preview', MarkdownPreview, '/markdown-preview'],
|
|
|
|
['Markdown Shortcuts', MarkdownShortcuts, '/markdown-shortcuts'],
|
2019-01-11 10:32:06 -08:00
|
|
|
['Mentions', Mentions, '/mentions'],
|
2018-02-21 20:19:56 -05:00
|
|
|
['Paste HTML', PasteHtml, '/paste-html'],
|
2019-04-02 14:23:50 +01:00
|
|
|
['Placeholders', Placeholder, '/placeholders'],
|
2019-01-11 10:32:06 -08:00
|
|
|
['Plain Text', PlainText, '/plain-text'],
|
|
|
|
['Plugins', Plugins, '/plugins'],
|
2018-02-21 20:19:56 -05:00
|
|
|
['Read-only', ReadOnly, '/read-only'],
|
2019-01-11 10:32:06 -08:00
|
|
|
['Rich Text', RichText, '/rich-text'],
|
2018-02-21 20:19:56 -05:00
|
|
|
['RTL', RTL, '/rtl'],
|
2019-01-11 10:32:06 -08:00
|
|
|
['Search Highlighting', SearchHighlighting, '/search-highlighting'],
|
|
|
|
['Syncing Operations', SyncingOperations, '/syncing-operations'],
|
|
|
|
['Tables', Tables, '/tables'],
|
2018-09-25 22:33:11 +02:00
|
|
|
['Versions', Versions, '/versions'],
|
2018-02-21 20:19:56 -05:00
|
|
|
]
|
|
|
|
|
2018-07-01 15:13:29 -06:00
|
|
|
/**
|
|
|
|
* Some styled components.
|
|
|
|
*
|
|
|
|
* @type {Component}
|
|
|
|
*/
|
|
|
|
|
2019-01-11 10:32:06 -08:00
|
|
|
const Header = styled('div')`
|
|
|
|
align-items: center;
|
2018-07-01 15:13:29 -06:00
|
|
|
background: #000;
|
2019-01-11 10:32:06 -08:00
|
|
|
color: #aaa;
|
|
|
|
display: flex;
|
|
|
|
height: 42px;
|
|
|
|
position: relative;
|
|
|
|
z-index: 1; /* To appear above the underlay */
|
2018-07-01 15:13:29 -06:00
|
|
|
`
|
|
|
|
|
|
|
|
const Title = styled('span')`
|
2019-01-11 10:32:06 -08:00
|
|
|
margin-left: 1em;
|
2018-07-01 15:13:29 -06:00
|
|
|
`
|
|
|
|
|
|
|
|
const LinkList = styled('div')`
|
2019-01-11 10:32:06 -08:00
|
|
|
margin-left: auto;
|
|
|
|
margin-right: 1em;
|
2018-07-01 15:13:29 -06:00
|
|
|
`
|
|
|
|
|
|
|
|
const Link = styled('a')`
|
|
|
|
margin-left: 1em;
|
|
|
|
color: #aaa;
|
|
|
|
text-decoration: none;
|
|
|
|
|
|
|
|
&:hover {
|
|
|
|
color: #fff;
|
|
|
|
text-decoration: underline;
|
|
|
|
}
|
|
|
|
`
|
|
|
|
|
|
|
|
const TabList = styled('div')`
|
|
|
|
background-color: #222;
|
2019-01-11 10:32:06 -08:00
|
|
|
display: flex;
|
|
|
|
flex-direction: column;
|
|
|
|
overflow: hidden;
|
|
|
|
padding-top: 0.2em;
|
|
|
|
position: absolute;
|
|
|
|
transition: width 0.2s;
|
|
|
|
width: ${props => (props.isVisible ? '200px' : '0')};
|
|
|
|
white-space: nowrap;
|
|
|
|
z-index: 1; /* To appear above the underlay */
|
|
|
|
`
|
|
|
|
|
|
|
|
const TabListUnderlay = styled('div')`
|
|
|
|
background-color: rgba(200, 200, 200, 0.8);
|
|
|
|
display: ${props => (props.isVisible ? 'block' : 'none')};
|
|
|
|
height: 100%;
|
|
|
|
top: 0;
|
|
|
|
position: fixed;
|
|
|
|
width: 100%;
|
|
|
|
`
|
2018-07-01 15:13:29 -06:00
|
|
|
|
2019-01-11 10:32:06 -08:00
|
|
|
const TabButton = styled('span')`
|
|
|
|
margin-left: 0.8em;
|
|
|
|
|
|
|
|
&:hover {
|
|
|
|
cursor: pointer;
|
|
|
|
}
|
|
|
|
|
|
|
|
.material-icons {
|
|
|
|
color: #aaa;
|
|
|
|
font-size: 24px;
|
2018-07-01 15:13:29 -06:00
|
|
|
}
|
|
|
|
`
|
|
|
|
|
2018-08-09 20:30:23 -07:00
|
|
|
const MaskedRouterLink = ({ active, ...props }) => <RouterLink {...props} />
|
|
|
|
|
|
|
|
const Tab = styled(MaskedRouterLink)`
|
2018-07-01 15:13:29 -06:00
|
|
|
display: inline-block;
|
|
|
|
margin-bottom: 0.2em;
|
2019-01-11 10:32:06 -08:00
|
|
|
padding: 0.2em 1em;
|
2018-07-01 15:13:29 -06:00
|
|
|
border-radius: 0.2em;
|
|
|
|
text-decoration: none;
|
2018-08-01 11:55:45 -07:00
|
|
|
color: ${p => (p.active ? 'white' : '#777')};
|
|
|
|
background: ${p => (p.active ? '#333' : 'transparent')};
|
2018-07-01 15:13:29 -06:00
|
|
|
|
|
|
|
&:hover {
|
|
|
|
background: #333;
|
|
|
|
}
|
|
|
|
`
|
|
|
|
|
|
|
|
const Wrapper = styled('div')`
|
|
|
|
max-width: 42em;
|
2019-01-11 10:32:06 -08:00
|
|
|
margin: 20px auto;
|
2018-07-01 15:13:29 -06:00
|
|
|
padding: 20px;
|
|
|
|
`
|
|
|
|
|
2019-01-11 10:32:06 -08:00
|
|
|
const ExampleHeader = styled('div')`
|
|
|
|
align-items: center;
|
|
|
|
background-color: #555;
|
|
|
|
color: #ddd;
|
|
|
|
display: flex;
|
|
|
|
height: 42px;
|
|
|
|
position: relative;
|
|
|
|
z-index: 1; /* To appear above the underlay */
|
|
|
|
`
|
|
|
|
|
|
|
|
const ExampleTitle = styled('span')`
|
|
|
|
margin-left: 1em;
|
|
|
|
`
|
|
|
|
|
|
|
|
const ExampleContent = styled(Wrapper)`
|
2018-07-01 15:13:29 -06:00
|
|
|
background: #fff;
|
|
|
|
`
|
|
|
|
|
|
|
|
const Warning = styled(Wrapper)`
|
|
|
|
background: #fffae0;
|
|
|
|
|
|
|
|
& > pre {
|
|
|
|
background: #fbf1bd;
|
|
|
|
white-space: pre;
|
|
|
|
overflow-x: scroll;
|
|
|
|
margin-bottom: 0;
|
|
|
|
}
|
|
|
|
`
|
|
|
|
|
2018-02-21 20:19:56 -05:00
|
|
|
/**
|
|
|
|
* App.
|
|
|
|
*
|
|
|
|
* @type {Component}
|
|
|
|
*/
|
|
|
|
|
|
|
|
export default class App extends React.Component {
|
2018-07-01 15:13:29 -06:00
|
|
|
/**
|
|
|
|
* Initial state.
|
|
|
|
*
|
|
|
|
* @type {Object}
|
|
|
|
*/
|
|
|
|
|
2018-02-21 20:19:56 -05:00
|
|
|
state = {
|
|
|
|
error: null,
|
|
|
|
info: null,
|
2019-01-11 10:32:06 -08:00
|
|
|
isTabListVisible: false,
|
2018-02-21 20:19:56 -05:00
|
|
|
}
|
|
|
|
|
2018-07-01 15:13:29 -06:00
|
|
|
/**
|
|
|
|
* Catch the `error` and `info`.
|
|
|
|
*
|
|
|
|
* @param {Error} error
|
|
|
|
* @param {Object} info
|
|
|
|
*/
|
|
|
|
|
2018-02-21 20:19:56 -05:00
|
|
|
componentDidCatch(error, info) {
|
|
|
|
this.setState({ error, info })
|
|
|
|
}
|
|
|
|
|
2018-07-01 15:13:29 -06:00
|
|
|
/**
|
|
|
|
* Render the example app.
|
|
|
|
*
|
|
|
|
* @return {Element}
|
|
|
|
*/
|
|
|
|
|
2018-02-21 20:19:56 -05:00
|
|
|
render() {
|
|
|
|
return (
|
|
|
|
<HashRouter>
|
2018-07-01 15:13:29 -06:00
|
|
|
<div>
|
2019-01-11 10:32:06 -08:00
|
|
|
{this.renderHeader()}
|
|
|
|
{this.renderExampleHeader()}
|
|
|
|
{this.renderTabList()}
|
|
|
|
{this.state.error ? this.renderError() : this.renderExample()}
|
|
|
|
<TabListUnderlay
|
|
|
|
isVisible={this.state.isTabListVisible}
|
|
|
|
onClick={this._hideTabList}
|
|
|
|
/>
|
2018-02-21 20:19:56 -05:00
|
|
|
</div>
|
|
|
|
</HashRouter>
|
|
|
|
)
|
|
|
|
}
|
2019-01-11 10:32:06 -08:00
|
|
|
|
|
|
|
renderError() {
|
|
|
|
return (
|
|
|
|
<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>
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
renderExample() {
|
|
|
|
return (
|
|
|
|
<Switch>
|
|
|
|
{EXAMPLES.map(([name, Component, path]) => (
|
|
|
|
<Route key={path} path={path}>
|
2019-03-08 10:14:52 -08:00
|
|
|
{({ match }) => (
|
|
|
|
<div>
|
|
|
|
<ExampleContent>
|
|
|
|
<Component params={match.params} />
|
|
|
|
</ExampleContent>
|
|
|
|
</div>
|
|
|
|
)}
|
2019-01-11 10:32:06 -08:00
|
|
|
</Route>
|
|
|
|
))}
|
|
|
|
<Redirect from="/" to="/rich-text" />
|
|
|
|
</Switch>
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
renderExampleHeader() {
|
|
|
|
return (
|
|
|
|
<ExampleHeader>
|
|
|
|
<TabButton
|
|
|
|
onClick={e => {
|
|
|
|
e.stopPropagation()
|
|
|
|
|
|
|
|
this.setState({
|
|
|
|
isTabListVisible: !this.state.isTabListVisible,
|
|
|
|
})
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
<Icon>menu</Icon>
|
|
|
|
</TabButton>
|
|
|
|
<Switch>
|
|
|
|
{EXAMPLES.map(([name, Component, path]) => (
|
2019-01-28 19:18:03 -08:00
|
|
|
<Route key={path} exact path={path}>
|
2019-02-19 21:11:17 +01:00
|
|
|
<ExampleTitle>
|
|
|
|
{name}
|
|
|
|
<Link
|
|
|
|
href={`https://github.com/ianstormtaylor/slate/blob/master/examples${path}`}
|
|
|
|
>
|
|
|
|
(View Source)
|
|
|
|
</Link>
|
|
|
|
</ExampleTitle>
|
2019-01-11 10:32:06 -08:00
|
|
|
</Route>
|
|
|
|
))}
|
|
|
|
</Switch>
|
|
|
|
</ExampleHeader>
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
renderHeader() {
|
|
|
|
return (
|
|
|
|
<Header>
|
|
|
|
<Title>Slate Examples</Title>
|
|
|
|
<LinkList>
|
|
|
|
<Link href="https://github.com/ianstormtaylor/slate">GitHub</Link>
|
|
|
|
<Link href="https://docs.slatejs.org/">Docs</Link>
|
|
|
|
</LinkList>
|
|
|
|
</Header>
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
renderTabList() {
|
|
|
|
return (
|
|
|
|
<TabList isVisible={this.state.isTabListVisible}>
|
|
|
|
{EXAMPLES.map(([name, Component, path]) => (
|
|
|
|
<Route key={path} exact path={path}>
|
|
|
|
{({ match }) => (
|
|
|
|
<Tab
|
|
|
|
to={path}
|
|
|
|
active={match && match.isExact}
|
|
|
|
onClick={this._hideTabList}
|
|
|
|
>
|
|
|
|
{name}
|
|
|
|
</Tab>
|
|
|
|
)}
|
|
|
|
</Route>
|
|
|
|
))}
|
|
|
|
</TabList>
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
_hideTabList = () => {
|
|
|
|
this.setState({ isTabListVisible: false })
|
|
|
|
}
|
2018-02-21 20:19:56 -05:00
|
|
|
}
|