Skip to content

Commit 85f9bf6

Browse files
author
Benjamin Kniffler
committed
Merge branch 'toolbar-plugin' into dndV2
2 parents 71a98ac + b8e42fb commit 85f9bf6

32 files changed

+1138
-61
lines changed

docs/client/components/pages/Dnd/SimpleDndEditor/index.js

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,18 @@ import React, { Component } from 'react';
22
import { EditorState, Entity } from 'draft-js';
33
import Editor from 'draft-js-plugins-editor';
44
import createDndPlugin from 'draft-js-dnd-plugin';
5+
import createToolbarPlugin from 'draft-js-toolbar-plugin';
56
import styles from './styles.css';
67
import mockUpload from '../utils/mockUpload';
78
import addBlock from 'draft-js-dnd-plugin/modifiers/addBlock';
9+
import TextToolbar from 'draft-js-toolbar-plugin/components/text-toolbar';
810

9-
import PreviewGithub from '../components/preview-github';
11+
import PlaceholderGithub from '../components/placeholder-github';
1012
import BlockImage from '../components/block-image';
1113
import BlockText from '../components/block-text';
1214
import cleanupEmpty from '../utils/cleanupEmpty';
1315

16+
const toolbarPlugin = createToolbarPlugin({});
1417
const dndPlugin = createDndPlugin({
1518
allowDrop: true,
1619
handleUpload: (data, success, failed, progress) =>
@@ -20,7 +23,7 @@ const dndPlugin = createDndPlugin({
2023
if (type.indexOf('image/') === 0) {
2124
return addBlock(state, state.getSelection(), 'block-image', data);
2225
} else if (type.indexOf('text/') === 0 || type === 'application/json') {
23-
return addBlock(state, state.getSelection(), 'preview-github', data);
26+
return addBlock(state, state.getSelection(), 'placeholder-github', data);
2427
} return state;
2528
}, handleBlock: (state, selection, data) => {
2629
const { type } = data;
@@ -63,11 +66,11 @@ class SimpleDndEditor extends Component {
6366

6467
blockRendererFn = (contentBlock) => {
6568
const type = contentBlock.getType();
66-
if (type === 'preview-github') {
69+
if (type === 'placeholder-github') {
6770
const entityKey = contentBlock.getEntityAt(0);
6871
const data = entityKey ? Entity.get(entityKey).data : {};
6972
return {
70-
component: PreviewGithub,
73+
component: PlaceholderGithub,
7174
props: { ...data },
7275
};
7376
} else if (type === 'block-text') {
@@ -84,6 +87,7 @@ class SimpleDndEditor extends Component {
8487
component: BlockImage,
8588
props: {
8689
...data,
90+
toolbarTheme: toolbarPlugin.theme,
8791
refreshEditorState: () => {
8892
const { editorState } = this.state;
8993
this.onChange(EditorState.forceSelection(editorState, editorState.getCurrentContent().getSelectionAfter()));
@@ -105,9 +109,10 @@ class SimpleDndEditor extends Component {
105109
<Editor editorState={editorState}
106110
onChange={this.onChange}
107111
blockRendererFn={this.blockRendererFn}
108-
plugins={[dndPlugin]}
112+
plugins={[dndPlugin, toolbarPlugin]}
109113
ref="editor"
110114
/>
115+
<TextToolbar editorState={ editorState } plugin={toolbarPlugin} onChange={this.onChange} />
111116
</div>
112117
);
113118
}

docs/client/components/pages/Dnd/components/block-image.js

Lines changed: 29 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,65 +1,52 @@
11
import React, { Component } from 'react';
22
import Draggable from 'draft-js-dnd-plugin/components/block-draggable-wrapper';
33
import Alignment from 'draft-js-dnd-plugin/components/block-alignment-wrapper';
4+
import Toolbar from 'draft-js-toolbar-plugin/components/hover-toolbar';
45
import imageStyles from './image.css';
56

67
class BlockImage extends Component {
7-
remove = (event) => {
8-
event.preventDefault();
9-
event.stopPropagation();
10-
11-
this.props.blockProps.onRemove(this.props.block.getKey());
12-
};
13-
14-
alignLeft = () => {
15-
this.props.align('left');
16-
};
17-
18-
alignCenter = () => {
19-
this.props.align('center');
20-
};
21-
22-
alignRight = () => {
23-
this.props.align('right');
24-
};
8+
renderProgress = progress => {
9+
if (progress >= 0) {
10+
return (
11+
<div className={imageStyles.imageLoader} style={{ width: `${100 - progress}%` }} />
12+
);
13+
} return null;
14+
}
2515

2616
render() {
2717
const { blockProps, block, alignment, onDragStart, draggable } = this.props;
2818

29-
const buttons = [
30-
<span className={ imageStyles.imageButton }
31-
onClick={this.alignLeft}
32-
style={{ marginLeft: '-2.4em' }}
33-
role="button" key={'left'}
34-
>
35-
L
36-
</span>,
37-
<span className={ imageStyles.imageButton }
38-
onClick={this.alignCenter}
39-
role="button" key={'center'}
40-
>
41-
C
42-
</span>,
43-
<span className={ imageStyles.imageButton }
44-
onClick={this.alignRight}
45-
style={{ marginLeft: '0.9em' }}
46-
role="button" key={'right'}
47-
>
48-
R
49-
</span>,
19+
const actions = [
20+
{
21+
active: alignment === 'left',
22+
button: <span>L</span>,
23+
toggle: () => this.props.align('left'),
24+
label: 'Align left',
25+
}, {
26+
active: !alignment || alignment === 'center',
27+
button: <span>C</span>,
28+
toggle: () => this.props.align('center'),
29+
label: 'Align center',
30+
}, {
31+
active: alignment === 'right',
32+
button: <span>R</span>,
33+
toggle: () => this.props.align('right'),
34+
label: 'Align right',
35+
},
5036
];
5137

5238
const className = `${imageStyles.imageWrapper} ${imageStyles[alignment || 'center']}`;
5339

40+
const key = `${block.get('key')}-0-0`;
5441
return (
5542
<figure className={ className }
5643
contentEditable={false}
57-
data-offset-key={ `${block.get('key')}-0-0` }
44+
data-offset-key={ key }
5845
onDragStart={onDragStart} draggable={draggable}
5946
>
6047
<img src={blockProps.src || blockProps.url} width="100%" height="auto" className={ imageStyles.image } />
61-
{blockProps.progress >= 0 ? <div className={imageStyles.imageLoader} style={{ width: `${100 - blockProps.progress}%` }} /> : null}
62-
{buttons}
48+
{this.renderProgress(blockProps.progress)}
49+
<Toolbar parent={ `figure[data-offset-key="${key}"]` } theme={blockProps.toolbarTheme} actions={actions} />
6350
</figure>
6451
);
6552
}
Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,24 @@
1-
import React, { Component } from 'react';
1+
import React, {Component} from 'react';
22
import Container from '../../shared/Container';
33
import Heading from '../../shared/Heading';
4-
import SimpleUploadEditor from './SimpleDndEditor';
4+
import SimpleDndEditor from './SimpleDndEditor';
55
import NavBar from '../../shared/NavBar';
66
import Separator from '../../shared/Separator';
77

88
export default class App extends Component {
99
render() {
1010
return (
11-
<div>
12-
<NavBar />
13-
<Separator />
14-
<Container>
15-
<Heading level={ 2 }>Drag & Drop</Heading>
16-
</Container>
17-
<Container>
18-
<Heading level={ 2 }>Simple Example</Heading>
19-
<SimpleUploadEditor />
20-
</Container>
21-
</div>
22-
);
11+
<div>
12+
<NavBar />
13+
<Separator />
14+
<Container>
15+
<Heading level={ 2 }>Drag & Drop</Heading>
16+
</Container>
17+
<Container>
18+
<Heading level={ 2 }>Simple Example</Heading>
19+
<SimpleDndEditor />
20+
</Container>
21+
</div>
22+
);
2323
}
2424
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import React, { Component } from 'react';
2+
import Editor, { createEditorStateWithText } from 'draft-js-plugins-editor';
3+
import TextToolbar from 'draft-js-toolbar-plugin/components/text-toolbar';
4+
import createToolbarPlugin from 'draft-js-toolbar-plugin';
5+
import styles from './styles.css';
6+
7+
const toolbarPlugin = createToolbarPlugin({});
8+
const text = `Cool, we can have all sorts of Emojis here. 🙌
9+
🌿☃️🎉🙈 aaaand maybe a few more here 🐲☀️🗻 Quite fun!`;
10+
11+
class SimpleToolbarEditor extends Component {
12+
state = {
13+
editorState: createEditorStateWithText(text),
14+
draggingOver: false,
15+
};
16+
17+
onChange = (editorState) => {
18+
// console.log(convertToRaw(editorState.getCurrentContent()));
19+
this.setState({
20+
editorState,
21+
});
22+
};
23+
24+
focus = () => {
25+
this.refs.editor.focus();
26+
};
27+
28+
render() {
29+
const { editorState } = this.state;
30+
31+
const classNames = [styles.editor];
32+
return (
33+
<div className={classNames.join(' ')} onClick={this.focus}>
34+
<Editor editorState={ editorState } onChange={this.onChange} plugins={[toolbarPlugin]} ref="editor" />
35+
<TextToolbar editorState={ editorState } theme={toolbarPlugin.theme} onChange={this.onChange} />
36+
</div>
37+
);
38+
}
39+
}
40+
41+
export default SimpleToolbarEditor;
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
.editor {
2+
border: 1px solid #ddd;
3+
cursor: text;
4+
padding: 16px;
5+
border-radius: 4px;
6+
margin-bottom: 2em;
7+
box-shadow: inset 0px 1px 8px -3px #ABABAB;
8+
background: #fefefe;
9+
/*Important to grow with floating children*/
10+
overflow: hidden;
11+
}
12+
13+
@keyframes border-pulsate {
14+
0% { outline-color: rgba(0, 255, 80, .5); }
15+
50% { outline-color: rgba(0, 255, 80, .01); }
16+
100% { outline-color: rgba(0, 255, 80, .5); }
17+
}
18+
19+
.uploading {
20+
outline: 2px solid rgba(0, 255, 80, .5);
21+
animation: border-pulsate 2s infinite;
22+
}
23+
24+
.dnd {
25+
outline: 3px solid rgba(0, 255, 80, .5);
26+
}
27+
28+
.editor :global(.public-DraftEditor-content) {
29+
min-height: 140px;
30+
}
31+
32+
.editorOptions {
33+
margin-bottom: 20px;
34+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import React, { Component } from 'react';
2+
import Container from '../../shared/Container';
3+
import Heading from '../../shared/Heading';
4+
import SimpleToolbarEditor from './SimpleToolbarEditor';
5+
import NavBar from '../../shared/NavBar';
6+
import Separator from '../../shared/Separator';
7+
8+
export default class App extends Component {
9+
render() {
10+
return (
11+
<div>
12+
<NavBar />
13+
<Separator />
14+
<Container>
15+
<Heading level={ 2 }>Drag & Drop</Heading>
16+
</Container>
17+
<Container>
18+
<Heading level={ 2 }>Simple Example</Heading>
19+
<SimpleToolbarEditor />
20+
</Container>
21+
</div>
22+
);
23+
}
24+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
.root {
2+
text-align: center;
3+
padding-top: 10em;
4+
}
5+
6+
.param {
7+
margin: 10px 0;
8+
}
9+
10+
.paramBig {
11+
margin: 10px 0;
12+
display: flex;
13+
}
14+
15+
.paramName {
16+
font-weight: bold;
17+
width: 175px;
18+
min-width: 175px;
19+
display: inline-block;
20+
}
21+
22+
.subParams {
23+
margin-left: 175px;
24+
margin-top: 10px;
25+
}
26+
27+
.subParam {
28+
margin-bottom: 5px;
29+
display: flex;
30+
}
31+
32+
.subParamName {
33+
font-weight: bold;
34+
margin-right: 5px;
35+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
2+
3+
export default function mockUpload(data, success, failed, progress) {
4+
// Mock file upload, actually only happens client side
5+
const reader = new FileReader();
6+
7+
// This is called when finished reading
8+
reader.onload = e => {
9+
// Return an array with one image
10+
const x = {
11+
// These are attributes like size, name, type, ...
12+
...data.files[0],
13+
14+
// This is the files content as base64
15+
src: e.target.result,
16+
17+
// No URL, since nothing on server
18+
url: null,
19+
};
20+
success([x]);
21+
};
22+
23+
function doProgress(percent) {
24+
progress(percent || 1);
25+
if (percent === 100) {
26+
// Start reading the file
27+
reader.readAsDataURL(data.files[0]);
28+
} else {
29+
setTimeout(doProgress, 250, (percent || 0) + 10);
30+
}
31+
}
32+
33+
doProgress();
34+
}

docs/client/routes.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import Sticker from './components/pages/Sticker';
1212
import Undo from './components/pages/Undo';
1313
import Mention from './components/pages/Mention';
1414
import Dnd from './components/pages/Dnd';
15+
import Toolbar from './components/pages/Toolbar';
1516
import Playground from './components/pages/Playground';
1617

1718
export const routes = (
@@ -25,6 +26,7 @@ export const routes = (
2526
<Route path="plugin/undo" title="App - Undo" component={Undo} />
2627
<Route path="plugin/mention" title="App - Mention" component={Mention} />
2728
<Route path="plugin/dnd" title="App - Drag & Drop" component={Dnd} />
29+
<Route path="plugin/toolbar" title="App - Toolbar" component={Toolbar} />
2830
</Route>
2931
<Route path="playground" title="App - Development Playground" component={Playground} />
3032
<Route path="*" title="404: Not Found" component={NotFound} />

0 commit comments

Comments
 (0)