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 (
- { value ? - { value } - : null} -
); -} - -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();