diff --git a/CHANGELOG.md b/CHANGELOG.md
index e5e91fbe..d0306ead 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
+## 0.6.15 - 2019-12-26
+### Fixed
+- Focus loss in plugins with react-select dependency (#288)
+- Data loss when swapping plugin blocks with blur update (#286)
+- Placeholder trimmed when movableBlocks prop is active (#283)
+
## 0.6.14 - 2019-11-30
### Added
- Add onAction function to listen to reorder blocks button clicks (#282)
diff --git a/package.json b/package.json
index b225bd2f..400225ba 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "megadraft",
- "version": "0.6.14",
+ "version": "0.6.15",
"description": "Rich Text editor built on top of draft.js",
"main": "lib/Megadraft.js",
"dependencies": {
@@ -71,8 +71,8 @@
"webpack-dev-server": "^3.4.1"
},
"peerDependencies": {
- "react": "^15.6.1 || ^16.1.0",
- "react-dom": "^15.6.1 || ^16.1.0"
+ "react": "^16.1.0",
+ "react-dom": "^16.1.0"
},
"scripts": {
"start": "gulp dev-server",
diff --git a/src/components/ActionsProvider.js b/src/components/ActionsProvider.js
index 458f15ab..024cf303 100644
--- a/src/components/ActionsProvider.js
+++ b/src/components/ActionsProvider.js
@@ -7,42 +7,18 @@
import React from "react";
import PropTypes from "prop-types";
-export default class ActionsProvider extends React.Component {
- constructor(props) {
- super(props);
- }
+export const defaultAction = () => {};
- getChildContext() {
- return {
- onAction: this.props.onAction
- };
- }
+export const ActionsContext = React.createContext({ onAction: defaultAction });
- render() {
- return this.props.children;
- }
-}
+const ActionsProvider = ({ onAction = defaultAction, children }) => (
+
+ {children}
+
+);
-ActionsProvider.childContextTypes = {
+ActionsProvider.propTypes = {
onAction: PropTypes.func
};
-export function withActions(WrappedComponent) {
- class WithActionsHOC extends React.Component {
- constructor(props) {
- super(props);
- }
-
- render() {
- return (
-
- );
- }
- }
-
- WithActionsHOC.contextTypes = {
- onAction: PropTypes.func
- };
-
- return WithActionsHOC;
-}
+export default ActionsProvider;
diff --git a/src/components/MegadraftEditor.js b/src/components/MegadraftEditor.js
index d0c3ff4a..6ce93dc5 100644
--- a/src/components/MegadraftEditor.js
+++ b/src/components/MegadraftEditor.js
@@ -43,12 +43,10 @@ import notFoundPlugin from "../plugins/not-found/plugin";
import DEFAULT_PLUGINS from "../plugins/default";
import DEFAULT_ACTIONS from "../actions/default";
import DEFAULT_ENTITY_INPUTS from "../entity_inputs/default";
-import ActionsProvider from "./ActionsProvider";
+import ActionsProvider, { defaultAction } from "./ActionsProvider";
const NO_RESET_STYLE_DEFAULT = ["ordered-list-item", "unordered-list-item"];
-const noop = () => {};
-
export default class MegadraftEditor extends Component {
static defaultProps = {
actions: DEFAULT_ACTIONS,
@@ -62,7 +60,10 @@ export default class MegadraftEditor extends Component {
this.state = {
readOnly: this.props.readOnly || false,
hasFocus: false,
- scrollRef: ""
+ scrollRef: "",
+ swapUp: false,
+ swapDown: false,
+ didSwap: false
};
this.onChange = ::this.onChange;
@@ -91,7 +92,7 @@ export default class MegadraftEditor extends Component {
this.keyBindings = this.props.keyBindings || [];
- this.onAction = this.props.onAction || noop;
+ this.onAction = this.props.onAction || defaultAction;
this.extendedBlockRenderMap = Immutable.OrderedMap().withMutations(r => {
for (let [blockType, data] of DefaultDraftBlockRenderMap.entrySeq()) {
@@ -104,6 +105,8 @@ export default class MegadraftEditor extends Component {
swapDown={this.swapDown}
isFirstBlock={this.isFirstBlock}
isLastBlock={this.isLastBlock}
+ onAction={this.onAction}
+ isAtomic={blockType === "atomic"}
/>
) : (
@@ -352,7 +355,9 @@ export default class MegadraftEditor extends Component {
}
handleClassEditor(identifier) {
- let classEditor = identifier;
+ let classEditor = this.props.movableBlocks
+ ? `${identifier} movable`
+ : identifier;
let contentState = this.props.editorState.getCurrentContent();
// If the user changes block type before entering any text, we can
// either style the placeholder or hide it.
@@ -383,8 +388,22 @@ export default class MegadraftEditor extends Component {
clearTimeout(this.blurTimeoutID);
}
- componentDidUpdate(prevProps) {
- if (prevProps.editorState !== this.props.editorState) {
+ componentDidUpdate() {
+ if (this.state.swapUp || this.state.swapDown) {
+ const swapFunction = this.state.swapUp ? swapDataUp : swapDataDown;
+
+ const newEditorState = swapFunction({
+ editorState: this.props.editorState,
+ currentKey: this.state.scrollRef
+ });
+
+ this.onChange(newEditorState);
+ this.setState({
+ didSwap: true,
+ swapUp: false,
+ swapDown: false
+ });
+ } else if (this.state.didSwap) {
const control = document.querySelector(`[id*="${this.state.scrollRef}"]`);
if (control) {
@@ -394,6 +413,9 @@ export default class MegadraftEditor extends Component {
control.classList.toggle("move-control--swapped");
};
+ const input = control.querySelector("[type=text]");
+ input && input.focus();
+
control.scrollIntoView({ block: "center" });
window.scroll(0, window.pageYOffset - control.clientHeight / 2);
@@ -403,7 +425,10 @@ export default class MegadraftEditor extends Component {
swapEffect();
}, 300);
- this.setState({ scrollRef: "" });
+ this.setState({
+ didSwap: false,
+ scrollRef: ""
+ });
}
}
}
@@ -467,21 +492,27 @@ export default class MegadraftEditor extends Component {
}
swapUp = currentKey => {
- const newEditorState = swapDataUp({
- editorState: this.props.editorState,
- currentKey
+ document.activeElement.blur();
+
+ this.forceUpdate(() => {
+ this.setState({
+ swapUp: true,
+ swapDown: false,
+ scrollRef: currentKey
+ });
});
- this.onChange(newEditorState);
- this.setState({ scrollRef: currentKey });
};
swapDown = currentKey => {
- const newEditorState = swapDataDown({
- editorState: this.props.editorState,
- currentKey
+ document.activeElement.blur();
+
+ this.forceUpdate(() => {
+ this.setState({
+ swapUp: false,
+ swapDown: true,
+ scrollRef: currentKey
+ });
});
- this.onChange(newEditorState);
- this.setState({ scrollRef: currentKey });
};
isFirstBlock = currentKey => {
diff --git a/src/components/ModalPluginItem.js b/src/components/ModalPluginItem.js
index 0699f9d2..d79126a5 100644
--- a/src/components/ModalPluginItem.js
+++ b/src/components/ModalPluginItem.js
@@ -6,10 +6,12 @@
import React, { Component } from "react";
-import { withActions } from "./ActionsProvider";
+import { ActionsContext } from "./ActionsProvider";
import { PLUGINS_MODAL_ADD_PLUGIN } from "../constants";
-class ModalPluginItem extends Component {
+export default class ModalPluginItem extends Component {
+ static contextType = ActionsContext;
+
constructor(props) {
super(props);
this.handleClick = ::this.handleClick;
@@ -33,7 +35,7 @@ class ModalPluginItem extends Component {
key={item.type}
className="megadraft-modal__item"
onClick={() => {
- this.props.onAction({
+ this.context.onAction({
type: PLUGINS_MODAL_ADD_PLUGIN,
pluginName: item.title
});
@@ -67,5 +69,3 @@ class ModalPluginItem extends Component {
);
}
}
-
-export default withActions(ModalPluginItem);
diff --git a/src/components/MoveControl.js b/src/components/MoveControl.js
index 688a132d..99aafc3c 100644
--- a/src/components/MoveControl.js
+++ b/src/components/MoveControl.js
@@ -7,7 +7,6 @@
import React from "react";
import icons from "../icons";
import MegadraftBlock from "./MegadraftBlock";
-import { withActions } from "./ActionsProvider";
import { BLOCK_SWAP_UP, BLOCK_SWAP_DOWN } from "../constants";
@@ -60,9 +59,13 @@ const Control = ({
onClickDown,
isFirst,
isLast,
- onAction
+ onAction,
+ isAtomic
}) => (
-
+
{children}
@@ -79,10 +82,11 @@ const Controlled = ({
keySwapDown,
isFirstBlock,
isLastBlock,
+ isAtomic,
swapUp,
swapDown,
- children,
- onAction
+ onAction,
+ children
}) => {
const onClickUp = () => swapUp(keySwapUp);
const onClickDown = () => swapDown(keySwapDown);
@@ -95,7 +99,7 @@ const Controlled = ({
id={
keySwapUp !== keySwapDown ? `${keySwapUp}-${keySwapDown}` : keySwapUp
}
- {...{ onClickUp, onClickDown, isFirst, isLast, onAction }}
+ {...{ onClickUp, onClickDown, isFirst, isLast, onAction, isAtomic }}
>
{children}
@@ -103,44 +107,43 @@ const Controlled = ({
);
};
-export default withActions(
- ({
- wrapper,
- swapUp,
- swapDown,
- children,
- isFirstBlock,
- isLastBlock,
- onAction
- }) => {
- const arrayChildren = React.Children.toArray(children);
- const firstChildKey = arrayChildren[0].props.children.key;
- const lastChildKey =
- arrayChildren[arrayChildren.length - 1].props.children.key;
-
- const controlledChildren = React.Children.map(children, child => {
- const currentKey = child.props.children.key;
- return (
-
- {child}
-
- );
- });
+export default ({
+ wrapper,
+ swapUp,
+ swapDown,
+ children,
+ isFirstBlock,
+ isLastBlock,
+ onAction,
+ isAtomic
+}) => {
+ const arrayChildren = React.Children.toArray(children);
+ const firstChildKey = arrayChildren[0].props.children.key;
+ const lastChildKey =
+ arrayChildren[arrayChildren.length - 1].props.children.key;
- return wrapper ? (
+ const controlledChildren = React.Children.map(children, child => {
+ const currentKey = child.props.children.key;
+ return (
- {React.cloneElement(wrapper, [], children)}
+ {child}
- ) : (
- controlledChildren
);
- }
-);
+ });
+
+ return wrapper ? (
+
+ {React.cloneElement(wrapper, [], children)}
+
+ ) : (
+ controlledChildren
+ );
+};
diff --git a/src/components/PluginsModal.js b/src/components/PluginsModal.js
index 16db9d2d..76a3607b 100644
--- a/src/components/PluginsModal.js
+++ b/src/components/PluginsModal.js
@@ -9,10 +9,12 @@ import React, { Component } from "react";
import Modal from "backstage-modal";
import ModalPluginList from "./ModalPluginList";
-import { withActions } from "./ActionsProvider";
+import { ActionsContext } from "./ActionsProvider";
import { PLUGINS_MODAL_CLOSE } from "../constants";
-class PluginsModal extends Component {
+export default class PluginsModal extends Component {
+ static contextType = ActionsContext;
+
constructor(props) {
super(props);
this.onCloseRequest = ::this.onCloseRequest;
@@ -26,7 +28,7 @@ class PluginsModal extends Component {
return;
}
document.body.classList.remove("megadraft-modal--open");
- this.props.onAction({ type: PLUGINS_MODAL_CLOSE });
+ this.context.onAction({ type: PLUGINS_MODAL_CLOSE });
this.props.toggleModalVisibility();
}
@@ -52,5 +54,3 @@ class PluginsModal extends Component {
);
}
}
-
-export default withActions(PluginsModal);
diff --git a/src/components/Sidebar.js b/src/components/Sidebar.js
index 9f219bb1..2ff75ce2 100644
--- a/src/components/Sidebar.js
+++ b/src/components/Sidebar.js
@@ -16,14 +16,16 @@ import {
SIDEBAR_CLICK_MORE
} from "../constants";
-import { withActions } from "./ActionsProvider";
+import { ActionsContext } from "./ActionsProvider";
import "setimmediate";
import PluginsModal from "./PluginsModal";
import { getSelectedBlockElement } from "../utils";
-class BlockStylesComponent extends Component {
+class BlockStyles extends Component {
+ static contextType = ActionsContext;
+
constructor(props) {
super(props);
this.state = {
@@ -70,7 +72,7 @@ class BlockStylesComponent extends Component {