feat(list): Add heading for list widgets (#5544)
This commit is contained in:
parent
b94d5f6e7f
commit
d60df8786d
@ -4,11 +4,17 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
|
|||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { css, ClassNames } from '@emotion/core';
|
import { css, ClassNames } from '@emotion/core';
|
||||||
import { List, Map, fromJS } from 'immutable';
|
import { List, Map, fromJS } from 'immutable';
|
||||||
import { partial, isEmpty } from 'lodash';
|
import { partial, isEmpty, uniqueId } from 'lodash';
|
||||||
import uuid from 'uuid/v4';
|
import uuid from 'uuid/v4';
|
||||||
import { SortableContainer, SortableElement, SortableHandle } from 'react-sortable-hoc';
|
import { SortableContainer, SortableElement, SortableHandle } from 'react-sortable-hoc';
|
||||||
import NetlifyCmsWidgetObject from 'netlify-cms-widget-object';
|
import NetlifyCmsWidgetObject from 'netlify-cms-widget-object';
|
||||||
import { ListItemTopBar, ObjectWidgetTopBar, colors, lengths } from 'netlify-cms-ui-default';
|
import {
|
||||||
|
ListItemTopBar,
|
||||||
|
ObjectWidgetTopBar,
|
||||||
|
colors,
|
||||||
|
lengths,
|
||||||
|
FieldLabel,
|
||||||
|
} from 'netlify-cms-ui-default';
|
||||||
import { stringTemplate, validations } from 'netlify-cms-lib-widgets';
|
import { stringTemplate, validations } from 'netlify-cms-lib-widgets';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@ -87,6 +93,14 @@ function validateItem(field, item) {
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
function LabelComponent({ field, isActive, hasErrors, uniqueFieldId, isFieldOptional, t }) {
|
||||||
|
const label = `${field.get('label', field.get('name'))}`;
|
||||||
|
return (
|
||||||
|
<FieldLabel isActive={isActive} hasErrors={hasErrors} htmlFor={uniqueFieldId}>
|
||||||
|
{label} {`${isFieldOptional ? ` (${t('editor.editorControl.field.optional')})` : ''}`}
|
||||||
|
</FieldLabel>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export default class ListControl extends React.Component {
|
export default class ListControl extends React.Component {
|
||||||
validations = [];
|
validations = [];
|
||||||
@ -164,6 +178,7 @@ export default class ListControl extends React.Component {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
uniqueFieldId = uniqueId(`${this.props.field.get('name')}-field-`);
|
||||||
/**
|
/**
|
||||||
* Always update so that each nested widget has the option to update. This is
|
* Always update so that each nested widget has the option to update. This is
|
||||||
* required because ControlHOC provides a default `shouldComponentUpdate`
|
* required because ControlHOC provides a default `shouldComponentUpdate`
|
||||||
@ -493,6 +508,7 @@ export default class ListControl extends React.Component {
|
|||||||
resolveWidget,
|
resolveWidget,
|
||||||
parentIds,
|
parentIds,
|
||||||
forID,
|
forID,
|
||||||
|
t,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const { itemsCollapsed, keys } = this.state;
|
const { itemsCollapsed, keys } = this.state;
|
||||||
@ -500,20 +516,29 @@ export default class ListControl extends React.Component {
|
|||||||
const key = keys[index];
|
const key = keys[index];
|
||||||
let field = this.props.field;
|
let field = this.props.field;
|
||||||
const hasError = this.hasError(index);
|
const hasError = this.hasError(index);
|
||||||
|
const isVariableTypesList = this.getValueType() === valueTypes.MIXED;
|
||||||
if (this.getValueType() === valueTypes.MIXED) {
|
if (isVariableTypesList) {
|
||||||
field = getTypedFieldForValue(field, item);
|
field = getTypedFieldForValue(field, item);
|
||||||
if (!field) {
|
if (!field) {
|
||||||
return this.renderErroneousTypedItem(index, item);
|
return this.renderErroneousTypedItem(index, item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SortableListItem
|
<SortableListItem
|
||||||
css={[styles.listControlItem, collapsed && styles.listControlItemCollapsed]}
|
css={[styles.listControlItem, collapsed && styles.listControlItemCollapsed]}
|
||||||
index={index}
|
index={index}
|
||||||
key={key}
|
key={key}
|
||||||
>
|
>
|
||||||
|
{isVariableTypesList && (
|
||||||
|
<LabelComponent
|
||||||
|
field={field}
|
||||||
|
isActive={false}
|
||||||
|
hasErrors={hasError}
|
||||||
|
uniqueFieldId={this.uniqueFieldId}
|
||||||
|
isFieldOptional={field.get('required') === false}
|
||||||
|
t={t}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<StyledListItemTopBar
|
<StyledListItemTopBar
|
||||||
collapsed={collapsed}
|
collapsed={collapsed}
|
||||||
onCollapseToggle={partial(this.handleItemCollapseToggle, index)}
|
onCollapseToggle={partial(this.handleItemCollapseToggle, index)}
|
||||||
|
@ -299,14 +299,14 @@ describe('ListControl', () => {
|
|||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
const { getByText } = render(
|
const { getAllByText } = render(
|
||||||
<ListControl
|
<ListControl
|
||||||
{...props}
|
{...props}
|
||||||
field={field}
|
field={field}
|
||||||
value={fromJS([{ first_name: 'hello', last_name: 'world', type: 'type_1_object' }])}
|
value={fromJS([{ first_name: 'hello', last_name: 'world', type: 'type_1_object' }])}
|
||||||
/>,
|
/>,
|
||||||
);
|
);
|
||||||
expect(getByText('type_1_object')).toBeInTheDocument();
|
expect(getAllByText('type_1_object')[1]).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should use label when no summary is configured for mixed types', () => {
|
it('should use label when no summary is configured for mixed types', () => {
|
||||||
@ -327,14 +327,14 @@ describe('ListControl', () => {
|
|||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
const { getByText } = render(
|
const { getAllByText } = render(
|
||||||
<ListControl
|
<ListControl
|
||||||
{...props}
|
{...props}
|
||||||
field={field}
|
field={field}
|
||||||
value={fromJS([{ first_name: 'hello', last_name: 'world', type: 'type_1_object' }])}
|
value={fromJS([{ first_name: 'hello', last_name: 'world', type: 'type_1_object' }])}
|
||||||
/>,
|
/>,
|
||||||
);
|
);
|
||||||
expect(getByText('Type 1 Object')).toBeInTheDocument();
|
expect(getAllByText('Type 1 Object')[1]).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should use summary when configured for mixed types', () => {
|
it('should use summary when configured for mixed types', () => {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user