The Static CMS exposes a `window.CMS` a global object that you can use to register custom widgets, previews, and editor plugins. The same object is also the default export if you import Static CMS as an npm module. The available widget extension methods are:
* **registerEditorComponent:** adds a block component to the Markdown editor.
### Writing React Components inline
The `registerWidget` requires you to provide a React component. If you have a build process in place for your project, it is possible to integrate with this build process.
However, although possible, it may be cumbersome or even impractical to add a React build phase. For this reason, Static CMS exposes two constructs globally to allow you to create components inline: `createClass` and `h` (alias for React.createElement).
| `name` | `string` | Widget name, allows this widget to be used via the field `widget` property in config |
| `control` | `React.Component` or `string` | <ul><li>React component that renders the control, receives the following props: <ul><li>**value:** Current field value</li><li>**field:** Immutable map of current field configuration</li><li>**forID:** Unique identifier for the field</li><li>**classNameWrapper:** class name to apply CMS styling to the field</li><li>**onChange:** Callback function to update the field value</li></ul></li><li>Name of a registered widget whose control should be used (includes built in widgets).</li></ul> |
| [`preview`] | `React.Component`, optional | Renders the widget preview, receives the following props: <ul><li>**value:** Current preview value</li><li>**field:** Immutable map of current field configuration</li><li>**getAsset:** Function for retrieving an asset url for image/file fields</li><li>**entry:** Immutable Record of all entry data</li></ul> |
Register a block level component for the Markdown editor:
```js
CMS.registerEditorComponent(definition)
```
**Params**
* **definition:** The component definition; must specify: id, label, fields, patterns, fromBlock, toBlock, toPreview
> Additional properties are optional and will be passed to the underlying widget control (object widget by default). For example, adding a `collapsed: true` property will collapse the widget by default.
All widget fields, including those for built-in widgets, [include basic validation](/docs/widgets/#common-widget-options) capability using the `required` and `pattern` options.
With custom widgets, the widget control can also optionally implement an `isValid` method to perform custom validations, in addition to presence and pattern. The `isValid` method will be automatically called, and it can return either a boolean value, an object with an error message or a promise. Examples:
**Boolean**
No errors:
```javascript
isValid = () => {
// Do internal validation
return true;
};
```
Existing error:
```javascript
isValid = () => {
// Do internal validation
return false;
};
```
**Object with `error` (useful for returning custom error messages)**
You can also return a promise from `isValid`. While the promise is pending, the widget will be marked as "in error". When the promise resolves, the error is automatically cleared.
```javascript
isValid = () => {
return this.existingPromise;
};
```
**Note:** Do not create a promise inside `isValid` - `isValid` is called right before trying to persist. This means that even if a previous promise was already resolved, when the user hits 'save', `isValid` will be called again. If it returns a new promise, it will be immediately marked as "in error" until the new promise resolves.
Widgets are inputs for the Static CMS editor interface. It's a React component that receives user input and outputs a serialized value. Those are the only rules - the component can be extremely simple, like text input, or extremely complicated, like a full-blown markdown editor. They can make calls to external services, and generally do anything that JavaScript can do.
3. For setting up a new npm package run this command:
```javascript
npm init
```
4. Answer the questions in the command line questionnaire.
5. In order to build React components, we need to set up a build step. We'll be using Webpack. Please run the following commands to install the required dependencies:
6. The `.babelrc` file is our local configuration for our code in the project. You should create it under the root of the application repo. It will affect all files that Babel processes. So, create a `.babelrc` file under the main project with this content:
```javascript
{
"presets": [
"react",
"env",
],
"plugins": [
"transform-export-extensions",
"transform-class-properties",
"transform-object-rest-spread",
],
}
```
7. Create a `src` directory with the files `Control.js`, `Preview.js` and `index.js`
`src/Control.js`
```javascript
import PropTypes from 'prop-types';
import React from 'react';
export default class Control extends React.Component {
static propTypes = {
onChange: PropTypes.func.isRequired,
forID: PropTypes.string,
value: PropTypes.node,
classNameWrapper: PropTypes.string.isRequired,
}
static defaultProps = {
value: '',
}
render() {
const {
forID,
value,
onChange,
classNameWrapper,
} = this.props;
return (
<input
type="text"
id={forID}
className={classNameWrapper}
value={value || ''}
onChange={e => onChange(e.target.value)}
/>
);
}
}
```
`src/Preview.js`
```javascript
import PropTypes from 'prop-types';
import React from 'react';
export default function Preview({ value }) {
return <div>{ value }</div>;
}
Preview.propTypes = {
value: PropTypes.node,
};
```
`src/index.js`
```javascript
import Control from './Control'
import Preview from './Preview'
if (typeof window !== 'undefined') {
window.Control = Control
window.Preview = Preview
}
export { Control, Preview }
```
8. Now you need to set up the locale example site.
Under the main project, create a `dev` directory with the files `bootstrap.js` and `index.js`