1 | [](https://coveralls.io/github/scniro/react-codemirror2)
|
2 | [](https://www.npmjs.com/package/react-codemirror2)
|
3 | [](https://www.npmjs.com/package/react-codemirror2)
|
4 |
|
5 | ### react-codemirror2
|
6 |
|
7 | demo @ [scniro.github.io/react-codemirror2](https://scniro.github.io/react-codemirror2/)
|
8 |
|
9 |
|
10 | ## Install
|
11 |
|
12 | ```bash
|
13 | npm install react-codemirror2 codemirror --save
|
14 | ```
|
15 |
|
16 | `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.
|
17 |
|
18 | ## uncontrolled usage
|
19 | ```jsx
|
20 | import {UnControlled as CodeMirror} from 'react-codemirror2'
|
21 |
|
22 | <CodeMirror
|
23 | value='<h1>I ♥ react-codemirror2</h1>'
|
24 | options={{
|
25 | mode: 'xml',
|
26 | theme: 'material',
|
27 | lineNumbers: true
|
28 | }}
|
29 | onChange={(editor, data, value) => {
|
30 | }}
|
31 | />
|
32 | ```
|
33 |
|
34 | ## controlled usage
|
35 | ```jsx
|
36 | import {Controlled as CodeMirror} from 'react-codemirror2'
|
37 |
|
38 | <CodeMirror
|
39 | value={this.state.value}
|
40 | options={options}
|
41 | onBeforeChange={(editor, data, value) => {
|
42 | this.setState({value});
|
43 | }}
|
44 | onChange={(editor, data, value) => {
|
45 | }}
|
46 | />
|
47 | ```
|
48 |
|
49 | ## requiring codemirror resources
|
50 |
|
51 | - [codemirror](https://www.npmjs.com/package/codemirror)
|
52 |
|
53 | `codemirror` comes as a [peer dependency](https://nodejs.org/en/blog/npm/peer-dependencies/), meaning you'll need to require it in your project _in addition to_ `react-codemirror2`. This prevents any versioning conflicts that would arise if `codemirror` came as a dependency through this wrapper. It's been observed that version mismatches can cause difficult to trace issues such as syntax highlighting disappearing without any explicit errors/warnings
|
54 |
|
55 | - additional
|
56 |
|
57 | Since codemirror ships mostly unconfigured, the user is left with the responsibility for requiring any additional resources should they be necessary. This is often the case when specifying certain [language modes]() and [themes](). How to import/require these assets will vary according to the specifics of your development environment. Below is a sample to include the assets necessary to specify a mode of `xml` (HTML) and a `material` theme.
|
58 |
|
59 | > note that the base codemirror.css file is required in all use cases
|
60 |
|
61 | ```css
|
62 | @import 'codemirror/lib/codemirror.css';
|
63 | @import 'codemirror/theme/material.css';
|
64 | ```
|
65 |
|
66 | ```jsx
|
67 | import CodeMirror from 'react-codemirror2';
|
68 | require('codemirror/mode/xml/xml');
|
69 | require('codemirror/mode/javascript/javascript');
|
70 | ```
|
71 |
|
72 | ## props
|
73 |
|
74 | | prop | type *`default`* | components | description |
|
75 | |--------------|------------------------|-----------------------------------|-----------------------------------------------------------------------------------------------------------------------|
|
76 | | `autoCursor` | boolean *`true`* | `Controlled` `UnControlled` | should component cursor position correct when `value` changed | |
|
77 | | `autoScroll` | boolean *`true`* | `Controlled` `UnControlled` | should component scroll cursor position into view when `value` changed |
|
78 | | `className` | string | `Controlled` `UnControlled` | pass through class *`class="react-codemirror2 className"`* |
|
79 | | `defineMode` | object | `Controlled` `UnControlled` | pass a [custom mode](http://marijnhaverbeke.nl/blog/codemirror-mode-system.html) via `{name: 'custom', fn: myModeFn}` |
|
80 | | `detach` | boolean | `UnControlled` | should component ignore new props |
|
81 | | `options` | object | `Controlled` `UnControlled` | [codemirror configuration](https://codemirror.net/doc/manual.html#config) |
|
82 | | `value` | string | *`Controlled` `UnControlled` | * component value _**must be managed for controlled components**_ |
|
83 |
|
84 | ## props cont. (wrapped codemirror [programming api](https://codemirror.net/doc/manual.html#api))
|
85 |
|
86 | - `cursor` - *[setCursor](https://codemirror.net/doc/manual.html#setCursor)*
|
87 | > will programmatically set cursor to the position specified
|
88 | ```jsx
|
89 | <CodeMirror
|
90 | [...]
|
91 | cursor={{
|
92 | line: 5,
|
93 | ch: 10
|
94 | }}
|
95 | onCursor={(editor, data) => {}}
|
96 | />
|
97 | ```
|
98 | - `scroll` - *[scrollTo](https://codemirror.net/doc/manual.html#scrollTo)*
|
99 | > will programmatically scroll to the specified coordinate
|
100 | ```jsx
|
101 | <CodeMirror
|
102 | [...]
|
103 | scroll={{
|
104 | x: 50,
|
105 | y: 50
|
106 | }}
|
107 | onScroll={(editor, data) => {}}
|
108 | />
|
109 | ```
|
110 | - `selection={{ranges: array<{anchor, head}>, focus?: boolean}` - *[setSelections](https://codemirror.net/doc/manual.html#setSelections)*
|
111 | > will programmatically select the ranges specified
|
112 | ```jsx
|
113 | <CodeMirror
|
114 | [...]
|
115 | selection={{
|
116 | ranges: [{
|
117 | anchor: {ch: 8, line: 5},
|
118 | head: {ch: 37, line: 5}
|
119 | }],
|
120 | focus: true // defaults false if not specified
|
121 | }}
|
122 | onSelection={(editor, data) => {}}
|
123 | />
|
124 | ```
|
125 |
|
126 | ## events
|
127 |
|
128 | | event | components | description |
|
129 | |------------------------------------------------------------------|----------------------------------|-------------------------------------------------------------------------------------------------------------|
|
130 | | **editorDidAttach(editor)** | `UnControlled` | component is now **responding** to new props |
|
131 | | **editorDidConfigure(editor)** | `Controlled` `UnControlled` | component configuration has been set |
|
132 | | **editorDidDetach(editor)** | `UnControlled` | component is now **ignoring** new props |
|
133 | | **editorDidMount(editor, _[next]_)** | `Controlled` `UnControlled` | * invoking optional `next` will trigger `editorDidConfigure` |
|
134 | | **editorWillUnmount(editor)** | `Controlled` `UnControlled` | invoked before [`componentWillUnmount`](https://reactjs.org/docs/react-component.html#componentwillunmount) |
|
135 | | **onBeforeChange(editor, data, value, _[next]_)** | `Controlled` `UnControlled` | * if used, `next` is returned via `UnControlled` and *must* be invoked to trigger onChange |
|
136 | | **onChange(editor, data, value)** | `Controlled` `UnControlled` | the component value has been changed |
|
137 |
|
138 | ## events cont. [wrapped codemirror events](https://codemirror.net/doc/manual.html#events)
|
139 |
|
140 | - `onBlur(editor, event)` - *[blur](https://codemirror.net/doc/manual.html#event_blur)*
|
141 | - `onContextMenu(editor, event)` - *[contextmenu](https://codemirror.net/doc/manual.html#event_dom)*
|
142 | - `onCopy(editor)` - *[copy](https://codemirror.net/doc/manual.html#event_dom)*
|
143 | - `onCursor(editor, data)`- *[cursorActivity](https://codemirror.net/doc/manual.html#event_doc_cursorActivity)*
|
144 | - `onCursorActivity(editor)` - *[cursorActivity](https://codemirror.net/doc/manual.html#event_cursorActivity)*
|
145 | - `onCut(editor)` - *[cut](https://codemirror.net/doc/manual.html#event_dom)*
|
146 | - `onDblClick(editor, event)` - *[dblclick](https://codemirror.net/doc/manual.html#event_dom)*
|
147 | - `onDragEnter(editor, event)` - *[dragenter](https://codemirror.net/doc/manual.html#event_dom)*
|
148 | - `onDragOver(editor, event)` - *[dragover](https://codemirror.net/doc/manual.html#event_dom)*
|
149 | - `onDragLeave(editor, event)` - *[dragleave](https://codemirror.net/doc/manual.html#event_dom)*
|
150 | - `onDragStart(editor, event)` - *[dragstart](https://codemirror.net/doc/manual.html#event_dom)*
|
151 | - `onDrop(editor, event)` - *[drop](https://codemirror.net/doc/manual.html#event_dom)*
|
152 | - `onFocus(editor, event)` - *[focus](https://codemirror.net/doc/manual.html#event_focus)*
|
153 | - `onGutterClick(editor, lineNumber, gutter, event)` - *[gutterClick](https://codemirror.net/doc/manual.html#event_gutterClick)*
|
154 | - `onInputRead(editor, changeObj)` - *[gutterClick](https://codemirror.net/doc/manual.html#events)*
|
155 | - `onKeyDown(editor, event)` - *[keydown](https://codemirror.net/doc/manual.html#event_dom)*
|
156 | - `onKeyHandled(editor, key, event)` - *[keyhandled](https://codemirror.net/doc/manual.html#events)*
|
157 | - `onKeyPress(editor, event)` - *[keypress](https://codemirror.net/doc/manual.html#event_dom)*
|
158 | - `onKeyUp(editor, event)` - *[keyup](https://codemirror.net/doc/manual.html#event_dom)*
|
159 | - `onMouseDown(editor, event)` - *[mousedown](https://codemirror.net/doc/manual.html#event_dom)*
|
160 | - `onPaste(editor)` - *[paste](https://codemirror.net/doc/manual.html#event_dom)*
|
161 | - `onScroll(editor, data)` - *[scroll](https://codemirror.net/doc/manual.html#event_scroll)*
|
162 | - `onSelection(editor, data)` - *[beforeSelectionChange](https://codemirror.net/doc/manual.html#event_doc_beforeSelectionChange)*
|
163 | - `onTouchStart(editor, event)` - *[touchstart](https://codemirror.net/doc/manual.html#event_dom)*
|
164 | - `onUpdate(editor, event)` - *[update](https://codemirror.net/doc/manual.html#event_update)*
|
165 | - `onViewportChange(editor, from, to)` - *[viewportChange](https://codemirror.net/doc/manual.html#event_viewportChange)*
|
166 |
|
167 | ## FAQ
|
168 |
|
169 | - Is server side rendering supported?
|
170 |
|
171 | Yes. react-codemirror2 will prevent rendering in absence of `navigator`. You can also force the component to not render via a `PREVENT_CODEMIRROR_RENDER` global.
|
172 |
|
173 | - How can I get the instance?
|
174 |
|
175 | The recommended technique to get the instance is to persist the `editor` returned via event callbacks. There is no static method to get it on demand, e.g. `CodeMirror.getInstance()`. Example...
|
176 |
|
177 | ```jsx
|
178 | constructor() {
|
179 | this.instance = null;
|
180 | }
|
181 |
|
182 | render() {
|
183 | <CodeMirror editorDidMount={editor => { this.instance = editor }}/>
|
184 | }
|
185 | ```
|
186 |
|
187 | - How can I have a resizable editor?
|
188 |
|
189 | Check out [bokuweb/re-resizable](https://github.com/bokuweb/re-resizable). Wrapping your component with `<Resizable/>'s` works well
|
190 |
|
191 | ## Contributing
|
192 |
|
193 | Pull Requests are welcome. Be mindful of the available scripts below to help submitting a well-received contribution.
|
194 |
|
195 | - `npm run start` to run the app on `localhost:8000`
|
196 | - `npm run test` to ensure tests continue to pass
|
197 | - `npm run build` to generate the demo bundle
|
198 |
|
199 | note that it's necessary to bump the [package.json](https://github.com/scniro/react-codemirror2/blob/master/package.json#L3) version prior to final `npm run build` so we can grab the proposed new version as seen in the demo header. Also note, the core changes are to be made in `src/index.tsx` as `./index.js` and `./index.d.ts` are _generated_
|
200 |
|
201 | [MIT](./LICENSE) © 2020 [scniro](https://github.com/scniro)
|