react-codemirror2
Advanced tools
Comparing version 3.0.7 to 4.0.0
@@ -0,1 +1,11 @@ | ||
4.0.0 | ||
================== | ||
* cursor, scroll, and selection events occur after an internal hydrate | ||
* cursor, scroll, and selection events have more strict checking and are more responsive for changed valued | ||
* added `PREVENT_CODEMIRROR_RENDER` global for rendering bypass | ||
* selections managed via props now have and isolated autofocus option | ||
* optimization of setting instance options when updated via props | ||
* https://github.com/scniro/react-codemirror2/issues/49 | ||
* test coverage | ||
3.0.6 | ||
@@ -2,0 +12,0 @@ ================== |
@@ -10,4 +10,4 @@ /// <reference types="codemirror" /> | ||
export interface ISetScrollOptions { | ||
x: number; | ||
y: number; | ||
x?: number | null; | ||
y?: number | null; | ||
} | ||
@@ -28,2 +28,3 @@ export interface ISetSelectionOptions { | ||
export interface IInstance extends codemirror.Editor, IDoc { | ||
options: codemirror.EditorConfiguration; | ||
} | ||
@@ -58,8 +59,7 @@ export interface ICodeMirror { | ||
options?: codemirror.EditorConfiguration; | ||
selection?: Array<ISetSelectionOptions>; | ||
selection?: { | ||
ranges: Array<ISetSelectionOptions>; | ||
focus?: boolean; | ||
}; | ||
scroll?: ISetScrollOptions; | ||
autoScrollCursorOnSet?: any; | ||
onBeforeSet?: any; | ||
onSet?: any; | ||
resetCursorOnSet?: any; | ||
} | ||
@@ -66,0 +66,0 @@ export interface IControlledCodeMirror extends ICodeMirror { |
195
index.js
@@ -14,7 +14,18 @@ 'use strict'; | ||
var React = require('react'); | ||
var SERVER_RENDERED = (typeof navigator === 'undefined' || global['PREVENT_CODEMIRROR_RENDER'] === true); | ||
var cm; | ||
var SERVER_RENDERED = typeof navigator === 'undefined'; | ||
if (!SERVER_RENDERED) { | ||
cm = require('codemirror'); | ||
} | ||
var Helper = (function () { | ||
function Helper() { | ||
} | ||
Helper.equals = function (x, y) { | ||
var _this = this; | ||
var ok = Object.keys, tx = typeof x, ty = typeof y; | ||
return x && y && tx === 'object' && tx === ty ? (ok(x).length === ok(y).length && | ||
ok(x).every(function (key) { return _this.equals(x[key], y[key]); })) : (x === y); | ||
}; | ||
return Helper; | ||
}()); | ||
var Shared = (function () { | ||
@@ -24,16 +35,59 @@ function Shared(editor, props) { | ||
this.props = props; | ||
this.notifyOfDeprecation(); | ||
} | ||
Shared.prototype.notifyOfDeprecation = function () { | ||
if (this.props.autoScrollCursorOnSet !== undefined) { | ||
console.warn('`autoScrollCursorOnSet` has been deprecated. Use `autoScroll` instead\n\nSee https://github.com/scniro/react-codemirror2#props'); | ||
Shared.prototype.delegateCursor = function (position, scroll, focus) { | ||
var doc = this.editor.getDoc(); | ||
if (focus) { | ||
this.editor.focus(); | ||
} | ||
if (this.props.resetCursorOnSet !== undefined) { | ||
console.warn('`resetCursorOnSet` has been deprecated. Use `autoCursor` instead\n\nSee https://github.com/scniro/react-codemirror2#props'); | ||
scroll ? doc.setCursor(position) : doc.setCursor(position, null, { scroll: false }); | ||
}; | ||
Shared.prototype.delegateScroll = function (coordinates) { | ||
this.editor.scrollTo(coordinates.x, coordinates.y); | ||
}; | ||
Shared.prototype.delegateSelection = function (ranges, focus) { | ||
this.editor.setSelections(ranges); | ||
if (focus) { | ||
this.editor.focus(); | ||
} | ||
if (this.props.onSet !== undefined) { | ||
console.warn('`onSet` has been deprecated. User `editorDidMount` instead. See https://github.com/scniro/react-codemirror2#events'); | ||
}; | ||
Shared.prototype.apply = function (props, next, preserved) { | ||
if (next) { | ||
if (next.selection) { | ||
if (next.selection.ranges) { | ||
if (props.selection) { | ||
if (!Helper.equals(props.selection.ranges, next.selection.ranges)) { | ||
this.delegateSelection(next.selection.ranges, next.selection.focus || false); | ||
} | ||
} | ||
else { | ||
this.delegateSelection(next.selection.ranges, next.selection.focus || false); | ||
} | ||
} | ||
} | ||
if (next.cursor) { | ||
if (props.cursor) { | ||
if (!Helper.equals(props.cursor, next.cursor)) { | ||
this.delegateCursor(preserved.cursor || next.cursor, (next.autoScroll || false), (next.autoCursor || false)); | ||
} | ||
} | ||
else { | ||
this.delegateCursor(preserved.cursor || next.cursor, (next.autoScroll || false), (next.autoCursor || false)); | ||
} | ||
} | ||
if (next.scroll) { | ||
this.delegateScroll(next.scroll); | ||
} | ||
} | ||
if (this.props.onBeforeSet !== undefined) { | ||
console.warn('`onBeforeSet` has been deprecated. User `onBeforeChange` for `Controlled`. instead. See https://github.com/scniro/react-codemirror2#events'); | ||
else { | ||
if (props.selection) { | ||
if (props.selection.ranges) { | ||
this.delegateSelection(props.selection.ranges, props.selection.focus || false); | ||
} | ||
} | ||
if (props.cursor) { | ||
this.delegateCursor(props.cursor, (props.autoScroll || false), (props.autoFocus || false)); | ||
} | ||
if (props.scroll) { | ||
this.delegateScroll(props.scroll); | ||
} | ||
} | ||
@@ -170,29 +224,16 @@ }; | ||
} | ||
Controlled.prototype.setCursor = function (cursorPos, scroll, focus) { | ||
var doc = this.editor.getDoc(); | ||
if (focus) { | ||
this.editor.focus(); | ||
} | ||
if (scroll) { | ||
doc.setCursor(cursorPos); | ||
} | ||
else { | ||
doc.setCursor(cursorPos, null, { scroll: false }); | ||
} | ||
}; | ||
Controlled.prototype.moveCursor = function (cursorPos, scroll) { | ||
var doc = this.editor.getDoc(); | ||
if (scroll) { | ||
doc.setCursor(cursorPos); | ||
} | ||
else { | ||
doc.setCursor(cursorPos, null, { scroll: false }); | ||
} | ||
}; | ||
Controlled.prototype.hydrate = function (props) { | ||
var _this = this; | ||
Object.keys(props.options || {}).forEach(function (key) { | ||
_this.editor.setOption(key, props.options[key]); | ||
_this.mirror.setOption(key, props.options[key]); | ||
}); | ||
var userDefinedOptions = Object.assign({}, cm.defaults, this.editor.options, props.options || {}); | ||
var optionDelta = Object.keys(userDefinedOptions).some(function (key) { return _this.editor.getOption(key) !== userDefinedOptions[key]; }); | ||
if (optionDelta) { | ||
Object.keys(userDefinedOptions).forEach(function (key) { | ||
if (props.options.hasOwnProperty(key)) { | ||
if (_this.editor.getOption(key) !== userDefinedOptions[key]) { | ||
_this.editor.setOption(key, userDefinedOptions[key]); | ||
_this.mirror.setOption(key, userDefinedOptions[key]); | ||
} | ||
} | ||
}); | ||
} | ||
if (!this.hydrated) { | ||
@@ -295,2 +336,5 @@ if (!this.mounted) { | ||
}); | ||
this.hydrate(this.props); | ||
this.shared.apply(this.props); | ||
this.mounted = true; | ||
if (this.props.onBlur) | ||
@@ -326,14 +370,2 @@ this.shared.wire('onBlur'); | ||
this.shared.wire('onViewportChange'); | ||
this.hydrate(this.props); | ||
if (this.props.selection) { | ||
var doc = this.editor.getDoc(); | ||
doc.setSelections(this.props.selection); | ||
} | ||
if (this.props.cursor) { | ||
this.setCursor(this.props.cursor, this.props.autoScroll || false, this.props.autoFocus || false); | ||
} | ||
if (this.props.scroll) { | ||
this.editor.scrollTo(this.props.scroll.x, this.props.scroll.y); | ||
} | ||
this.mounted = true; | ||
if (this.props.editorDidMount) { | ||
@@ -346,3 +378,3 @@ this.props.editorDidMount(this.editor, this.editor.getValue(), this.initCb); | ||
return; | ||
var cursorPos; | ||
var preserved = { cursor: null }; | ||
if (nextProps.value !== this.props.value) { | ||
@@ -352,8 +384,6 @@ this.hydrated = false; | ||
if (!this.props.autoCursor && this.props.autoCursor !== undefined) { | ||
cursorPos = this.editor.getCursor(); | ||
preserved.cursor = this.editor.getCursor(); | ||
} | ||
this.hydrate(nextProps); | ||
if (!this.props.autoCursor && this.props.autoCursor !== undefined) { | ||
this.moveCursor(cursorPos, this.props.autoScroll || false); | ||
} | ||
this.shared.apply(this.props, nextProps, preserved); | ||
}; | ||
@@ -399,26 +429,15 @@ Controlled.prototype.componentWillUnmount = function () { | ||
} | ||
UnControlled.prototype.setCursor = function (cursorPos, scroll, focus) { | ||
var doc = this.editor.getDoc(); | ||
if (focus) { | ||
this.editor.focus(); | ||
} | ||
if (scroll) { | ||
doc.setCursor(cursorPos); | ||
} | ||
else { | ||
doc.setCursor(cursorPos, null, { scroll: false }); | ||
} | ||
}; | ||
UnControlled.prototype.moveCursor = function (cursorPos, scroll) { | ||
var doc = this.editor.getDoc(); | ||
if (scroll) { | ||
doc.setCursor(cursorPos); | ||
} | ||
else { | ||
doc.setCursor(cursorPos, null, { scroll: false }); | ||
} | ||
}; | ||
UnControlled.prototype.hydrate = function (props) { | ||
var _this = this; | ||
Object.keys(props.options || {}).forEach(function (key) { return _this.editor.setOption(key, props.options[key]); }); | ||
var userDefinedOptions = Object.assign({}, cm.defaults, this.editor.options, props.options || {}); | ||
var optionDelta = Object.keys(userDefinedOptions).some(function (key) { return _this.editor.getOption(key) !== userDefinedOptions[key]; }); | ||
if (optionDelta) { | ||
Object.keys(userDefinedOptions).forEach(function (key) { | ||
if (props.options.hasOwnProperty(key)) { | ||
if (_this.editor.getOption(key) !== userDefinedOptions[key]) { | ||
_this.editor.setOption(key, userDefinedOptions[key]); | ||
} | ||
} | ||
}); | ||
} | ||
if (!this.hydrated) { | ||
@@ -462,5 +481,2 @@ var lastLine = this.editor.lastLine(); | ||
} | ||
else { | ||
return; | ||
} | ||
} | ||
@@ -471,2 +487,5 @@ else { | ||
}); | ||
this.hydrate(this.props); | ||
this.shared.apply(this.props); | ||
this.mounted = true; | ||
if (this.props.onBlur) | ||
@@ -502,14 +521,2 @@ this.shared.wire('onBlur'); | ||
this.shared.wire('onViewportChange'); | ||
this.hydrate(this.props); | ||
if (this.props.selection) { | ||
var doc = this.editor.getDoc(); | ||
doc.setSelections(this.props.selection); | ||
} | ||
if (this.props.cursor) { | ||
this.setCursor(this.props.cursor, this.props.autoScroll || false, this.props.autoFocus || false); | ||
} | ||
if (this.props.scroll) { | ||
this.editor.scrollTo(this.props.scroll.x, this.props.scroll.y); | ||
} | ||
this.mounted = true; | ||
this.editor.clearHistory(); | ||
@@ -523,3 +530,3 @@ if (this.props.editorDidMount) { | ||
return; | ||
var cursorPos; | ||
var preserved = { cursor: null }; | ||
if (nextProps.value !== this.props.value) { | ||
@@ -529,8 +536,6 @@ this.hydrated = false; | ||
if (!this.props.autoCursor && this.props.autoCursor !== undefined) { | ||
cursorPos = this.editor.getCursor(); | ||
preserved.cursor = this.editor.getCursor(); | ||
} | ||
this.hydrate(nextProps); | ||
if (!this.props.autoCursor && this.props.autoCursor !== undefined) { | ||
this.moveCursor(cursorPos, this.props.autoScroll || false); | ||
} | ||
this.shared.apply(this.props, nextProps, preserved); | ||
}; | ||
@@ -537,0 +542,0 @@ UnControlled.prototype.componentWillUnmount = function () { |
{ | ||
"name": "react-codemirror2", | ||
"version": "3.0.7", | ||
"version": "4.0.0", | ||
"description": "a tiny react codemirror component wrapper", | ||
@@ -27,3 +27,3 @@ "main": "index.js", | ||
], | ||
"testRegex": "./test/index.spec.tsx", | ||
"testRegex": "./test/(index|index.server).spec.tsx", | ||
"transform": { | ||
@@ -63,15 +63,14 @@ ".(ts|tsx)": "<rootDir>/node_modules/ts-jest/preprocessor.js" | ||
"@nteract/mockument": "1.0.4", | ||
"@types/codemirror": "0.0.50", | ||
"@types/codemirror": "0.0.55", | ||
"@types/jest": "21.1.5", | ||
"@types/react": "16.0.19", | ||
"@types/react": "16.0.35", | ||
"babel-core": "6.26.0", | ||
"babel-jest": "21.2.0", | ||
"babel-loader": "7.1.2", | ||
"babel-preset-es2015": "6.24.1", | ||
"babel-preset-react": "6.24.1", | ||
"codemirror": "5.31.0", | ||
"codemirror": "5.33.0", | ||
"coveralls": "3.0.0", | ||
"css-loader": "0.28.7", | ||
"enzyme": "3.1.0", | ||
"enzyme-adapter-react-16": "1.0.3", | ||
"css-loader": "0.28.9", | ||
"enzyme": "3.3.0", | ||
"enzyme-adapter-react-16": "1.1.1", | ||
"express": "4.16.2", | ||
@@ -81,22 +80,21 @@ "gulp": "3.9.1", | ||
"jest": "21.2.1", | ||
"js-beautify": "1.7.4", | ||
"node-sass": "4.5.3", | ||
"js-beautify": "1.7.5", | ||
"node-sass": "4.7.2", | ||
"open": "0.0.5", | ||
"prismjs": "1.8.3", | ||
"prop-types": "15.6.0", | ||
"prismjs": "1.10.0", | ||
"raf": "3.4.0", | ||
"react": "16.0.0", | ||
"react-dom": "16.0.0", | ||
"react": "16.2.0", | ||
"react-dom": "16.2.0", | ||
"react-redux": "5.0.6", | ||
"react-test-renderer": "16.0.0", | ||
"react-test-renderer": "16.2.0", | ||
"redux": "3.7.2", | ||
"rimraf": "2.6.2", | ||
"sass-loader": "6.0.6", | ||
"sinon": "4.1.1", | ||
"style-loader": "0.19.0", | ||
"sinon": "4.2.2", | ||
"style-loader": "0.20.1", | ||
"ts-jest": "21.1.4", | ||
"typescript": "2.6.1", | ||
"typescript-formatter": "7.0.0", | ||
"webpack": "3.8.1" | ||
"typescript": "2.6.2", | ||
"typescript-formatter": "7.0.1", | ||
"webpack": "3.10.0" | ||
} | ||
} |
@@ -1,5 +0,6 @@ | ||
[](https://travis-ci.org/scniro/react-codemirror2) | ||
[](https://travis-ci.org/scniro/react-codemirror2) | ||
[](https://david-dm.org/scniro/react-codemirror2) | ||
[](https://david-dm.org/scniro/react-codemirror2#info=devDependencies) | ||
[](https://coveralls.io/github/scniro/react-codemirror2) | ||
[](https://www.npmjs.com/package/react-codemirror2) | ||
[](https://www.npmjs.com/package/react-codemirror2) | ||
@@ -11,8 +12,6 @@ | ||
> npm install react-codemirror2 | ||
> npm install react-codemirror2 codemirror --save | ||
## new in 3.0.0 | ||
`react-codemirror2` ships with the notion of an [uncontrolled](https://reactjs.org/docs/uncontrolled-components.html) and [controlled](https://reactjs.org/docs/forms.html#controlled-components) component. `UnControlled` consists of a simple wrapper largely powered by the inner workings of `codemirror` itself, while `Controlled` will demand state management from the user, preventing codemirror changes unless properly handled via `value`. The latter will offer more control and likely be more appropriate with [redux](http://redux.js.org/) heavy apps. | ||
`react-codemirror2` now ships with the notion of an [uncontrolled](https://reactjs.org/docs/uncontrolled-components.html) and [controlled](https://reactjs.org/docs/forms.html#controlled-components) component. `UnControlled` consists of a simple wrapper largely powered by the inner workings of `codemirror` itself, while `Controlled` will demand state management from the user, preventing codemirror changes unless properly handled via `value`. The latter will offer more control and likely be more appropriate with [redux](http://redux.js.org/) heavy apps. | ||
## uncontrolled usage | ||
@@ -139,3 +138,2 @@ ```jsx | ||
## events cont. [wrapped codemirror events](https://codemirror.net/doc/manual.html#events) | ||
@@ -159,2 +157,23 @@ | ||
[MIT](./LICENSE) © 2017 [scniro](https://github.com/scniro) | ||
## misc. notes | ||
- server rendering | ||
react-codemirror2 will prevent rendering in absence of `navigator` that is typical of a server environment. In case of any issue, you can force the component to not render via a `PREVENT_CODEMIRROR_RENDER` global variable that this wrapper respond to. | ||
- getting the instance | ||
getting the instance of the underlying editor can be done via the event callbacks where `editor` is returned. There is no static method to get it on demand, e.g. `CodeMirror.getInstance()`. The recommended approach can be observed as follows... | ||
```jsx | ||
constructor() { | ||
this.instance = null; | ||
} | ||
render() { | ||
<CodeMirror editorDidMount={editor => { this.instance = editor }}/> | ||
} | ||
``` | ||
[MIT](./LICENSE) © 2018 [scniro](https://github.com/scniro) |
38146
35
622
177