Skip to content
This repository was archived by the owner on May 31, 2020. It is now read-only.

Commit 1072ea5

Browse files
committed
- update atomic block plugin with some behaviours
- add utility methods - add editorRef to plugin and editor props
1 parent 630b4f8 commit 1072ea5

File tree

10 files changed

+329
-114
lines changed

10 files changed

+329
-114
lines changed

examples/block-switcher/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"name": "@djsp/block-insert",
2+
"name": "@djsp/block-switcher",
33
"homepage": "https://juliankrispel.github.io/@djsp/core",
44
"version": "0.1.0",
55
"private": true,

packages/atomic-block/.flowconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
.*/node_modules/@octokit/.*
55
.*/node_modules/@types/.*
66
.*/node_modules/\([a-c]\|[g-h]\|e\|[j-z]\).*/.*
7+
.*/EditorContainer/.*
78

89

910
[include]

packages/atomic-block/rollup.config.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,12 @@ import url from 'rollup-plugin-url'
88
import pkg from './package.json'
99

1010
export default {
11-
external: ['@djsp/core', 'draft-js'],
11+
external: [
12+
'draft-js/lib/DraftOffsetKey',
13+
'@djsp/core',
14+
'@djsp/utils',
15+
'draft-js',
16+
],
1217
input: 'src/index.js',
1318
output: [
1419
{

packages/atomic-block/src/AtomicBlock.js

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import React, { Component } from 'react'
44
import type { Node } from 'react'
5-
import styles from './styles.css'
65

76
type Props = {
87
onClick: (event: SyntheticMouseEvent<*>) => void,
@@ -12,14 +11,8 @@ type Props = {
1211

1312
export default class AtomicBlock extends Component<Props> {
1413
render() {
15-
const { onClick, children, isFocused } = this.props
16-
const classNames = []
17-
if (isFocused) classNames.push(styles.focused)
14+
const { onClick, children } = this.props
1815

19-
return (
20-
<div className={classNames} onClick={onClick}>
21-
{children}
22-
</div>
23-
)
16+
return <div onClick={onClick}>{children}</div>
2417
}
2518
}

packages/atomic-block/src/index.js

Lines changed: 112 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
// @flow
22

33
import React, { Component } from 'react'
4-
import { withPluginContext } from '@djsp/core'
4+
import { withPluginContext, constants } from '@djsp/core'
55
import type { PluginProps } from '@djsp/core'
6-
import Draft from 'draft-js'
6+
import { ContentBlock, EditorState, Modifier, SelectionState } from 'draft-js'
7+
import { insertNewLine } from '@djsp/utils'
8+
import DraftOffsetKey from 'draft-js/lib/DraftOffsetKey'
79
import AtomicBlock from './AtomicBlock'
810

9-
const { EditorState } = Draft
10-
1111
type Props = PluginProps & {
1212
type: string,
1313
children: any,
@@ -17,6 +17,38 @@ type State = {
1717
isFocused: boolean,
1818
}
1919

20+
// Set selection of editor to next/previous block
21+
const setSelection = (
22+
editorState: EditorState,
23+
setEditorState: EditorState,
24+
newActiveBlock: ContentBlock
25+
): void => {
26+
// TODO verify that always a key-0-0 exists
27+
const offsetKey = DraftOffsetKey.encode(newActiveBlock.getKey(), 0, 0)
28+
const node = document.querySelectorAll(`[data-offset-key="${offsetKey}"]`)[0]
29+
// set the native selection to the node so the caret is not in the text and
30+
// the selectionState matches the native selection
31+
const selection = window.getSelection()
32+
const range = document.createRange()
33+
range.setStart(node, 0)
34+
range.setEnd(node, 0)
35+
selection.removeAllRanges()
36+
selection.addRange(range)
37+
38+
setEditorState(
39+
EditorState.forceSelection(
40+
editorState,
41+
new SelectionState({
42+
anchorKey: newActiveBlock.getKey(),
43+
anchorOffset: 0,
44+
focusKey: newActiveBlock.getKey(),
45+
focusOffset: 0,
46+
isBackward: false,
47+
})
48+
)
49+
)
50+
}
51+
2052
class AtomicBlockPlugin extends Component<Props, State> {
2153
unregister: () => void
2254

@@ -26,38 +58,90 @@ class AtomicBlockPlugin extends Component<Props, State> {
2658
const { registerPlugin } = this.props
2759

2860
this.unregister = registerPlugin({
29-
keyBindingFn: this.keyBindingFn,
3061
blockRendererFn: this.blockRendererFn,
62+
handleReturn: this.handleReturn,
63+
handleKeyCommand: this.handleKeyCommand,
3164
})
3265
}
3366

3467
componentWillUnmount() {
3568
this.unregister()
3669
}
3770

38-
focusBlock = (blockKey: string) => {
39-
const { setEditorState, editorState } = this.props
71+
handleKeyCommand = (command, editorState) => {
72+
const { setEditorState } = this.props
4073

41-
let selection = editorState.getSelection()
74+
let contentState = editorState.getCurrentContent()
75+
const selection = editorState.getSelection()
76+
const key = selection.getStartKey()
77+
const currentBlock = contentState.getBlockForKey(key)
78+
const previousBlock = contentState.getBlockBefore(key)
79+
80+
if (!selection.isCollapsed()) {
81+
return constants.NOT_HANDLED
82+
} else if (
83+
currentBlock.getType() !== 'atomic' &&
84+
previousBlock != null &&
85+
selection.getStartOffset() === 0 &&
86+
previousBlock.getType() === 'atomic' &&
87+
command === 'backspace'
88+
) {
89+
setSelection(editorState, setEditorState, previousBlock)
90+
return constants.HANDLED
91+
} else if (
92+
currentBlock.getType() === 'atomic' &&
93+
['backspace', 'delete'].includes(command)
94+
) {
95+
contentState = Modifier.removeRange(
96+
contentState,
97+
editorState.getSelection().merge({
98+
anchorOffset: 0,
99+
focusOffset: 1,
100+
}),
101+
null
102+
)
103+
104+
setEditorState(
105+
EditorState.push(
106+
editorState,
107+
Modifier.setBlockType(contentState, selection, 'unstyled')
108+
)
109+
)
110+
return constants.HANDLED
111+
}
42112

43-
selection = selection.merge({
44-
anchorKey: blockKey,
45-
anchorOffset: 0,
46-
focusKey: blockKey,
47-
focusOffset: 0,
48-
})
113+
return constants.NOT_HANDLED
114+
}
49115

50-
window.getSelection().removeAllRanges()
116+
focusBlock = (blockKey: string) => {
117+
const { setEditorState, editorState } = this.props
118+
const block = editorState.getCurrentContent().getBlockForKey(blockKey)
51119

52-
setEditorState(EditorState.forceSelection(editorState, selection))
120+
setSelection(editorState, setEditorState, block)
53121
}
54122

55-
keyBindingFn = (event: SyntheticKeyboardEvent<*>) => {
56-
console.log('event.key', event.key)
123+
deleteAtomicBlock = (key: string) => {
124+
const { editorState, setEditorState } = this.props
125+
const selection = editorState.getSelection()
126+
127+
setEditorState(
128+
EditorState.push(
129+
editorState,
130+
Modifier.removeRange(
131+
editorState.getCurrentContent(),
132+
selection.merge({
133+
anchorKey: key,
134+
focusKey: key,
135+
anchorOffset: 0,
136+
focusOffset: 1,
137+
})
138+
)
139+
)
140+
)
57141
}
58142

59143
renderChildren = (props: Object) => {
60-
const { editorState } = this.props
144+
const { editorState, setEditorState } = this.props
61145

62146
const blockKey = props.block.getKey()
63147
const selection = editorState.getSelection()
@@ -66,13 +150,21 @@ class AtomicBlockPlugin extends Component<Props, State> {
66150

67151
return (
68152
<AtomicBlock
153+
onDeleteBlock={() => this.deleteAtomicBlock(blockKey)}
154+
setEditorState={setEditorState}
69155
isFocused={isFocused}
70156
onClick={() => this.focusBlock(blockKey)}>
71-
{this.props.children(props)}
157+
{this.props.children({ ...props, isFocused })}
72158
</AtomicBlock>
73159
)
74160
}
75161

162+
handleReturn = (event, editorState) => {
163+
const { setEditorState } = this.props
164+
165+
setEditorState(insertNewLine(editorState))
166+
}
167+
76168
blockRendererFn = block => {
77169
const { type, editorState } = this.props
78170
const content = editorState.getCurrentContent()

packages/core/README.md

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,63 @@
88
## License
99

1010
MIT © [juliankrispel](https://github.com/juliankrispel)
11+
12+
13+
## API
14+
15+
### <Plugin />
16+
17+
```jsx
18+
import { Plugin } from '@djsp/core' }
19+
```
20+
21+
#### Props
22+
A plugin inherits the same props as as the [Draft js Editor](https://draftjs.org/docs/api-reference-editor) including a few exceptions. Here's the full list of props:
23+
```jsx
24+
export type PluginProps = {
25+
blockRendererFn: (block: BlockNodeRecord) => ?Object,
26+
blockStyleFn: (block: BlockNodeRecord) => string,
27+
keyBindingFn: (e: SyntheticKeyboardEvent<>) => ?string,
28+
handleReturn?: (
29+
e: SyntheticKeyboardEvent<>,
30+
editorState: EditorState,
31+
) => DraftHandleValue,
32+
handleKeyCommand?: (
33+
command: DraftEditorCommand | string,
34+
editorState: EditorState,
35+
eventTimeStamp: number,
36+
) => DraftHandleValue,
37+
handleBeforeInput?: (
38+
chars: string,
39+
editorState: EditorState,
40+
eventTimeStamp: number,
41+
) => DraftHandleValue,
42+
handlePastedText?: (
43+
text: string,
44+
html?: string,
45+
editorState: EditorState,
46+
) => DraftHandleValue,
47+
handlePastedFiles?: (files: Array<Blob>) => DraftHandleValue,
48+
handleDroppedFiles?: (
49+
selection: SelectionState,
50+
files: Array<Blob>,
51+
) => DraftHandleValue,
52+
handleDrop?: (
53+
selection: SelectionState,
54+
dataTransfer: Object,
55+
isInternal: DraftDragType,
56+
) => DraftHandleValue,
57+
onEscape?: (e: SyntheticKeyboardEvent<>) => void,
58+
onTab?: (e: SyntheticKeyboardEvent<>) => void,
59+
onUpArrow?: (e: SyntheticKeyboardEvent<>) => void,
60+
onRightArrow?: (e: SyntheticKeyboardEvent<>) => void,
61+
onDownArrow?: (e: SyntheticKeyboardEvent<>) => void,
62+
onLeftArrow?: (e: SyntheticKeyboardEvent<>) => void,
63+
onBlur?: (e: SyntheticEvent<>) => void,
64+
onFocus?: (e: SyntheticEvent<>) => void,
65+
customStyleMap?: Object,
66+
customStyleFn?: (style: DraftInlineStyle, block: BlockNodeRecord) => ?Object,
67+
blockRenderMap: DraftBlockRenderMap,
68+
};
69+
```
70+
Lines changed: 9 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,11 @@
1-
/**
2-
* Copyright (c) 2013-present, Facebook, Inc.
3-
* All rights reserved.
4-
*
5-
* This source code is licensed under the BSD-style license found in the
6-
* LICENSE file in the root directory of this source tree. An additional grant
7-
* of patent rights can be found in the PATENTS file in the same directory.
8-
*
9-
* @providesModule DraftEntityInstance
10-
* @legacyServerCallableInstance
11-
* @format
12-
* @flow
13-
*/
14-
15-
'use strict';
16-
17-
import type { DraftEntityMutability } from './DraftEntityMutability';
18-
import type { DraftEntityType } from './DraftEntityType';
19-
20-
var Immutable = require('immutable');
21-
22-
var { Record } = Immutable;
23-
24-
var DraftEntityInstanceRecord = Record({
25-
type: 'TOKEN',
26-
mutability: 'IMMUTABLE',
27-
data: Object
28-
});
29-
30-
/**
31-
* An instance of a document entity, consisting of a `type` and relevant
32-
* `data`, metadata about the entity.
33-
*
34-
* For instance, a "link" entity might provide a URI, and a "mention"
35-
* entity might provide the mentioned user's ID. These pieces of data
36-
* may be used when rendering the entity as part of a ContentBlock DOM
37-
* representation. For a link, the data would be used as an href for
38-
* the rendered anchor. For a mention, the ID could be used to retrieve
39-
* a hovercard.
40-
*/
41-
class DraftEntityInstance extends DraftEntityInstanceRecord {
42-
getType(): DraftEntityType {
43-
return this.get('type');
44-
}
45-
46-
getMutability(): DraftEntityMutability {
47-
return this.get('mutability');
48-
}
49-
50-
getData(): Object {
51-
return this.get('data');
1+
// @flow
2+
import type { DraftEntityMutability } from './DraftEntityMutability'
3+
import type { DraftEntityType } from './DraftEntityType'
4+
5+
declare module 'draft-js/lib/DraftEntityInstance' {
6+
declare export default class DraftEntityInstance {
7+
getType(): DraftEntityType;
8+
getMutability(): DraftEntityMutability;
9+
getData(): Object;
5210
}
5311
}
54-
55-
export default DraftEntityInstance;

packages/core/flow-lib/draft-js/DraftOffsetKey.js.flow

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,16 @@ var DraftOffsetKey = {
3232
}
3333
};
3434

35-
export default DraftOffsetKey;
35+
36+
declare module 'draft-js/lib/DraftOffsetKey' {
37+
declare type DraftOffsetKey = {
38+
encode: (
39+
blockKey: string,
40+
decoratorKey: number,
41+
leafKey: number
42+
) => string,
43+
decode: (offsetKey: string) => DraftOffsetKeyPath,
44+
}
45+
46+
declare export default DraftOffsetKey
47+
}

0 commit comments

Comments
 (0)