Merge pull request #470 from netlify/relation-preview-improvements
Relation preview improvements
This commit is contained in:
commit
1d08f1a33b
@ -16,11 +16,16 @@ Although possible, it may be cumbersome or even impractical to add a React build
|
||||
Register a custom widget.
|
||||
|
||||
```js
|
||||
CMS.registerWidget(field, control, \[preview\])
|
||||
CMS.registerWidget(name, control, \[preview\])
|
||||
```
|
||||
|
||||
**Params:**
|
||||
|
||||
Param | Type | Description
|
||||
--- | --- | ---
|
||||
`name` | string | Widget name, allows this widget to be used via the field `widget` property in config
|
||||
`control` | React.Component \| string | <ul><li>React component that renders the control, receives the following props: <ul><li>**value:** Current field value</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>**metadata:** Immutable map of any available metadata for the current field</li><li>**getAsset:** Function for retrieving an asset url for image/file fields</li><li>**entry:** Immutable Map of all entry data</li><li>**fieldsMetaData:** Immutable map of metadata from all fields.</li></ul>
|
||||
* **field:** The field type which this widget will be used for.
|
||||
* **control:** A React component that renders the editing interface for this field. Two props will be passed:
|
||||
* **value:** The current value for this field.
|
||||
@ -43,7 +48,17 @@ var CategoriesControl = createClass({
|
||||
}
|
||||
});
|
||||
|
||||
CMS.registerWidget('categories', CategoriesControl);
|
||||
var CategoriesPreview = createClass({
|
||||
render: function() {
|
||||
return h('ul', {},
|
||||
this.props.value.map(function(val, index) {
|
||||
return h('li', {key: index}, val);
|
||||
})
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
CMS.registerWidget('categories', CategoriesControl, CategoriesPreview);
|
||||
</script>
|
||||
```
|
||||
|
||||
|
@ -87,19 +87,7 @@ You point to where the files are stored, and specify the fields that define them
|
||||
|
||||
### Widgets
|
||||
|
||||
Widgets define the data type and interface for entry fields. Netlify CMS comes with several built-in widgets, including:
|
||||
|
||||
Widget | UI | Data Type
|
||||
--- | --- | ---
|
||||
`string` | text input | string
|
||||
`text` | text area input | plain text, multiline input
|
||||
`number` | text input with `+` and `-` buttons | number
|
||||
`markdown` | rich text editor with raw option | markdown-formatted string
|
||||
`datetime` | date picker widget | ISO date string
|
||||
`image` | file picker widget with drag-and-drop | file path saved as string, image uploaded to media folder
|
||||
`hidden` | No UI | Hidden element, typically only useful with a `default` attribute
|
||||
|
||||
We’re always adding new widgets, and you can also create your own.
|
||||
Widgets define the data type and interface for entry fields. Netlify CMS comes with several built-in [widgets](/docs/widgets).
|
||||
|
||||
## Customization
|
||||
|
||||
|
@ -4,19 +4,60 @@
|
||||
|
||||
Widgets define the data type and interface for entry fields. Netlify CMS comes with several built-in widgets, including:
|
||||
|
||||
| Name | UI | Data Type |
|
||||
| -------- | --------------------------------- | --------------------------------------------------|
|
||||
| `string` | text input | string |
|
||||
| `boolean` | toggle switch | boolean |
|
||||
| `text` | textarea input | string (multiline) |
|
||||
| `number` | number input | number |
|
||||
| `markdown` | rich text editor | string (markdown) |
|
||||
| `datetime` | date picker | string (ISO date) |
|
||||
| `select` | select input (dropdown) | string |
|
||||
| `image` | file picker w/ drag and drop | image file |
|
||||
| `file` | file picker w/ drag and drop | file |
|
||||
| `hidden` | none | string |
|
||||
| `object` | group of other widgets | Immutable Map containing field values |
|
||||
| `list` | repeatable group of other widgets | Immutable List of objects containing field values |
|
||||
| Name | UI | Data Type |
|
||||
| -------- | ---------------------------------- | ---------------------------------------------------|
|
||||
| `string` | text input | string |
|
||||
| `boolean` | toggle switch | boolean |
|
||||
| `text` | textarea input | string (multiline) |
|
||||
| `number` | number input | number |
|
||||
| `markdown` | rich text editor | string (markdown) |
|
||||
| `datetime` | date picker | string (ISO date) |
|
||||
| `select` | select input (dropdown) | string |
|
||||
| `image` | file picker w/ drag and drop | image file |
|
||||
| `file` | file picker w/ drag and drop | file |
|
||||
| `hidden` | none | string |
|
||||
| `object` | group of other widgets | Immutable Map containing field values |
|
||||
| `list` | repeatable group of other widgets | Immutable List of objects containing field values |
|
||||
| `relation` | text input w/ suggestions dropdown | value of `valueField` in related entry (see below) |
|
||||
|
||||
We’re always adding new widgets, and you can also [create your own](/docs/extending)!
|
||||
|
||||
### Relation Widget
|
||||
|
||||
The relation widget allows you to reference an existing entry from within the entry you're editing. It provides a search input with a list of entries from the collection you're referencing, and the list automatically updates with matched entries based on what you've typed.
|
||||
|
||||
The following field configuration properties are specific to fields using the relation widget:
|
||||
|
||||
Property | Accepted Values | Description
|
||||
--- | --- | ---
|
||||
`collection` | string | name of the collection being referenced
|
||||
`searchFields` | list | one or more names of fields in the referenced colleciton to search for the typed value
|
||||
`valueField` | string | name a field from the referenced collection whose value will be stored for the relation
|
||||
`name` | text input | string
|
||||
|
||||
Let's say we have a "posts" collection and an "authors" collection, and we want to select an author for each post - our config might look something like this:
|
||||
|
||||
```yaml
|
||||
collections:
|
||||
- name: authors
|
||||
label: Authors
|
||||
folder: "authors"
|
||||
create: true
|
||||
fields:
|
||||
- {name: name, label: Name}
|
||||
- {name: twitterHandle, label: "Twitter Handle"}
|
||||
- {name: bio, label: Bio, widget: text}
|
||||
- name: posts
|
||||
label: Posts
|
||||
folder: "posts"
|
||||
create: true
|
||||
fields:
|
||||
- {name: title, label: Title}
|
||||
- {name: body, label: Body, widget: markdown}
|
||||
- name: author
|
||||
label: Author
|
||||
widget: relation
|
||||
collection: authors
|
||||
searchFields: [name, twitterHandle]
|
||||
valueField: name
|
||||
```
|
||||
|
@ -62,6 +62,12 @@ collections: # A list of collections the CMS should be able to edit
|
||||
folder: "_sink"
|
||||
create: true
|
||||
fields:
|
||||
- label: "Related Post"
|
||||
name: "post"
|
||||
widget: "relationKitchenSinkPost"
|
||||
collection: "posts"
|
||||
searchFields: ["title", "body"]
|
||||
valueField: "title"
|
||||
- {label: "Title", name: "title", widget: "string"}
|
||||
- {label: "Boolean", name: "boolean", widget: "boolean", default: true}
|
||||
- {label: "Text", name: "text", widget: "text"}
|
||||
@ -77,6 +83,12 @@ collections: # A list of collections the CMS should be able to edit
|
||||
name: "object"
|
||||
widget: "object"
|
||||
fields:
|
||||
- label: "Related Post"
|
||||
name: "post"
|
||||
widget: "relationKitchenSinkPost"
|
||||
collection: "posts"
|
||||
searchFields: ["title", "body"]
|
||||
valueField: "title"
|
||||
- {label: "String", name: "string", widget: "string"}
|
||||
- {label: "Boolean", name: "boolean", widget: "boolean", default: false}
|
||||
- {label: "Text", name: "text", widget: "text"}
|
||||
@ -119,6 +131,12 @@ collections: # A list of collections the CMS should be able to edit
|
||||
name: "list"
|
||||
widget: "list"
|
||||
fields:
|
||||
- label: "Related Post"
|
||||
name: "post"
|
||||
widget: "relationKitchenSinkPost"
|
||||
collection: "posts"
|
||||
searchFields: ["title", "body"]
|
||||
valueField: "title"
|
||||
- {label: "String", name: "string", widget: "string"}
|
||||
- {label: "Boolean", name: "boolean", widget: "boolean"}
|
||||
- {label: "Text", name: "text", widget: "text"}
|
||||
|
File diff suppressed because one or more lines are too long
@ -13,7 +13,7 @@ import styles from './PreviewPane.css';
|
||||
export default class PreviewPane extends React.Component {
|
||||
|
||||
getWidget = (field, value, props) => {
|
||||
const { fieldsMetaData, getAsset } = props;
|
||||
const { fieldsMetaData, getAsset, entry } = props;
|
||||
const widget = resolveWidget(field.get('widget'));
|
||||
|
||||
return !widget.preview ? null : React.createElement(widget.preview, {
|
||||
@ -22,6 +22,8 @@ export default class PreviewPane extends React.Component {
|
||||
value: value && Map.isMap(value) ? value.get(field.get('name')) : value,
|
||||
metadata: fieldsMetaData && fieldsMetaData.get(field.get('name')),
|
||||
getAsset,
|
||||
entry,
|
||||
fieldsMetaData,
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -69,7 +69,7 @@ class RelationControl extends Component {
|
||||
const collection = field.get('collection');
|
||||
const searchFields = field.get('searchFields').toJS();
|
||||
this.props.query(this.controlID, collection, searchFields, value);
|
||||
}, 100);
|
||||
}, 500);
|
||||
|
||||
onSuggestionsClearRequested = () => {
|
||||
this.props.clearSearch();
|
||||
|
@ -22,7 +22,10 @@ export default {
|
||||
return _registry.previewStyles;
|
||||
},
|
||||
registerWidget(name, control, preview) {
|
||||
_registry.widgets[name] = { control, preview };
|
||||
// A registered widget control can be reused by a new widget, allowing
|
||||
// multiple copies with different previews.
|
||||
const newControl = typeof control === 'string' ? _registry.widgets[control].control : control;
|
||||
_registry.widgets[name] = { control: newControl, preview };
|
||||
},
|
||||
getWidget(name) {
|
||||
return _registry.widgets[name];
|
||||
|
Loading…
x
Reference in New Issue
Block a user