diff --git a/packages/netlify-cms-core/scripts/load-extensions.js b/packages/netlify-cms-core/scripts/load-extensions.js
index f711c78a..ee3d968e 100644
--- a/packages/netlify-cms-core/scripts/load-extensions.js
+++ b/packages/netlify-cms-core/scripts/load-extensions.js
@@ -8,13 +8,13 @@ import { DateControl, DatePreview } from 'netlify-cms-widget-date';
import { DateTimeControl, DateTimePreview } from 'netlify-cms-widget-datetime';
import { FileControl, FilePreview } from 'netlify-cms-widget-file';
import { ImageControl, ImagePreview } from 'netlify-cms-widget-image';
+import { ListControl, ListPreview } from 'netlify-cms-widget-list';
+import { ObjectControl, ObjectPreview } from 'netlify-cms-widget-object';
import { StringControl, StringPreview } from 'netlify-cms-widget-string';
// import { NumberControl, NumberPreview } from 'netlify-cms-widget-number';
// import { TextControl, TextPreview } from 'netlify-cms-widget-text';
// import { SelectControl, SelectPreview } from 'netlify-cms-widget-select';
// import { MarkdownControl, MarkdownPreview } from 'netlify-cms-widget-markdown';
-// import { ListControl, ListPreview } from 'netlify-cms-widget-list';
-// import { ObjectControl, ObjectPreview } from 'netlify-cms-widget-object';
// import { RelationControl, RelationPreview } from 'netlify-cms-widget-relation';
import image from 'netlify-cms-editor-component-image';
@@ -27,12 +27,12 @@ registerWidget('date', DateControl, DatePreview);
registerWidget('datetime', DateTimeControl, DateTimePreview);
registerWidget('file', FileControl, FilePreview);
registerWidget('image', ImageControl, ImagePreview);
+registerWidget('list', ListControl, ListPreview);
+registerWidget('object', ObjectControl, ObjectPreview);
registerWidget('string', StringControl, StringPreview);
// registerWidget('text', TextControl, TextPreview);
// registerWidget('number', NumberControl, NumberPreview);
-// registerWidget('list', ListControl, ListPreview);
// registerWidget('markdown', MarkdownControl, MarkdownPreview);
// registerWidget('select', SelectControl, SelectPreview);
-// registerWidget('object', ObjectControl, ObjectPreview);
// registerWidget('relation', RelationControl, RelationPreview);
registerEditorComponent(image);
diff --git a/packages/netlify-cms-core/src/components/Editor/EditorControlPane/EditorControl.js b/packages/netlify-cms-core/src/components/Editor/EditorControlPane/EditorControl.js
index 79273243..ada1791a 100644
--- a/packages/netlify-cms-core/src/components/Editor/EditorControlPane/EditorControl.js
+++ b/packages/netlify-cms-core/src/components/Editor/EditorControlPane/EditorControl.js
@@ -172,6 +172,7 @@ export default class EditorControl extends React.Component {
hasActiveStyle={this.state.styleActive}
setActiveStyle={() => this.setState({ styleActive: true })}
setInactiveStyle={() => this.setState({ styleActive: false })}
+ resolveWidget={resolveWidget}
ref={processControlRef && partial(processControlRef, fieldName)}
editorControl={EditorControl}
/>
diff --git a/packages/netlify-cms-core/src/components/Editor/EditorControlPane/Widget.js b/packages/netlify-cms-core/src/components/Editor/EditorControlPane/Widget.js
index 45964d98..f8ba4445 100644
--- a/packages/netlify-cms-core/src/components/Editor/EditorControlPane/Widget.js
+++ b/packages/netlify-cms-core/src/components/Editor/EditorControlPane/Widget.js
@@ -39,6 +39,7 @@ export default class Widget extends Component {
onAddAsset: PropTypes.func.isRequired,
onRemoveInsertedMedia: PropTypes.func.isRequired,
getAsset: PropTypes.func.isRequired,
+ resolveWidget: PropTypes.func.isRequired,
};
shouldComponentUpdate(nextProps) {
@@ -189,7 +190,8 @@ export default class Widget extends Component {
setInactiveStyle,
hasActiveStyle,
editorControl,
- uniqueFieldId
+ uniqueFieldId,
+ resolveWidget,
} = this.props;
return React.createElement(controlComponent, {
field,
@@ -213,6 +215,7 @@ export default class Widget extends Component {
setInactiveStyle,
hasActiveStyle,
editorControl,
+ resolveWidget,
});
}
}
diff --git a/packages/netlify-cms-core/src/components/EditorWidgets/File/FileControl.css b/packages/netlify-cms-core/src/components/EditorWidgets/File/FileControl.css
deleted file mode 100644
index bd521747..00000000
--- a/packages/netlify-cms-core/src/components/EditorWidgets/File/FileControl.css
+++ /dev/null
@@ -1,7 +0,0 @@
-.nc-fileControl-input {
- display: none !important;
-}
-
-.nc-fileControl-imageUpload {
- cursor: pointer;
-}
diff --git a/packages/netlify-cms-core/src/components/EditorWidgets/File/FileControl.js b/packages/netlify-cms-core/src/components/EditorWidgets/File/FileControl.js
deleted file mode 100644
index db2fdeb0..00000000
--- a/packages/netlify-cms-core/src/components/EditorWidgets/File/FileControl.js
+++ /dev/null
@@ -1,5 +0,0 @@
-import withMediaControl from 'EditorWidgets/withMedia/withMediaControl';
-
-const FileControl = withMediaControl();
-
-export default FileControl;
diff --git a/packages/netlify-cms-core/src/components/EditorWidgets/File/FilePreview.js b/packages/netlify-cms-core/src/components/EditorWidgets/File/FilePreview.js
deleted file mode 100644
index 716bba42..00000000
--- a/packages/netlify-cms-core/src/components/EditorWidgets/File/FilePreview.js
+++ /dev/null
@@ -1,15 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-
-export default function FilePreview({ value, getAsset }) {
- return (
);
-}
-
-FilePreview.propTypes = {
- getAsset: PropTypes.func.isRequired,
- value: PropTypes.node,
-};
diff --git a/packages/netlify-cms-core/src/components/EditorWidgets/Image/Image.css b/packages/netlify-cms-core/src/components/EditorWidgets/Image/Image.css
deleted file mode 100644
index e3351ec8..00000000
--- a/packages/netlify-cms-core/src/components/EditorWidgets/Image/Image.css
+++ /dev/null
@@ -1,4 +0,0 @@
-.nc-imagePreview-image {
- max-width: 100%;
- height: auto;
-}
diff --git a/packages/netlify-cms-core/src/components/EditorWidgets/Image/ImageControl.js b/packages/netlify-cms-core/src/components/EditorWidgets/Image/ImageControl.js
deleted file mode 100644
index 801a59bc..00000000
--- a/packages/netlify-cms-core/src/components/EditorWidgets/Image/ImageControl.js
+++ /dev/null
@@ -1,5 +0,0 @@
-import withMediaControl from 'EditorWidgets/withMedia/withMediaControl';
-
-const ImageControl = withMediaControl(true);
-
-export default ImageControl;
diff --git a/packages/netlify-cms-core/src/components/EditorWidgets/Image/ImagePreview.js b/packages/netlify-cms-core/src/components/EditorWidgets/Image/ImagePreview.js
deleted file mode 100644
index b18c96d5..00000000
--- a/packages/netlify-cms-core/src/components/EditorWidgets/Image/ImagePreview.js
+++ /dev/null
@@ -1,19 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-
-export default function ImagePreview({ value, getAsset }) {
- return (
- { value ?
-
- : null}
-
);
-}
-
-ImagePreview.propTypes = {
- getAsset: PropTypes.func.isRequired,
- value: PropTypes.node,
-};
diff --git a/packages/netlify-cms-core/src/components/EditorWidgets/List/List.css b/packages/netlify-cms-core/src/components/EditorWidgets/List/List.css
deleted file mode 100644
index 6e5cbdd8..00000000
--- a/packages/netlify-cms-core/src/components/EditorWidgets/List/List.css
+++ /dev/null
@@ -1,88 +0,0 @@
-.nc-listControl {
- padding: 0 14px 14px;
-
- &.nc-listControl-collapsed {
- padding-bottom: 0;
- }
-}
-
-.list-item-dragging {
- opacity: 0.5;
-}
-
-.nc-listControl-topBar {
- display: flex;
- justify-content: space-between;
- align-items: center;
- margin: 0 -14px;
- background-color: var(--textFieldBorderColor);
- padding: 13px;
-}
-
-.nc-listControl-addButton {
- display: flex;
- justify-content: center;
- align-items: center;
- padding: 2px 12px;
- font-size: 12px;
- font-weight: bold;
- border-radius: 3px;
-
- & .nc-icon {
- padding-left: 6px;
- }
-}
-
-.nc-listControl-listCollapseToggle {
- display: flex;
- align-items: center;
- font-size: 14px;
- font-weight: 500;
- line-height: 1;
-}
-
-.nc-listControl-listCollapseToggleButton{
- padding: 4px;
- background-color: transparent;
- color: inherit;
-
- &:last-of-type {
- margin-right: 4px;
- }
-}
-
-.nc-listControl-item {
- margin-top: 18px;
-
- &:first-of-type {
- margin-top: 26px;
- }
-}
-
-.nc-listControl-itemTopBar {
- background-color: var(--textFieldBorderColor);
-}
-
-.nc-listControl-objectLabel {
- display: none;
- border-top: 0;
- background-color: var(--textFieldBorderColor);
- padding: 13px;
- border-radius: 0 0 var(--borderRadius) var(--borderRadius);
-}
-
-.nc-listControl-objectControl {
- padding: 6px 14px 14px;
- border-top: 0;
- border-top-left-radius: 0;
- border-top-right-radius: 0;
-}
-
-.nc-listControl-collapsed {
- & .nc-listControl-objectLabel {
- display: block;
- }
- & .nc-listControl-objectControl {
- display: none;
- }
-}
diff --git a/packages/netlify-cms-core/src/components/EditorWidgets/List/ListPreview.js b/packages/netlify-cms-core/src/components/EditorWidgets/List/ListPreview.js
deleted file mode 100644
index 82562100..00000000
--- a/packages/netlify-cms-core/src/components/EditorWidgets/List/ListPreview.js
+++ /dev/null
@@ -1,11 +0,0 @@
-import PropTypes from 'prop-types';
-import React, { Component } from 'react';
-import ObjectPreview from 'EditorWidgets/Object/ObjectPreview';
-
-const ListPreview = ObjectPreview;
-
-ListPreview.propTypes = {
- field: PropTypes.node,
-};
-
-export default ListPreview;
diff --git a/packages/netlify-cms-core/src/components/EditorWidgets/Object/Object.css b/packages/netlify-cms-core/src/components/EditorWidgets/Object/Object.css
deleted file mode 100644
index 919907de..00000000
--- a/packages/netlify-cms-core/src/components/EditorWidgets/Object/Object.css
+++ /dev/null
@@ -1,12 +0,0 @@
-.nc-objectControl-root {
- padding: 0 14px 14px;
-}
-
-.nc-objectControl-topBar {
- align-items: center;
- background-color: #dfdfe3;
- display: flex;
- justify-content: space-between;
- margin: 0 -14px;
- padding: 13px;
-}
diff --git a/packages/netlify-cms-core/src/components/EditorWidgets/Object/ObjectPreview.js b/packages/netlify-cms-core/src/components/EditorWidgets/Object/ObjectPreview.js
deleted file mode 100644
index c849d428..00000000
--- a/packages/netlify-cms-core/src/components/EditorWidgets/Object/ObjectPreview.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import PropTypes from 'prop-types';
-import React, { Component } from 'react';
-
-const ObjectPreview = ({ field }) => (
- {(field && field.get('fields')) || null}
-);
-
-ObjectPreview.propTypes = {
- field: PropTypes.node,
-};
-
-export default ObjectPreview;
diff --git a/packages/netlify-cms-core/src/components/EditorWidgets/index.js b/packages/netlify-cms-core/src/components/EditorWidgets/index.js
index dade5aa3..f19bd2fc 100644
--- a/packages/netlify-cms-core/src/components/EditorWidgets/index.js
+++ b/packages/netlify-cms-core/src/components/EditorWidgets/index.js
@@ -9,18 +9,12 @@ import SelectControl from './Select/SelectControl';
import SelectPreview from './Select/SelectPreview';
import MarkdownControl from './Markdown/MarkdownControl';
import MarkdownPreview from './Markdown/MarkdownPreview';
-import ListControl from './List/ListControl';
-import ListPreview from './List/ListPreview';
-import ObjectControl from './Object/ObjectControl';
-import ObjectPreview from './Object/ObjectPreview';
import RelationControl from './Relation/RelationControl';
import RelationPreview from './Relation/RelationPreview';
registerWidget('text', TextControl, TextPreview);
registerWidget('number', NumberControl, NumberPreview);
-registerWidget('list', ListControl, ListPreview);
registerWidget('markdown', MarkdownControl, MarkdownPreview);
registerWidget('select', SelectControl, SelectPreview);
-registerWidget('object', ObjectControl, ObjectPreview);
registerWidget('relation', RelationControl, RelationPreview);
registerWidget('unknown', UnknownControl, UnknownPreview);
diff --git a/packages/netlify-cms-core/src/components/EditorWidgets/withMedia/withMedia.css b/packages/netlify-cms-core/src/components/EditorWidgets/withMedia/withMedia.css
deleted file mode 100644
index 9fbb68d9..00000000
--- a/packages/netlify-cms-core/src/components/EditorWidgets/withMedia/withMedia.css
+++ /dev/null
@@ -1,34 +0,0 @@
-.nc-imageControl-content {
- display: flex;
-}
-
-.nc-imageControl-imageWrapper {
- width: 155px;
- height: 100px;
- margin-right: 20px;
-
- & img {
- width: 100%;
- height: 100%;
- object-fit: cover;
- border-radius: var(--borderRadius);
- }
-}
-
-.nc-imageControl-filename {
- display: block;
- font-size: 16px;
- margin-bottom: 20px;
-}
-
-.nc-imageControl-chooseButton,
-.nc-imageControl-changeButton {
- @apply(--textBadge);
- display: block;
-}
-
-.nc-imageControl-removeButton {
- @apply(--textBadgeDanger);
- display: block;
- margin-top: 12px;
-}
diff --git a/packages/netlify-cms-core/src/components/EditorWidgets/withMedia/withMediaControl.js b/packages/netlify-cms-core/src/components/EditorWidgets/withMedia/withMediaControl.js
deleted file mode 100644
index 7cc2c585..00000000
--- a/packages/netlify-cms-core/src/components/EditorWidgets/withMedia/withMediaControl.js
+++ /dev/null
@@ -1,120 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import ImmutablePropTypes from "react-immutable-proptypes";
-import uuid from 'uuid/v4';
-import { truncateMiddle } from 'Lib/textHelper';
-
-const MAX_DISPLAY_LENGTH = 50;
-
-export default function withMediaControl(forImage) {
- return class extends React.Component {
- static propTypes = {
- field: PropTypes.object.isRequired,
- getAsset: PropTypes.func.isRequired,
- mediaPaths: ImmutablePropTypes.map.isRequired,
- onAddAsset: PropTypes.func.isRequired,
- onChange: PropTypes.func.isRequired,
- onRemoveInsertedMedia: PropTypes.func.isRequired,
- onOpenMediaLibrary: PropTypes.func.isRequired,
- classNameWrapper: PropTypes.string.isRequired,
- value: PropTypes.node,
- };
-
- static defaultProps = {
- value: '',
- };
-
- constructor(props) {
- super(props);
- this.controlID = uuid();
- }
-
- shouldComponentUpdate(nextProps) {
- /**
- * Always update if the value changes.
- */
- if (this.props.value !== nextProps.value) {
- return true;
- }
-
- /**
- * If there is a media path for this control in the state object, and that
- * path is different than the value in `nextProps`, update.
- */
- const mediaPath = nextProps.mediaPaths.get(this.controlID);
- if (mediaPath && (nextProps.value !== mediaPath)) {
- return true;
- }
-
- return false;
- }
-
- componentWillReceiveProps(nextProps) {
- const { mediaPaths, value, onRemoveInsertedMedia, onChange } = nextProps;
- const mediaPath = mediaPaths.get(this.controlID);
- if (mediaPath && mediaPath !== value) {
- onChange(mediaPath);
- } else if (mediaPath && mediaPath === value) {
- onRemoveInsertedMedia(this.controlID);
- }
- }
-
- handleChange = e => {
- const { field, onOpenMediaLibrary} = this.props;
- e.preventDefault();
- return onOpenMediaLibrary({
- controlID: this.controlID,
- forImage,
- privateUpload: field.get('private'),
- });
- };
-
- handleRemove = e => {
- e.preventDefault();
- return this.props.onChange('');
- };
-
- renderFileName = () => {
- const { value, classNameWrapper } = this.props;
- return value ? truncateMiddle(value, MAX_DISPLAY_LENGTH) : null;
- };
-
- render() {
- const { value, getAsset, onRemoveAsset, classNameWrapper } = this.props;
- const fileName = this.renderFileName();
- const subject = forImage ? 'image' : 'file';
- const article = forImage ? 'an' : 'a';
-
- return (
-
-
- {
- fileName
- ?
- {
- forImage
- ?
-
-
- : null
- }
-
- {fileName}
-
-
-
-
- :
- }
-
-
- );
- }
- };
-};
diff --git a/packages/netlify-cms-ui-default/src/ListItemTopBar.js b/packages/netlify-cms-ui-default/src/ListItemTopBar.js
index 006d9770..19ad8593 100644
--- a/packages/netlify-cms-ui-default/src/ListItemTopBar.js
+++ b/packages/netlify-cms-ui-default/src/ListItemTopBar.js
@@ -1,9 +1,18 @@
import React from 'react';
import styled from 'react-emotion';
import Icon from './Icon';
-import { colors, lengths } from './styles';
+import { colors, lengths, buttons } from './styles';
+
+const TopBar = styled.div`
+ display: flex;
+ justify-content: space-between;
+ height: 26px;
+ border-radius: ${lengths.borderRadius} ${lengths.borderRadius} 0 0;
+ position: relative;
+`
const TopBarButton = styled.button`
+ ${buttons.button};
color: ${colors.controlLabel};
background: transparent;
font-size: 16px;
@@ -24,8 +33,8 @@ const DragIcon = styled(TopBarButtonSpan)`
cursor: move;
`
-const ListItemTopBar = ({ collapsed, onCollapseToggle, onRemove, dragHandleHOC }) => (
-
+const ListItemTopBar = ({ className, collapsed, onCollapseToggle, onRemove, dragHandleHOC }) => (
+
{
onCollapseToggle
?
@@ -47,7 +56,7 @@ const ListItemTopBar = ({ collapsed, onCollapseToggle, onRemove, dragHandleHOC }
: null
}
-
+
);
const StyledListItemTopBar = styled(ListItemTopBar)`
diff --git a/packages/netlify-cms-ui-default/src/ObjectWidgetTopBar.js b/packages/netlify-cms-ui-default/src/ObjectWidgetTopBar.js
new file mode 100644
index 00000000..b26ec1cb
--- /dev/null
+++ b/packages/netlify-cms-ui-default/src/ObjectWidgetTopBar.js
@@ -0,0 +1,67 @@
+import React from 'react';
+import styled, { css }from 'react-emotion';
+import Icon from './Icon';
+import { colors, buttons } from './styles';
+
+const TopBarContainer = styled.div`
+ align-items: center;
+ background-color: ${colors.textFieldBorder};
+ display: flex;
+ justify-content: space-between;
+ margin: 0 -14px;
+ padding: 13px;
+`
+
+const ExpandButtonContainer = styled.div`
+ ${props => props.hasHeading && css`
+ display: flex;
+ align-items: center;
+ font-size: 14px;
+ font-weight: 500;
+ line-height: 1;
+ `}
+`
+
+const ExpandButton = styled.button`
+ ${buttons.button};
+ padding: 4px;
+ background-color: transparent;
+ color: inherit;
+
+ &:last-of-type {
+ margin-right: 4px;
+ }
+`
+
+const AddButton = styled.button`
+ ${buttons.button};
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ padding: 2px 12px;
+ font-size: 12px;
+ font-weight: bold;
+ border-radius: 3px;
+
+ ${Icon} {
+ margin-left: 6px;
+ }
+`
+
+const ObjectWidgetTopBar = ({ allowAdd, onAdd, onCollapseToggle, collapsed, heading = null, label }) => (
+
+
+
+
+
+ {heading}
+
+ {!allowAdd ? null :
+
+ Add {label}
+
+ }
+
+);
+
+export default ObjectWidgetTopBar;
diff --git a/packages/netlify-cms-ui-default/src/index.js b/packages/netlify-cms-ui-default/src/index.js
index 13b44e15..6293eab4 100644
--- a/packages/netlify-cms-ui-default/src/index.js
+++ b/packages/netlify-cms-ui-default/src/index.js
@@ -5,6 +5,7 @@ export Loader from './Loader';
export Toggle, { ToggleContainer, ToggleBackground, ToggleHandle } from './Toggle';
export AuthenticationPage from './AuthenticationPage';
export WidgetPreviewContainer from './WidgetPreviewContainer';
+export ObjectWidgetTopBar from './ObjectWidgetTopBar';
export {
fonts,
colorsRaw,
diff --git a/packages/netlify-cms-ui-default/src/styles.js b/packages/netlify-cms-ui-default/src/styles.js
index d2548792..563c7086 100644
--- a/packages/netlify-cms-ui-default/src/styles.js
+++ b/packages/netlify-cms-ui-default/src/styles.js
@@ -253,6 +253,9 @@ const components = {
font-size: 14px;
margin-top: 8px;
`,
+ objectWidgetTopBarContainer: css`
+ padding: 0 14px 14px;
+ `,
}
injectGlobal`
diff --git a/packages/netlify-cms-widget-list/package.json b/packages/netlify-cms-widget-list/package.json
new file mode 100644
index 00000000..fdfe3e99
--- /dev/null
+++ b/packages/netlify-cms-widget-list/package.json
@@ -0,0 +1,39 @@
+{
+ "name": "netlify-cms-widget-list",
+ "description": "Widget for editing lists in Netlify CMS.",
+ "version": "2.0.0-alpha.0",
+ "main": "dist/netlify-cms-widget-list.js",
+ "license": "MIT",
+ "keywords": [
+ "netlify",
+ "netlify-cms",
+ "widget",
+ "list",
+ "object"
+ ],
+ "sideEffects": false,
+ "scripts": {
+ "watch": "webpack -w",
+ "build": "webpack"
+ },
+ "dependencies": {
+ "netlify-cms-widget-object": "^2.0.0-alpha.0",
+ "react-sortable-hoc": "^0.6.8"
+ },
+ "devDependencies": {
+ "webpack": "^4.16.1",
+ "webpack-cli": "^3.1.0"
+ },
+ "peerDependencies": {
+ "immutable": "^3.7.6",
+ "lodash": "^4.17.10",
+ "netlify-cms-ui-default": "^2.0.0-alpha.0",
+ "prop-types": "^15.5.10",
+ "react": "^16.4.1",
+ "react-emotion": "^9.2.6",
+ "react-immutable-proptypes": "^2.1.0"
+ },
+ "localExternals": [
+ "netlify-cms-widget-object"
+ ]
+}
diff --git a/packages/netlify-cms-core/src/components/EditorWidgets/List/ListControl.js b/packages/netlify-cms-widget-list/src/ListControl.js
similarity index 75%
rename from packages/netlify-cms-core/src/components/EditorWidgets/List/ListControl.js
rename to packages/netlify-cms-widget-list/src/ListControl.js
index c863fbc7..62333f96 100644
--- a/packages/netlify-cms-core/src/components/EditorWidgets/List/ListControl.js
+++ b/packages/netlify-cms-widget-list/src/ListControl.js
@@ -1,47 +1,55 @@
-import React, { Component } from 'react';
+import React from 'react';
import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes';
+import styled, { cx, css } from 'react-emotion';
import { List, Map } from 'immutable';
import { partial } from 'lodash';
-import c from 'classnames';
import { SortableContainer, SortableElement, SortableHandle } from 'react-sortable-hoc';
-import { Icon, ListItemTopBar } from 'netlify-cms-ui-default';
-import ObjectControl from 'EditorWidgets/Object/ObjectControl';
-
-function ListItem(props) {
- return {props.children}
;
-}
-ListItem.propTypes = {
- className: PropTypes.string,
- children: PropTypes.node,
-};
-ListItem.displayName = 'list-item';
+import { ObjectControl } from 'netlify-cms-widget-object';
+import {
+ Icon,
+ ListItemTopBar,
+ ObjectWidgetTopBar,
+ colors,
+ lengths,
+ components,
+} from 'netlify-cms-ui-default';
function valueToString(value) {
return value ? value.join(',').replace(/,([^\s]|$)/g, ', $1') : '';
}
+const ListItem = styled.div();
+
const SortableListItem = SortableElement(ListItem);
-const TopBar = ({ allowAdd, onAdd, listLabel, onCollapseAllToggle, allItemsCollapsed, itemsCount }) => (
-
-
-
- {itemsCount} {listLabel}
-
+const StyledListItemTopBar = styled(ListItemTopBar)`
+ background-color: ${colors.textFieldBorder};
+`
- {
- allowAdd ?
-
- :
- null
+const NestedObjectLabel = styled.div`
+ display: ${props => props.collapsed ? 'block' : 'none'};
+ border-top: 0;
+ background-color: ${colors.textFieldBorder};
+ padding: 13px;
+ border-radius: 0 0 ${lengths.borderRadius} ${lengths.borderRadius};
+`
+
+const styles = {
+ collapsedObjectControl: css`
+ display: none;
+ `,
+ listControlItem: css`
+ margin-top: 18px;
+
+ &:first-of-type {
+ margin-top: 26px;
}
-
-);
+ `,
+ listControlItemCollapsed: css`
+ padding-bottom: 0;
+ `,
+};
const SortableList = SortableContainer(({ items, renderItem }) => {
return {items.map(renderItem)}
;
@@ -52,7 +60,7 @@ const valueTypes = {
MULTIPLE: 'MULTIPLE',
};
-export default class ListControl extends Component {
+export default class ListControl extends React.Component {
static propTypes = {
onChange: PropTypes.func.isRequired,
onChangeObject: PropTypes.func.isRequired,
@@ -229,33 +237,44 @@ export default class ListControl extends Component {
onAddAsset,
onRemoveInsertedMedia,
classNameWrapper,
+ editorControl,
+ resolveWidget,
} = this.props;
const { itemsCollapsed } = this.state;
const collapsed = itemsCollapsed.get(index);
- const classNames = ['nc-listControl-item', collapsed ? 'nc-listControl-collapsed' : ''];
- return (
-
- {this.objectLabel(item)}
-
- );
+ return (
+
+
+ {this.objectLabel(item)}
+
+
+ );
};
renderListControl() {
@@ -264,16 +283,17 @@ export default class ListControl extends Component {
const items = value || List();
const label = field.get('label');
const labelSingular = field.get('label_singular') || field.get('label');
+ const listLabel = items.size === 1 ? labelSingular.toLowerCase() : label.toLowerCase();
return (
-
-
+ val === true)}
- itemsCount={items.size}
+ heading={`${items.size} ${listLabel}`}
+ label={listLabel}
+ onCollapseToggle={this.handleCollapseAllToggle}
+ collapsed={itemsCollapsed.every(val => val === true)}
/>
(
-
-);
+const styles = {
+ nestedObjectControl: css`
+ padding: 6px 14px 14px;
+ border-top: 0;
+ border-top-left-radius: 0;
+ border-top-right-radius: 0;
+ `,
+};
export default class ObjectControl extends Component {
static propTypes = {
@@ -35,6 +33,7 @@ export default class ObjectControl extends Component {
classNameWrapper: PropTypes.string.isRequired,
forList: PropTypes.bool,
editorControl: PropTypes.func.isRequired,
+ resolveWidget: PropTypes.func.isRequired,
};
static defaultProps = {
@@ -68,6 +67,7 @@ export default class ObjectControl extends Component {
value,
onChangeObject,
editorControl: EditorControl,
+ resolveWidget,
} = this.props;
if (field.get('widget') === 'hidden') {
@@ -105,9 +105,15 @@ export default class ObjectControl extends Component {
if (multiFields) {
return (
-
- { forList ? null :
}
- { collapsed ? null : multiFields.map((f, idx) => this.controlFor(f, idx)) }
+
+ {forList ? null :
+
+ }
+ {collapsed ? null : multiFields.map((f, idx) => this.controlFor(f, idx))}
);
} else if (singleField) {
diff --git a/packages/netlify-cms-widget-object/src/ObjectPreview.js b/packages/netlify-cms-widget-object/src/ObjectPreview.js
new file mode 100644
index 00000000..f5bd2b9a
--- /dev/null
+++ b/packages/netlify-cms-widget-object/src/ObjectPreview.js
@@ -0,0 +1,13 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { WidgetPreviewContainer } from 'netlify-cms-ui-default';
+
+const ObjectPreview = ({ field }) => (
+
{(field && field.get('fields')) || null}
+);
+
+ObjectPreview.propTypes = {
+ field: PropTypes.node,
+};
+
+export default ObjectPreview;
diff --git a/packages/netlify-cms-widget-object/src/index.js b/packages/netlify-cms-widget-object/src/index.js
new file mode 100644
index 00000000..ea1f17ea
--- /dev/null
+++ b/packages/netlify-cms-widget-object/src/index.js
@@ -0,0 +1,2 @@
+export ObjectControl from './ObjectControl';
+export ObjectPreview from './ObjectPreview';
diff --git a/packages/netlify-cms-widget-object/webpack.config.js b/packages/netlify-cms-widget-object/webpack.config.js
new file mode 100644
index 00000000..42edd361
--- /dev/null
+++ b/packages/netlify-cms-widget-object/webpack.config.js
@@ -0,0 +1,3 @@
+const { getConfig } = require('../../scripts/webpack.js');
+
+module.exports = getConfig();